Explorar el Código

refactoring for dictionary handling

Shinsuke Sugaya hace 9 años
padre
commit
e3430336e5
Se han modificado 46 ficheros con 541 adiciones y 644 borrados
  1. 4 4
      pom.xml
  2. 1 1
      src/main/java/org/codelibs/fess/app/pager/KuromojiPager.java
  3. 25 29
      src/main/java/org/codelibs/fess/app/service/KuromojiService.java
  4. 2 6
      src/main/java/org/codelibs/fess/app/service/SynonymService.java
  5. 6 5
      src/main/java/org/codelibs/fess/app/web/admin/dict/AdminDictAction.java
  6. 1 1
      src/main/java/org/codelibs/fess/app/web/admin/dict/ListForm.java
  7. 50 50
      src/main/java/org/codelibs/fess/app/web/admin/dict/kuromoji/AdminDictKuromojiAction.java
  8. 2 2
      src/main/java/org/codelibs/fess/app/web/admin/dict/kuromoji/EditForm.java
  9. 2 2
      src/main/java/org/codelibs/fess/app/web/admin/dict/kuromoji/SearchForm.java
  10. 2 2
      src/main/java/org/codelibs/fess/app/web/admin/dict/kuromoji/UploadForm.java
  11. 23 23
      src/main/java/org/codelibs/fess/app/web/admin/dict/synonym/AdminDictSynonymAction.java
  12. 1 1
      src/main/java/org/codelibs/fess/app/web/admin/dict/synonym/EditForm.java
  13. 1 1
      src/main/java/org/codelibs/fess/app/web/admin/dict/synonym/SearchForm.java
  14. 1 1
      src/main/java/org/codelibs/fess/app/web/admin/dict/synonym/UploadForm.java
  15. 39 0
      src/main/java/org/codelibs/fess/dict/DictionaryCreator.java
  16. 30 10
      src/main/java/org/codelibs/fess/dict/DictionaryFile.java
  17. 0 64
      src/main/java/org/codelibs/fess/dict/DictionaryLocator.java
  18. 80 69
      src/main/java/org/codelibs/fess/dict/DictionaryManager.java
  19. 24 0
      src/main/java/org/codelibs/fess/dict/kuromoji/KuromojiCreator.java
  20. 83 106
      src/main/java/org/codelibs/fess/dict/kuromoji/KuromojiFile.java
  21. 5 5
      src/main/java/org/codelibs/fess/dict/kuromoji/KuromojiItem.java
  22. 24 0
      src/main/java/org/codelibs/fess/dict/synonym/SynonymCreator.java
  23. 50 81
      src/main/java/org/codelibs/fess/dict/synonym/SynonymFile.java
  24. 0 55
      src/main/java/org/codelibs/fess/dict/synonym/SynonymLocator.java
  25. 0 55
      src/main/java/org/codelibs/fess/dict/userdict/UserDictLocator.java
  26. 1 1
      src/main/java/org/codelibs/fess/exec/Crawler.java
  27. 1 1
      src/main/java/org/codelibs/fess/helper/ViewHelper.java
  28. 18 18
      src/main/java/org/codelibs/fess/mylasta/action/FessHtmlPath.java
  29. 8 0
      src/main/java/org/codelibs/fess/util/ComponentUtil.java
  30. 2 2
      src/main/java/org/codelibs/fess/util/KuromojiCSVUtil.java
  31. 33 18
      src/main/java/org/codelibs/fess/util/ResourceUtil.java
  32. 7 16
      src/main/resources/fess_dict.xml
  33. 1 1
      src/main/webapp/WEB-INF/view/admin/dict/error.jsp
  34. 2 2
      src/main/webapp/WEB-INF/view/admin/dict/index.jsp
  35. 1 1
      src/main/webapp/WEB-INF/view/admin/dict/kuromoji/confirm.jsp
  36. 1 1
      src/main/webapp/WEB-INF/view/admin/dict/kuromoji/download.jsp
  37. 1 1
      src/main/webapp/WEB-INF/view/admin/dict/kuromoji/edit.jsp
  38. 1 1
      src/main/webapp/WEB-INF/view/admin/dict/kuromoji/error.jsp
  39. 1 1
      src/main/webapp/WEB-INF/view/admin/dict/kuromoji/index.jsp
  40. 1 1
      src/main/webapp/WEB-INF/view/admin/dict/kuromoji/upload.jsp
  41. 1 1
      src/main/webapp/WEB-INF/view/admin/dict/synonym/confirm.jsp
  42. 1 1
      src/main/webapp/WEB-INF/view/admin/dict/synonym/download.jsp
  43. 1 1
      src/main/webapp/WEB-INF/view/admin/dict/synonym/edit.jsp
  44. 1 1
      src/main/webapp/WEB-INF/view/admin/dict/synonym/error.jsp
  45. 1 1
      src/main/webapp/WEB-INF/view/admin/dict/synonym/index.jsp
  46. 1 1
      src/main/webapp/WEB-INF/view/admin/dict/synonym/upload.jsp

+ 4 - 4
pom.xml

@@ -110,7 +110,7 @@
 		<plugins>
 			<plugin>
 				<artifactId>maven-compiler-plugin</artifactId>
-				<version>3.2</version>
+				<version>3.3</version>
 				<configuration>
 					<source>1.8</source>
 					<target>1.8</target>
@@ -279,7 +279,7 @@
 							<url
 								url="${maven.release.repo.url}/org/codelibs/elasticsearch-analysis-synonym/1.5.0/elasticsearch-analysis-synonym-1.5.0.zip" />
 							<url
-								url="${maven.release.repo.url}/org/codelibs/elasticsearch-configsync/1.7.0/elasticsearch-configsync-1.7.0.zip" />
+								url="${maven.snapshot.repo.url}/org/codelibs/elasticsearch-configsync/1.7.1-SNAPSHOT/elasticsearch-configsync-1.7.1-20151008.061136-2.zip" />
 							<url
 								url="${maven.release.repo.url}/org/codelibs/elasticsearch-langfield/1.7.0/elasticsearch-langfield-1.7.0.zip" />
 						</get>
@@ -290,7 +290,7 @@
 						<unzip dest="${basedir}/plugins/analysis-synonym"
 							src="${basedir}/target/plugins/elasticsearch-analysis-synonym-1.5.0.zip" />
 						<unzip dest="${basedir}/plugins/configsync"
-							src="${basedir}/target/plugins/elasticsearch-configsync-1.7.0.zip" />
+							src="${basedir}/target/plugins/elasticsearch-configsync-1.7.1-20151008.061136-2.zip" />
 						<unzip dest="${basedir}/plugins/langfield"
 							src="${basedir}/target/plugins/elasticsearch-langfield-1.7.0.zip" />
 					</tasks>
@@ -427,7 +427,7 @@
 		<dependency>
 			<groupId>org.codelibs</groupId>
 			<artifactId>corelib</artifactId>
-			<version>0.3.0</version>
+			<version>0.3.1-SNAPSHOT</version>
 		</dependency>
 
 		<!-- fileupload -->

+ 1 - 1
src/main/java/org/codelibs/fess/app/pager/UserDictPager.java → src/main/java/org/codelibs/fess/app/pager/KuromojiPager.java

@@ -21,7 +21,7 @@ import java.util.List;
 
 import org.codelibs.fess.Constants;
 
-public class UserDictPager implements Serializable {
+public class KuromojiPager implements Serializable {
 
     private static final long serialVersionUID = 1L;
 

+ 25 - 29
src/main/java/org/codelibs/fess/app/service/UserDictService.java → src/main/java/org/codelibs/fess/app/service/KuromojiService.java

@@ -24,50 +24,46 @@ import javax.annotation.Resource;
 import org.codelibs.core.beans.util.BeanUtil;
 import org.codelibs.core.lang.StringUtil;
 import org.codelibs.fess.Constants;
-import org.codelibs.fess.app.pager.UserDictPager;
+import org.codelibs.fess.app.pager.KuromojiPager;
 import org.codelibs.fess.dict.DictionaryExpiredException;
-import org.codelibs.fess.dict.DictionaryFile;
 import org.codelibs.fess.dict.DictionaryFile.PagingList;
 import org.codelibs.fess.dict.DictionaryManager;
-import org.codelibs.fess.dict.userdict.UserDictFile;
-import org.codelibs.fess.dict.userdict.UserDictItem;
+import org.codelibs.fess.dict.kuromoji.KuromojiFile;
+import org.codelibs.fess.dict.kuromoji.KuromojiItem;
 
-public class UserDictService {
+public class KuromojiService {
     @Resource
     protected DictionaryManager dictionaryManager;
 
-    public List<UserDictItem> getUserDictList(final String dictId, final UserDictPager userDictPager) {
-        final UserDictFile userDictFile = getUserDictFile(dictId);
+    public List<KuromojiItem> getUserDictList(final String dictId, final KuromojiPager kuromojiPager) {
+        final KuromojiFile kuromojiFile = getUserDictFile(dictId);
 
-        final int pageSize = userDictPager.getPageSize();
-        final PagingList<UserDictItem> userDictList =
-                userDictFile.selectList((userDictPager.getCurrentPageNumber() - 1) * pageSize, pageSize);
+        final int pageSize = kuromojiPager.getPageSize();
+        final PagingList<KuromojiItem> userDictList =
+                kuromojiFile.selectList((kuromojiPager.getCurrentPageNumber() - 1) * pageSize, pageSize);
 
         // update pager
-        BeanUtil.copyBeanToBean(userDictList, userDictPager, option -> option.include(Constants.PAGER_CONVERSION_RULE));
+        BeanUtil.copyBeanToBean(userDictList, kuromojiPager, option -> option.include(Constants.PAGER_CONVERSION_RULE));
         userDictList.setPageRangeSize(5);
-        userDictPager.setPageNumberList(userDictList.createPageNumberList());
+        kuromojiPager.setPageNumberList(userDictList.createPageNumberList());
 
         return userDictList;
 
     }
 
-    public UserDictFile getUserDictFile(final String dictId) {
-        final DictionaryFile<?> dictionaryFile = dictionaryManager.getDictionaryFile(dictId);
-        if (dictionaryFile instanceof UserDictFile) {
-            return (UserDictFile) dictionaryFile;
-        }
-        throw new DictionaryExpiredException();
+    public KuromojiFile getUserDictFile(final String dictId) {
+        return dictionaryManager.getDictionaryFile(dictId).filter(file -> file instanceof KuromojiFile).map(file -> (KuromojiFile) file)
+                .orElseThrow(() -> new DictionaryExpiredException());
     }
 
-    public UserDictItem getUserDict(final String dictId, final Map<String, String> paramMap) {
-        final UserDictFile userDictFile = getUserDictFile(dictId);
+    public KuromojiItem getUserDict(final String dictId, final Map<String, String> paramMap) {
+        final KuromojiFile kuromojiFile = getUserDictFile(dictId);
 
         final String idStr = paramMap.get("id");
         if (StringUtil.isNotBlank(idStr)) {
             try {
                 final long id = Long.parseLong(idStr);
-                return userDictFile.get(id);
+                return kuromojiFile.get(id);
             } catch (final NumberFormatException e) {
                 // ignore
             }
@@ -76,18 +72,18 @@ public class UserDictService {
         return null;
     }
 
-    public void store(final String dictId, final UserDictItem userDictItem) {
-        final UserDictFile userDictFile = getUserDictFile(dictId);
+    public void store(final String dictId, final KuromojiItem kuromojiItem) {
+        final KuromojiFile kuromojiFile = getUserDictFile(dictId);
 
-        if (userDictItem.getId() == 0) {
-            userDictFile.insert(userDictItem);
+        if (kuromojiItem.getId() == 0) {
+            kuromojiFile.insert(kuromojiItem);
         } else {
-            userDictFile.update(userDictItem);
+            kuromojiFile.update(kuromojiItem);
         }
     }
 
-    public void delete(final String dictId, final UserDictItem userDictItem) {
-        final UserDictFile userDictFile = getUserDictFile(dictId);
-        userDictFile.delete(userDictItem);
+    public void delete(final String dictId, final KuromojiItem kuromojiItem) {
+        final KuromojiFile kuromojiFile = getUserDictFile(dictId);
+        kuromojiFile.delete(kuromojiItem);
     }
 }

+ 2 - 6
src/main/java/org/codelibs/fess/app/service/SynonymService.java

@@ -26,7 +26,6 @@ import org.codelibs.core.lang.StringUtil;
 import org.codelibs.fess.Constants;
 import org.codelibs.fess.app.pager.SynonymPager;
 import org.codelibs.fess.dict.DictionaryExpiredException;
-import org.codelibs.fess.dict.DictionaryFile;
 import org.codelibs.fess.dict.DictionaryFile.PagingList;
 import org.codelibs.fess.dict.DictionaryManager;
 import org.codelibs.fess.dict.synonym.SynonymFile;
@@ -52,11 +51,8 @@ public class SynonymService {
     }
 
     public SynonymFile getSynonymFile(final String dictId) {
-        final DictionaryFile<?> dictionaryFile = dictionaryManager.getDictionaryFile(dictId);
-        if (dictionaryFile instanceof SynonymFile) {
-            return (SynonymFile) dictionaryFile;
-        }
-        throw new DictionaryExpiredException();
+        return dictionaryManager.getDictionaryFile(dictId).filter(file -> file instanceof SynonymFile).map(file -> (SynonymFile) file)
+                .orElseThrow(() -> new DictionaryExpiredException());
     }
 
     public SynonymItem getSynonym(final String dictId, final Map<String, String> paramMap) {

+ 6 - 5
src/main/java/org/codelibs/fess/app/web/admin/dict/AdminDictAction.java

@@ -19,6 +19,8 @@ package org.codelibs.fess.app.web.admin.dict;
 import javax.annotation.Resource;
 
 import org.codelibs.fess.app.web.base.FessAdminAction;
+import org.codelibs.fess.dict.DictionaryFile;
+import org.codelibs.fess.dict.DictionaryItem;
 import org.codelibs.fess.dict.DictionaryManager;
 import org.codelibs.fess.helper.SystemHelper;
 import org.lastaflute.web.Execute;
@@ -51,11 +53,10 @@ public class AdminDictAction extends FessAdminAction {
     //                                                                      Search Execute
     //                                                                      ==============
     @Execute
-    public HtmlResponse index(final DictForm form) {
+    public HtmlResponse index(final ListForm form) {
         return asHtml(path_AdminDict_IndexJsp).renderWith(data -> {
-            // TODO
-            // DictionaryFile<? extends DictionaryItem>[] dictFiles dictFiles = dictionaryManager.getDictionaryFiles();
-            // data.register("dictFiles", dictFiles);
-            });
+            DictionaryFile<? extends DictionaryItem>[] dictFiles = dictionaryManager.getDictionaryFiles();
+            data.register("dictFiles", dictFiles);
+        });
     }
 }

+ 1 - 1
src/main/java/org/codelibs/fess/app/web/admin/dict/DictForm.java → src/main/java/org/codelibs/fess/app/web/admin/dict/ListForm.java

@@ -23,7 +23,7 @@ import java.util.Map;
 /**
  * @author Keiichi Watanabe
  */
-public class DictForm implements Serializable {
+public class ListForm implements Serializable {
 
     private static final long serialVersionUID = 1L;
 

+ 50 - 50
src/main/java/org/codelibs/fess/app/web/admin/dict/userdict/AdminDictUserdictAction.java → src/main/java/org/codelibs/fess/app/web/admin/dict/kuromoji/AdminDictKuromojiAction.java

@@ -14,15 +14,15 @@
  * governing permissions and limitations under the License.
  */
 
-package org.codelibs.fess.app.web.admin.dict.userdict;
+package org.codelibs.fess.app.web.admin.dict.kuromoji;
 
 import javax.annotation.Resource;
 
 import org.codelibs.core.misc.DynamicProperties;
 import org.codelibs.fess.Constants;
 import org.codelibs.fess.annotation.Token;
-import org.codelibs.fess.app.pager.UserDictPager;
-import org.codelibs.fess.app.service.UserDictService;
+import org.codelibs.fess.app.pager.KuromojiPager;
+import org.codelibs.fess.app.service.KuromojiService;
 import org.codelibs.fess.app.web.CrudMode;
 import org.codelibs.fess.app.web.admin.suggestelevateword.SuggestElevateWordEditForm;
 import org.codelibs.fess.app.web.base.FessAdminAction;
@@ -36,15 +36,15 @@ import org.lastaflute.web.validation.VaErrorHook;
 /**
  * @author Keiichi Watanabe
  */
-public class AdminDictUserdictAction extends FessAdminAction {
+public class AdminDictKuromojiAction extends FessAdminAction {
 
     // ===================================================================================
     //                                                                           Attribute
     //                                                                           =========
     @Resource
-    private UserDictService userDictService;
+    private KuromojiService kuromojiService;
     @Resource
-    private UserDictPager userDictPager;
+    private KuromojiPager kuromojiPager;
     @Resource
     private SystemHelper systemHelper;
     @Resource
@@ -63,44 +63,44 @@ public class AdminDictUserdictAction extends FessAdminAction {
     //                                                                      Search Execute
     //                                                                      ==============
     @Execute
-    public HtmlResponse index(final UserDictSearchForm form) {
-        return asHtml(path_AdminDictUserdict_IndexJsp).renderWith(data -> {
+    public HtmlResponse index(final SearchForm form) {
+        return asHtml(path_AdminDictKuromoji_IndexJsp).renderWith(data -> {
             searchPaging(data, form);
         });
     }
 
     @Execute
-    public HtmlResponse list(final Integer pageNumber, final UserDictSearchForm form) {
-        userDictPager.setCurrentPageNumber(pageNumber);
-        return asHtml(path_AdminDictUserdict_IndexJsp).renderWith(data -> {
+    public HtmlResponse list(final Integer pageNumber, final SearchForm form) {
+        kuromojiPager.setCurrentPageNumber(pageNumber);
+        return asHtml(path_AdminDictKuromoji_IndexJsp).renderWith(data -> {
             searchPaging(data, form);
         });
     }
 
     @Execute
-    public HtmlResponse search(final UserDictSearchForm form) {
-        copyBeanToBean(form.searchParams, userDictPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
-        return asHtml(path_AdminDictUserdict_IndexJsp).renderWith(data -> {
+    public HtmlResponse search(final SearchForm form) {
+        copyBeanToBean(form.searchParams, kuromojiPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
+        return asHtml(path_AdminDictKuromoji_IndexJsp).renderWith(data -> {
             searchPaging(data, form);
         });
     }
 
     @Execute
-    public HtmlResponse reset(final UserDictSearchForm form) {
-        userDictPager.clear();
-        return asHtml(path_AdminDictUserdict_IndexJsp).renderWith(data -> {
+    public HtmlResponse reset(final SearchForm form) {
+        kuromojiPager.clear();
+        return asHtml(path_AdminDictKuromoji_IndexJsp).renderWith(data -> {
             searchPaging(data, form);
         });
     }
 
     @Execute
-    public HtmlResponse back(final UserDictSearchForm form) {
-        return asHtml(path_AdminDictUserdict_IndexJsp).renderWith(data -> {
+    public HtmlResponse back(final SearchForm form) {
+        return asHtml(path_AdminDictKuromoji_IndexJsp).renderWith(data -> {
             searchPaging(data, form);
         });
     }
 
-    protected void searchPaging(final RenderData data, final UserDictSearchForm form) {
+    protected void searchPaging(final RenderData data, final SearchForm form) {
         // TODO
     }
 
@@ -112,78 +112,78 @@ public class AdminDictUserdictAction extends FessAdminAction {
     //                                            ----------
     @Token(save = true, validate = false)
     @Execute
-    public HtmlResponse createpage(final UserDictEditForm form) {
+    public HtmlResponse createpage(final EditForm form) {
         form.initialize();
         form.crudMode = CrudMode.CREATE;
-        return asHtml(path_AdminDictUserdict_EditJsp);
+        return asHtml(path_AdminDictKuromoji_EditJsp);
     }
 
     @Token(save = true, validate = false)
     @Execute
-    public HtmlResponse editpage(final int crudMode, final String id, final UserDictEditForm form) {
+    public HtmlResponse editpage(final int crudMode, final String id, final EditForm form) {
         form.crudMode = crudMode;
         form.id = id;
         verifyCrudMode(form, CrudMode.EDIT);
         // TODO loadUserDict(form);
-        return asHtml(path_AdminDictUserdict_EditJsp);
+        return asHtml(path_AdminDictKuromoji_EditJsp);
     }
 
     @Token(save = true, validate = false)
     @Execute
-    public HtmlResponse editagain(final UserDictEditForm form) {
-        return asHtml(path_AdminDictUserdict_EditJsp);
+    public HtmlResponse editagain(final EditForm form) {
+        return asHtml(path_AdminDictKuromoji_EditJsp);
     }
 
     @Token(save = true, validate = false)
     @Execute
-    public HtmlResponse editfromconfirm(final UserDictEditForm form) {
+    public HtmlResponse editfromconfirm(final EditForm form) {
         form.crudMode = CrudMode.EDIT;
         // TODO loadUserDict(form);
-        return asHtml(path_AdminDictUserdict_EditJsp);
+        return asHtml(path_AdminDictKuromoji_EditJsp);
     }
 
     @Token(save = true, validate = false)
     @Execute
-    public HtmlResponse deletepage(final int crudMode, final String id, final UserDictEditForm form) {
+    public HtmlResponse deletepage(final int crudMode, final String id, final EditForm form) {
         form.crudMode = crudMode;
         form.id = id;
         verifyCrudMode(form, CrudMode.DELETE);
         // TODO loadUserDict(form);
-        return asHtml(path_AdminDictUserdict_ConfirmJsp);
+        return asHtml(path_AdminDictKuromoji_ConfirmJsp);
     }
 
     @Token(save = true, validate = false)
     @Execute
-    public HtmlResponse deletefromconfirm(final UserDictEditForm form) {
+    public HtmlResponse deletefromconfirm(final EditForm form) {
         form.crudMode = CrudMode.DELETE;
         // TODO loadUserDict(form);
-        return asHtml(path_AdminDictUserdict_ConfirmJsp);
+        return asHtml(path_AdminDictKuromoji_ConfirmJsp);
     }
 
     // -----------------------------------------------------
     //                                               Confirm
     //                                               -------
     @Execute
-    public HtmlResponse confirmpage(final int crudMode, final String id, final UserDictEditForm form) {
+    public HtmlResponse confirmpage(final int crudMode, final String id, final EditForm form) {
         form.crudMode = crudMode;
         form.id = id;
         verifyCrudMode(form, CrudMode.CONFIRM);
         // TODO loadUserDict(form);
-        return asHtml(path_AdminDictUserdict_ConfirmJsp);
+        return asHtml(path_AdminDictKuromoji_ConfirmJsp);
     }
 
     @Token(save = false, validate = true, keep = true)
     @Execute
-    public HtmlResponse confirmfromcreate(final UserDictEditForm form) {
+    public HtmlResponse confirmfromcreate(final EditForm form) {
         validate(form, messages -> {}, toEditHtml());
-        return asHtml(path_AdminDictUserdict_ConfirmJsp);
+        return asHtml(path_AdminDictKuromoji_ConfirmJsp);
     }
 
     @Token(save = false, validate = true, keep = true)
     @Execute
-    public HtmlResponse confirmfromupdate(final UserDictEditForm form) {
+    public HtmlResponse confirmfromupdate(final EditForm form) {
         validate(form, messages -> {}, toEditHtml());
-        return asHtml(path_AdminDictUserdict_ConfirmJsp);
+        return asHtml(path_AdminDictKuromoji_ConfirmJsp);
     }
 
     // -----------------------------------------------------
@@ -191,16 +191,16 @@ public class AdminDictUserdictAction extends FessAdminAction {
     //                                               -------
     @Token(save = false, validate = true)
     @Execute
-    public HtmlResponse downloadpage(final UserDictSearchForm form) {
-        return asHtml(path_AdminDictUserdict_DownloadJsp);
+    public HtmlResponse downloadpage(final SearchForm form) {
+        return asHtml(path_AdminDictKuromoji_DownloadJsp);
     }
 
     @Token(save = false, validate = true)
     @Execute
-    public HtmlResponse download(final UserDictSearchForm form) {
+    public HtmlResponse download(final SearchForm form) {
         // TODO Download
 
-        return asHtml(path_AdminDictUserdict_DownloadJsp);
+        return asHtml(path_AdminDictKuromoji_DownloadJsp);
     }
 
     // -----------------------------------------------------
@@ -208,10 +208,10 @@ public class AdminDictUserdictAction extends FessAdminAction {
     //                                               -------
     @Token(save = false, validate = true)
     @Execute
-    public HtmlResponse uploadpage(final UserDictUploadForm form) {
+    public HtmlResponse uploadpage(final UploadForm form) {
         // TODO Upload
 
-        return asHtml(path_AdminDictUserdict_UploadJsp);
+        return asHtml(path_AdminDictKuromoji_UploadJsp);
     }
 
     // -----------------------------------------------------
@@ -219,27 +219,27 @@ public class AdminDictUserdictAction extends FessAdminAction {
     //                                         -------------
     @Token(save = false, validate = true)
     @Execute
-    public HtmlResponse create(final UserDictEditForm form) {
+    public HtmlResponse create(final EditForm form) {
         // TODO
         return redirect(getClass());
     }
 
     @Token(save = false, validate = true)
     @Execute
-    public HtmlResponse update(final UserDictEditForm form) {
+    public HtmlResponse update(final EditForm form) {
         // TODO
         return redirect(getClass());
     }
 
     @Execute
-    public HtmlResponse delete(final UserDictEditForm form) {
+    public HtmlResponse delete(final EditForm form) {
         // TODO
         return redirect(getClass());
     }
 
     @Token(save = false, validate = true)
     @Execute
-    public HtmlResponse upload(final UserDictUploadForm form) {
+    public HtmlResponse upload(final UploadForm form) {
         // TODO
         return redirect(getClass());
     }
@@ -254,7 +254,7 @@ public class AdminDictUserdictAction extends FessAdminAction {
     // ===================================================================================
     //                                                                        Small Helper
     //                                                                        ============
-    protected void verifyCrudMode(final UserDictEditForm form, final int expectedMode) {
+    protected void verifyCrudMode(final EditForm form, final int expectedMode) {
         if (form.crudMode != expectedMode) {
             throwValidationError(messages -> {
                 messages.addErrorsCrudInvalidMode(GLOBAL, String.valueOf(expectedMode), String.valueOf(form.crudMode));
@@ -264,7 +264,7 @@ public class AdminDictUserdictAction extends FessAdminAction {
 
     protected VaErrorHook toEditHtml() {
         return () -> {
-            return asHtml(path_AdminDictUserdict_EditJsp);
+            return asHtml(path_AdminDictKuromoji_EditJsp);
         };
     }
 }

+ 2 - 2
src/main/java/org/codelibs/fess/app/web/admin/dict/userdict/UserDictEditForm.java → src/main/java/org/codelibs/fess/app/web/admin/dict/kuromoji/EditForm.java

@@ -14,7 +14,7 @@
  * governing permissions and limitations under the License.
  */
 
-package org.codelibs.fess.app.web.admin.dict.userdict;
+package org.codelibs.fess.app.web.admin.dict.kuromoji;
 
 import java.io.Serializable;
 import java.util.HashMap;
@@ -24,7 +24,7 @@ import java.util.Map;
  * @author codelibs
  * @author Keiichi Watanabe
  */
-public class UserDictEditForm implements Serializable {
+public class EditForm implements Serializable {
 
     private static final long serialVersionUID = 1L;
 

+ 2 - 2
src/main/java/org/codelibs/fess/app/web/admin/dict/userdict/UserDictSearchForm.java → src/main/java/org/codelibs/fess/app/web/admin/dict/kuromoji/SearchForm.java

@@ -14,7 +14,7 @@
  * governing permissions and limitations under the License.
  */
 
-package org.codelibs.fess.app.web.admin.dict.userdict;
+package org.codelibs.fess.app.web.admin.dict.kuromoji;
 
 import java.io.Serializable;
 import java.util.HashMap;
@@ -24,7 +24,7 @@ import java.util.Map;
  * @author codelibs
  * @author Keiichi Watanabe
  */
-public class UserDictSearchForm implements Serializable {
+public class SearchForm implements Serializable {
 
     private static final long serialVersionUID = 1L;
 

+ 2 - 2
src/main/java/org/codelibs/fess/app/web/admin/dict/userdict/UserDictUploadForm.java → src/main/java/org/codelibs/fess/app/web/admin/dict/kuromoji/UploadForm.java

@@ -14,7 +14,7 @@
  * governing permissions and limitations under the License.
  */
 
-package org.codelibs.fess.app.web.admin.dict.userdict;
+package org.codelibs.fess.app.web.admin.dict.kuromoji;
 
 import java.io.Serializable;
 
@@ -24,7 +24,7 @@ import org.lastaflute.web.ruts.multipart.MultipartFormFile;
  * @author codelibs
  * @author Keiichi Watanabe
  */
-public class UserDictUploadForm implements Serializable {
+public class UploadForm implements Serializable {
 
     private static final long serialVersionUID = 1L;
 

+ 23 - 23
src/main/java/org/codelibs/fess/app/web/admin/dict/synonym/AdminDictSynonymAction.java

@@ -63,14 +63,14 @@ public class AdminDictSynonymAction extends FessAdminAction {
     //                                                                      Search Execute
     //                                                                      ==============
     @Execute
-    public HtmlResponse index(final SynonymSearchForm form) {
+    public HtmlResponse index(final SearchForm form) {
         return asHtml(path_AdminDictSynonym_IndexJsp).renderWith(data -> {
             searchPaging(data, form);
         });
     }
 
     @Execute
-    public HtmlResponse list(final Integer pageNumber, final SynonymSearchForm form) {
+    public HtmlResponse list(final Integer pageNumber, final SearchForm form) {
         synonymPager.setCurrentPageNumber(pageNumber);
         return asHtml(path_AdminDictSynonym_IndexJsp).renderWith(data -> {
             searchPaging(data, form);
@@ -78,7 +78,7 @@ public class AdminDictSynonymAction extends FessAdminAction {
     }
 
     @Execute
-    public HtmlResponse search(final SynonymSearchForm form) {
+    public HtmlResponse search(final SearchForm form) {
         copyBeanToBean(form.searchParams, synonymPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
         return asHtml(path_AdminDictSynonym_IndexJsp).renderWith(data -> {
             searchPaging(data, form);
@@ -86,7 +86,7 @@ public class AdminDictSynonymAction extends FessAdminAction {
     }
 
     @Execute
-    public HtmlResponse reset(final SynonymSearchForm form) {
+    public HtmlResponse reset(final SearchForm form) {
         synonymPager.clear();
         return asHtml(path_AdminDictSynonym_IndexJsp).renderWith(data -> {
             searchPaging(data, form);
@@ -94,13 +94,13 @@ public class AdminDictSynonymAction extends FessAdminAction {
     }
 
     @Execute
-    public HtmlResponse back(final SynonymSearchForm form) {
+    public HtmlResponse back(final SearchForm form) {
         return asHtml(path_AdminDictSynonym_IndexJsp).renderWith(data -> {
             searchPaging(data, form);
         });
     }
 
-    protected void searchPaging(final RenderData data, final SynonymSearchForm form) {
+    protected void searchPaging(final RenderData data, final SearchForm form) {
         // TODO
     }
 
@@ -112,7 +112,7 @@ public class AdminDictSynonymAction extends FessAdminAction {
     //                                            ----------
     @Token(save = true, validate = false)
     @Execute
-    public HtmlResponse createpage(final SynonymEditForm form) {
+    public HtmlResponse createpage(final EditForm form) {
         form.initialize();
         form.crudMode = CrudMode.CREATE;
         return asHtml(path_AdminDictSynonym_EditJsp);
@@ -120,7 +120,7 @@ public class AdminDictSynonymAction extends FessAdminAction {
 
     @Token(save = true, validate = false)
     @Execute
-    public HtmlResponse editpage(final int crudMode, final String id, final SynonymEditForm form) {
+    public HtmlResponse editpage(final int crudMode, final String id, final EditForm form) {
         form.crudMode = crudMode;
         form.id = id;
         verifyCrudMode(form, CrudMode.EDIT);
@@ -130,13 +130,13 @@ public class AdminDictSynonymAction extends FessAdminAction {
 
     @Token(save = true, validate = false)
     @Execute
-    public HtmlResponse editagain(final SynonymEditForm form) {
+    public HtmlResponse editagain(final EditForm form) {
         return asHtml(path_AdminDictSynonym_EditJsp);
     }
 
     @Token(save = true, validate = false)
     @Execute
-    public HtmlResponse editfromconfirm(final SynonymEditForm form) {
+    public HtmlResponse editfromconfirm(final EditForm form) {
         form.crudMode = CrudMode.EDIT;
         // TODO loadSynonym(form);
         return asHtml(path_AdminDictSynonym_EditJsp);
@@ -144,7 +144,7 @@ public class AdminDictSynonymAction extends FessAdminAction {
 
     @Token(save = true, validate = false)
     @Execute
-    public HtmlResponse deletepage(final int crudMode, final String id, final SynonymEditForm form) {
+    public HtmlResponse deletepage(final int crudMode, final String id, final EditForm form) {
         form.crudMode = crudMode;
         form.id = id;
         verifyCrudMode(form, CrudMode.DELETE);
@@ -154,7 +154,7 @@ public class AdminDictSynonymAction extends FessAdminAction {
 
     @Token(save = true, validate = false)
     @Execute
-    public HtmlResponse deletefromconfirm(final SynonymEditForm form) {
+    public HtmlResponse deletefromconfirm(final EditForm form) {
         form.crudMode = CrudMode.DELETE;
         // TODO loadSynonym(form);
         return asHtml(path_AdminDictSynonym_ConfirmJsp);
@@ -164,7 +164,7 @@ public class AdminDictSynonymAction extends FessAdminAction {
     //                                               Confirm
     //                                               -------
     @Execute
-    public HtmlResponse confirmpage(final int crudMode, final String id, final SynonymEditForm form) {
+    public HtmlResponse confirmpage(final int crudMode, final String id, final EditForm form) {
         form.crudMode = crudMode;
         form.id = id;
         verifyCrudMode(form, CrudMode.CONFIRM);
@@ -174,14 +174,14 @@ public class AdminDictSynonymAction extends FessAdminAction {
 
     @Token(save = false, validate = true, keep = true)
     @Execute
-    public HtmlResponse confirmfromcreate(final SynonymEditForm form) {
+    public HtmlResponse confirmfromcreate(final EditForm form) {
         validate(form, messages -> {}, toEditHtml());
         return asHtml(path_AdminDictSynonym_ConfirmJsp);
     }
 
     @Token(save = false, validate = true, keep = true)
     @Execute
-    public HtmlResponse confirmfromupdate(final SynonymEditForm form) {
+    public HtmlResponse confirmfromupdate(final EditForm form) {
         validate(form, messages -> {}, toEditHtml());
         return asHtml(path_AdminDictSynonym_ConfirmJsp);
     }
@@ -191,13 +191,13 @@ public class AdminDictSynonymAction extends FessAdminAction {
     //                                               -------
     @Token(save = false, validate = true)
     @Execute
-    public HtmlResponse downloadpage(final SynonymSearchForm form) {
+    public HtmlResponse downloadpage(final SearchForm form) {
         return asHtml(path_AdminDictSynonym_DownloadJsp);
     }
 
     @Token(save = false, validate = true)
     @Execute
-    public HtmlResponse download(final SynonymSearchForm form) {
+    public HtmlResponse download(final SearchForm form) {
         // TODO Download
 
         return asHtml(path_AdminDictSynonym_DownloadJsp);
@@ -208,7 +208,7 @@ public class AdminDictSynonymAction extends FessAdminAction {
     //                                               -------
     @Token(save = false, validate = true)
     @Execute
-    public HtmlResponse uploadpage(final SynonymUploadForm form) {
+    public HtmlResponse uploadpage(final UploadForm form) {
         // TODO Upload
 
         return asHtml(path_AdminDictSynonym_UploadJsp);
@@ -219,27 +219,27 @@ public class AdminDictSynonymAction extends FessAdminAction {
     //                                         -------------
     @Token(save = false, validate = true)
     @Execute
-    public HtmlResponse create(final SynonymEditForm form) {
+    public HtmlResponse create(final EditForm form) {
         // TODO
         return redirect(getClass());
     }
 
     @Token(save = false, validate = true)
     @Execute
-    public HtmlResponse update(final SynonymEditForm form) {
+    public HtmlResponse update(final EditForm form) {
         // TODO
         return redirect(getClass());
     }
 
     @Execute
-    public HtmlResponse delete(final SynonymEditForm form) {
+    public HtmlResponse delete(final EditForm form) {
         // TODO
         return redirect(getClass());
     }
 
     @Token(save = false, validate = true)
     @Execute
-    public HtmlResponse upload(final SynonymUploadForm form) {
+    public HtmlResponse upload(final UploadForm form) {
         // TODO
         return redirect(getClass());
     }
@@ -254,7 +254,7 @@ public class AdminDictSynonymAction extends FessAdminAction {
     // ===================================================================================
     //                                                                        Small Helper
     //                                                                        ============
-    protected void verifyCrudMode(final SynonymEditForm form, final int expectedMode) {
+    protected void verifyCrudMode(final EditForm form, final int expectedMode) {
         if (form.crudMode != expectedMode) {
             throwValidationError(messages -> {
                 messages.addErrorsCrudInvalidMode(GLOBAL, String.valueOf(expectedMode), String.valueOf(form.crudMode));

+ 1 - 1
src/main/java/org/codelibs/fess/app/web/admin/dict/synonym/SynonymEditForm.java → src/main/java/org/codelibs/fess/app/web/admin/dict/synonym/EditForm.java

@@ -24,7 +24,7 @@ import java.util.Map;
  * @author codelibs
  * @author Keiichi Watanabe
  */
-public class SynonymEditForm implements Serializable {
+public class EditForm implements Serializable {
 
     private static final long serialVersionUID = 1L;
 

+ 1 - 1
src/main/java/org/codelibs/fess/app/web/admin/dict/synonym/SynonymSearchForm.java → src/main/java/org/codelibs/fess/app/web/admin/dict/synonym/SearchForm.java

@@ -24,7 +24,7 @@ import java.util.Map;
  * @author codelibs
  * @author Keiichi Watanabe
  */
-public class SynonymSearchForm implements Serializable {
+public class SearchForm implements Serializable {
 
     private static final long serialVersionUID = 1L;
 

+ 1 - 1
src/main/java/org/codelibs/fess/app/web/admin/dict/synonym/SynonymUploadForm.java → src/main/java/org/codelibs/fess/app/web/admin/dict/synonym/UploadForm.java

@@ -24,7 +24,7 @@ import org.lastaflute.web.ruts.multipart.MultipartFormFile;
  * @author codelibs
  * @author Keiichi Watanabe
  */
-public class SynonymUploadForm implements Serializable {
+public class UploadForm implements Serializable {
 
     private static final long serialVersionUID = 1L;
 

+ 39 - 0
src/main/java/org/codelibs/fess/dict/DictionaryCreator.java

@@ -0,0 +1,39 @@
+package org.codelibs.fess.dict;
+
+import java.util.Base64;
+import java.util.Date;
+import java.util.regex.Pattern;
+
+import org.codelibs.fess.Constants;
+
+public abstract class DictionaryCreator {
+    protected Pattern pattern;
+
+    protected DictionaryManager dictionaryManager;
+
+    public DictionaryCreator(String pattern) {
+        this.pattern = Pattern.compile(pattern);
+    }
+
+    public DictionaryFile<? extends DictionaryItem> create(String path, Date timestamp) {
+        if (!isTarget(path)) {
+            return null;
+        }
+
+        return newDictionaryFile(encodePath(path), path, timestamp);
+    }
+
+    protected String encodePath(String path) {
+        return Base64.getEncoder().encodeToString(path.getBytes(Constants.CHARSET_UTF_8));
+    }
+
+    protected boolean isTarget(String path) {
+        return pattern.matcher(path).find();
+    }
+
+    protected abstract DictionaryFile<? extends DictionaryItem> newDictionaryFile(String id, String path, Date timestamp);
+
+    public void setDictionaryManager(DictionaryManager dictionaryManager) {
+        this.dictionaryManager = dictionaryManager;
+    }
+}

+ 30 - 10
src/main/java/org/codelibs/fess/dict/DictionaryFile.java

@@ -18,16 +18,44 @@ package org.codelibs.fess.dict;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
 
 public abstract class DictionaryFile<T extends DictionaryItem> {
+    protected DictionaryManager dictionaryManager;
+
     protected String id;
 
-    public abstract String getType();
+    protected String path;
+
+    protected Date timestamp;
+
+    public DictionaryFile(String id, String path, Date timestamp) {
+        this.id = id;
+        this.path = path;
+        this.timestamp = timestamp;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getPath() {
+        return path;
+    }
 
-    public abstract String getName();
+    public Date getTimestamp() {
+        return timestamp;
+    }
+
+    public DictionaryFile<T> manager(DictionaryManager dictionaryManager) {
+        this.dictionaryManager = dictionaryManager;
+        return this;
+    }
+
+    public abstract String getType();
 
     public abstract PagingList<T> selectList(int offset, int size);
 
@@ -39,14 +67,6 @@ public abstract class DictionaryFile<T extends DictionaryItem> {
 
     public abstract void delete(T item);
 
-    public String getId() {
-        return id;
-    }
-
-    public void setId(final String id) {
-        this.id = id;
-    }
-
     public static class PagingList<E> implements List<E> {
         private final List<E> parent;
 

+ 0 - 64
src/main/java/org/codelibs/fess/dict/DictionaryLocator.java

@@ -1,64 +0,0 @@
-/*
- * Copyright 2009-2015 the CodeLibs Project and the Others.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language
- * governing permissions and limitations under the License.
- */
-
-package org.codelibs.fess.dict;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.filefilter.AbstractFileFilter;
-import org.codelibs.fess.util.ResourceUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public abstract class DictionaryLocator {
-    private static final Logger logger = LoggerFactory.getLogger(DictionaryLocator.class);
-
-    protected List<String> searchPathList = new ArrayList<String>();
-
-    public abstract List<DictionaryFile<? extends DictionaryItem>> find();
-
-    protected File[] findFiles(final String path, final String filenamePrefix, final List<String> excludedSet) {
-
-        final File directory = new File(path);
-        if (logger.isDebugEnabled()) {
-            logger.debug("Load files from " + directory.getAbsolutePath());
-        }
-        final Collection<File> files = FileUtils.listFiles(directory, new AbstractFileFilter() {
-            @Override
-            public boolean accept(final File dir, final String name) {
-                return name.startsWith(filenamePrefix);
-            }
-        }, new AbstractFileFilter() {
-            @Override
-            public boolean accept(final File dir, final String name) {
-                return excludedSet == null || !excludedSet.contains(name);
-            }
-        });
-
-        if (logger.isDebugEnabled()) {
-            logger.debug("Dictionary files: " + files);
-        }
-        return files.toArray(new File[files.size()]);
-    }
-
-    public void addSearchPath(final String path) {
-        searchPathList.add(ResourceUtil.resolve(path));
-    }
-}

+ 80 - 69
src/main/java/org/codelibs/fess/dict/DictionaryManager.java

@@ -16,106 +16,117 @@
 
 package org.codelibs.fess.dict;
 
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedHashMap;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
-import java.util.UUID;
 
 import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
 
-import org.codelibs.core.lang.StringUtil;
-import org.lastaflute.di.helper.timer.TimeoutManager;
-import org.lastaflute.di.helper.timer.TimeoutTarget;
-import org.lastaflute.di.helper.timer.TimeoutTask;
+import org.codelibs.core.io.FileUtil;
+import org.codelibs.elasticsearch.runner.net.Curl;
+import org.codelibs.elasticsearch.runner.net.CurlResponse;
+import org.codelibs.fess.Constants;
+import org.dbflute.optional.OptionalEntity;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class DictionaryManager {
     private static final Logger logger = LoggerFactory.getLogger(DictionaryManager.class);
 
-    protected Map<String, DictionaryFile<? extends DictionaryItem>> dicFileMap;
+    protected String esUrl = "http://localhost:9201";
 
-    public long keepAlive = 5 * 60 * 1000; // 5min
-
-    public int watcherTimeout = 60; // 1min
-
-    protected volatile long lifetime = 0;
-
-    protected TimeoutTask watcherTargetTask;
-
-    protected List<DictionaryLocator> locatorList = new ArrayList<DictionaryLocator>();
+    protected List<DictionaryCreator> creatorList = new ArrayList<>();
 
     @PostConstruct
     public void init() {
-        // start
-        final WatcherTarget watcherTarget = new WatcherTarget();
-        watcherTargetTask = TimeoutManager.getInstance().addTimeoutTarget(watcherTarget, watcherTimeout, true);
-    }
-
-    @PreDestroy
-    public void destroy() {
-        if (watcherTargetTask != null && !watcherTargetTask.isStopped()) {
-            watcherTargetTask.stop();
-        }
+        creatorList.forEach(creator -> {
+            creator.setDictionaryManager(this);
+        });
     }
 
     public DictionaryFile<? extends DictionaryItem>[] getDictionaryFiles() {
-        final Map<String, DictionaryFile<? extends DictionaryItem>> fileMap = getDictionaryFileMap();
-
-        final Collection<DictionaryFile<? extends DictionaryItem>> values = fileMap.values();
-        @SuppressWarnings("unchecked")
-        final DictionaryFile<? extends DictionaryItem>[] list = new DictionaryFile[values.size()];
-        return values.toArray(list);
+        try (CurlResponse response = Curl.get(esUrl + "/_configsync/file").param("fields", "path,@timestamp").execute()) {
+            Map<String, Object> contentMap = response.getContentAsMap();
+            @SuppressWarnings("unchecked")
+            List<Map<String, Object>> fileList = (List<Map<String, Object>>) contentMap.get("file");
+            return fileList
+                    .stream()
+                    .map(fileMap -> {
+                        try {
+                            String path = fileMap.get("path").toString();
+                            Date timestamp =
+                                    new SimpleDateFormat(Constants.DATE_FORMAT_ISO_8601_EXTEND_UTC).parse(fileMap.get("@timestamp")
+                                            .toString());
+                            for (final DictionaryCreator creator : creatorList) {
+                                DictionaryFile<? extends DictionaryItem> file = creator.create(path, timestamp);
+                                if (file != null) {
+                                    return file;
+                                }
+                            }
+                        } catch (Exception e) {
+                            logger.warn("Failed to load " + fileMap, e);
+                        }
+                        return null;
+                    }).filter(file -> file != null).toArray(n -> new DictionaryFile<?>[n]);
+        } catch (IOException e) {
+            throw new DictionaryException("Failed to access dictionaries", e);
+        }
     }
 
-    public DictionaryFile<? extends DictionaryItem> getDictionaryFile(final String id) {
-        if (StringUtil.isBlank(id)) {
-            return null;
+    public OptionalEntity<DictionaryFile<? extends DictionaryItem>> getDictionaryFile(final String id) {
+        for (DictionaryFile<? extends DictionaryItem> dictFile : getDictionaryFiles()) {
+            if (dictFile.getId().equals(id)) {
+                return OptionalEntity.of(dictFile);
+            }
         }
-
-        final Map<String, DictionaryFile<? extends DictionaryItem>> fileMap = getDictionaryFileMap();
-        return fileMap.get(id);
+        return OptionalEntity.empty();
     }
 
-    protected Map<String, DictionaryFile<? extends DictionaryItem>> getDictionaryFileMap() {
-        synchronized (this) {
-            if (lifetime > System.currentTimeMillis() && dicFileMap != null) {
-                lifetime = System.currentTimeMillis() + keepAlive;
-                return dicFileMap;
+    public void store(DictionaryFile<? extends DictionaryItem> dictFile, File file) {
+        getDictionaryFile(dictFile.getId()).ifPresent(currentFile -> {
+            if (currentFile.getTimestamp().getTime() > dictFile.getTimestamp().getTime()) {
+                throw new DictionaryException(dictFile.getPath() + " was updated.");
             }
 
-            final Map<String, DictionaryFile<? extends DictionaryItem>> newFileMap = new LinkedHashMap<>();
-            for (final DictionaryLocator locator : locatorList) {
-                for (final DictionaryFile<? extends DictionaryItem> dictFile : locator.find()) {
-                    final String id = UUID.randomUUID().toString();
-                    dictFile.setId(id);
-                    newFileMap.put(id, dictFile);
+            // TODO use stream
+                try (CurlResponse response =
+                        Curl.post(esUrl + "/_configsync/file").param("path", dictFile.getPath()).body(FileUtil.readUTF8(file)).execute()) {
+                    Map<String, Object> contentMap = response.getContentAsMap();
+                    if (!Constants.TRUE.equalsIgnoreCase(contentMap.get("acknowledged").toString())) {
+                        throw new DictionaryException("Failed to update " + dictFile.getPath());
+                    }
+                } catch (IOException e) {
+                    throw new DictionaryException("Failed to update " + dictFile.getPath(), e);
                 }
-            }
-            dicFileMap = newFileMap;
-            lifetime = System.currentTimeMillis() + keepAlive;
-            return dicFileMap;
+
+            }).orElse(() -> {
+            throw new DictionaryException(dictFile.getPath() + " does not exist.");
+        });
+    }
+
+    public InputStream getContentInputStream(DictionaryFile<? extends DictionaryItem> dictFile) {
+        try {
+            return Curl.get(esUrl + "/_configsync/file").param("path", dictFile.getPath()).execute().getContentAsStream();
+        } catch (IOException e) {
+            throw new DictionaryException("Failed to access " + dictFile.getPath(), e);
         }
     }
 
-    public void addLocator(final DictionaryLocator locator) {
-        locatorList.add(locator);
+    public String getEsUrl() {
+        return esUrl;
     }
 
-    protected class WatcherTarget implements TimeoutTarget {
-        @Override
-        public void expired() {
-            synchronized (DictionaryManager.this) {
-                if (lifetime <= System.currentTimeMillis() && dicFileMap != null) {
-                    dicFileMap = null;
-                    if (logger.isDebugEnabled()) {
-                        logger.debug("Clear dictionary cache: " + dicFileMap);
-                    }
-                }
-            }
-        }
+    public void setEsUrl(String esUrl) {
+        this.esUrl = esUrl;
     }
+
+    public void addCreator(DictionaryCreator creator) {
+        creatorList.add(creator);
+    }
+
 }

+ 24 - 0
src/main/java/org/codelibs/fess/dict/kuromoji/KuromojiCreator.java

@@ -0,0 +1,24 @@
+package org.codelibs.fess.dict.kuromoji;
+
+import java.util.Date;
+
+import org.codelibs.fess.dict.DictionaryCreator;
+import org.codelibs.fess.dict.DictionaryFile;
+import org.codelibs.fess.dict.DictionaryItem;
+
+public class KuromojiCreator extends DictionaryCreator {
+
+    public KuromojiCreator() {
+        super("kuromoji.*\\.txt");
+    }
+
+    public KuromojiCreator(String pattern) {
+        super(pattern);
+    }
+
+    @Override
+    protected DictionaryFile<? extends DictionaryItem> newDictionaryFile(String id, String path, Date timestamp) {
+        return new KuromojiFile(id, path, timestamp).manager(dictionaryManager);
+    }
+
+}

+ 83 - 106
src/main/java/org/codelibs/fess/dict/userdict/UserDictFile.java → src/main/java/org/codelibs/fess/dict/kuromoji/KuromojiFile.java

@@ -14,138 +14,104 @@
  * governing permissions and limitations under the License.
  */
 
-package org.codelibs.fess.dict.userdict;
+package org.codelibs.fess.dict.kuromoji;
 
-import java.io.BufferedInputStream;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.Closeable;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
 
-import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
-import org.codelibs.core.io.CopyUtil;
 import org.codelibs.core.lang.StringUtil;
 import org.codelibs.fess.Constants;
 import org.codelibs.fess.dict.DictionaryException;
 import org.codelibs.fess.dict.DictionaryFile;
-import org.codelibs.fess.util.UserDictCSVUtil;
+import org.codelibs.fess.util.KuromojiCSVUtil;
 
-public class UserDictFile extends DictionaryFile<UserDictItem> {
-    private static final String USERDICT = "userDict";
+public class KuromojiFile extends DictionaryFile<KuromojiItem> {
+    private static final String KUROMOJI = "kuromoji";
 
-    private final File file;
+    List<KuromojiItem> kuromojiItemList;
 
-    List<UserDictItem> userDictItemList;
-
-    public UserDictFile(final File file) {
-        this.file = file;
+    public KuromojiFile(String id, String path, Date timestamp) {
+        super(id, path, timestamp);
     }
 
     @Override
     public String getType() {
-        return USERDICT;
+        return KUROMOJI;
     }
 
     @Override
-    public String getName() {
-        return file.getAbsolutePath();
+    public String getPath() {
+        return path;
     }
 
     @Override
-    public UserDictItem get(final long id) {
-        for (final UserDictItem userDictItem : userDictItemList) {
-            if (id == userDictItem.getId()) {
-                return userDictItem;
+    public KuromojiItem get(final long id) {
+        for (final KuromojiItem kuromojiItem : kuromojiItemList) {
+            if (id == kuromojiItem.getId()) {
+                return kuromojiItem;
             }
         }
         return null;
     }
 
     @Override
-    public synchronized PagingList<UserDictItem> selectList(final int offset, final int size) {
-        if (userDictItemList == null) {
+    public synchronized PagingList<KuromojiItem> selectList(final int offset, final int size) {
+        if (kuromojiItemList == null) {
             reload(null);
         }
 
-        if (offset >= userDictItemList.size() || offset < 0) {
-            return new PagingList<UserDictItem>(Collections.<UserDictItem> emptyList(), offset, size, userDictItemList.size());
+        if (offset >= kuromojiItemList.size() || offset < 0) {
+            return new PagingList<KuromojiItem>(Collections.<KuromojiItem> emptyList(), offset, size, kuromojiItemList.size());
         }
 
         int toIndex = offset + size;
-        if (toIndex > userDictItemList.size()) {
-            toIndex = userDictItemList.size();
+        if (toIndex > kuromojiItemList.size()) {
+            toIndex = kuromojiItemList.size();
         }
 
-        return new PagingList<UserDictItem>(userDictItemList.subList(offset, toIndex), offset, size, userDictItemList.size());
+        return new PagingList<KuromojiItem>(kuromojiItemList.subList(offset, toIndex), offset, size, kuromojiItemList.size());
     }
 
     @Override
-    public synchronized void insert(final UserDictItem item) {
-        final UserDictItem userDictItem = item;
-        BufferedWriter bw = null;
-        try {
-            bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true), Constants.UTF_8));
-            bw.newLine();
-            bw.write(userDictItem.toLineString());
-            bw.flush();
-
-            long nextId = 1;
-            if (!userDictItemList.isEmpty()) {
-                final UserDictItem lastItem = userDictItemList.get(userDictItemList.size() - 1);
-                nextId = lastItem.getId() + 1;
-            }
-            userDictItemList.add(new UserDictItem(nextId, userDictItem.getNewToken(), userDictItem.getNewSegmentation(), userDictItem
-                    .getNewReading(), userDictItem.getNewPos()));
-        } catch (final IOException e) {
-            throw new DictionaryException("Failed to write: " + item, e);
-        } finally {
-            IOUtils.closeQuietly(bw);
+    public synchronized void insert(final KuromojiItem item) {
+        try (KuromojiUpdater updater = new KuromojiUpdater(item)) {
+            reload(updater);
         }
     }
 
     @Override
-    public synchronized void update(final UserDictItem item) {
-        UserDictUpdater updater = null;
-        try {
-            updater = new UserDictUpdater(file, item);
+    public synchronized void update(final KuromojiItem item) {
+        try (KuromojiUpdater updater = new KuromojiUpdater(item)) {
             reload(updater);
-        } finally {
-            if (updater != null) {
-                updater.close();
-            }
         }
     }
 
     @Override
-    public synchronized void delete(final UserDictItem item) {
-        final UserDictItem userDictItem = item;
-        userDictItem.setNewToken(StringUtil.EMPTY);
-        UserDictUpdater updater = null;
-        try {
-            updater = new UserDictUpdater(file, userDictItem);
+    public synchronized void delete(final KuromojiItem item) {
+        final KuromojiItem kuromojiItem = item;
+        kuromojiItem.setNewToken(StringUtil.EMPTY);
+        try (KuromojiUpdater updater = new KuromojiUpdater(item)) {
             reload(updater);
-        } finally {
-            if (updater != null) {
-                updater.close();
-            }
         }
     }
 
-    protected void reload(final UserDictUpdater updater) {
-        final List<UserDictItem> itemList = new ArrayList<UserDictItem>();
+    protected void reload(final KuromojiUpdater updater) {
+        final List<KuromojiItem> itemList = new ArrayList<KuromojiItem>();
         BufferedReader reader = null;
         try {
-            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), Constants.UTF_8));
+            reader = new BufferedReader(new InputStreamReader(dictionaryManager.getContentInputStream(this), Constants.UTF_8));
             long id = 0;
             String line = null;
             while ((line = reader.readLine()) != null) {
@@ -160,7 +126,7 @@ public class UserDictFile extends DictionaryFile<UserDictItem> {
                     continue;
                 }
 
-                final String[] values = UserDictCSVUtil.parse(line);
+                final String[] values = KuromojiCSVUtil.parse(line);
                 String token = null;
                 String segmentation = null;
                 String reading = null;
@@ -179,9 +145,9 @@ public class UserDictFile extends DictionaryFile<UserDictItem> {
                 }
 
                 id++;
-                final UserDictItem item = new UserDictItem(id, token, segmentation, reading, pos);
+                final KuromojiItem item = new KuromojiItem(id, token, segmentation, reading, pos);
                 if (updater != null) {
-                    final UserDictItem newItem = updater.write(item);
+                    final KuromojiItem newItem = updater.write(item);
                     if (newItem != null) {
                         itemList.add(newItem);
                     } else {
@@ -192,31 +158,51 @@ public class UserDictFile extends DictionaryFile<UserDictItem> {
                 }
             }
             if (updater != null) {
-                updater.commit();
+                KuromojiItem item = updater.commit();
+                if (item != null) {
+                    itemList.add(item);
+                }
             }
-            userDictItemList = itemList;
+            kuromojiItemList = itemList;
         } catch (final IOException e) {
-            throw new DictionaryException("Failed to parse " + file.getAbsolutePath(), e);
+            throw new DictionaryException("Failed to parse " + path, e);
         } finally {
             IOUtils.closeQuietly(reader);
         }
     }
 
-    protected static class UserDictUpdater {
+    public String getSimpleName() {
+        return new File(path).getName();
+    }
 
-        protected boolean isCommit = false;
+    // TODO
+    //    public InputStream getInputStream() throws IOException {
+    //        return new BufferedInputStream(new FileInputStream(file));
+    //    }
+    //
+    //    public void update(final InputStream in) throws IOException {
+    //        CopyUtil.copy(in, file);
+    //        reload(null);
+    //    }
 
-        protected File oldFile;
+    @Override
+    public String toString() {
+        return "KuromojiFile [path=" + path + ", kuromojiItemList=" + kuromojiItemList + ", id=" + id + "]";
+    }
+
+    protected class KuromojiUpdater implements Closeable {
+
+        protected boolean isCommit = false;
 
         protected File newFile;
 
         protected Writer writer;
 
-        protected UserDictItem item;
+        protected KuromojiItem item;
 
-        protected UserDictUpdater(final File file, final UserDictItem newItem) {
+        protected KuromojiUpdater(final KuromojiItem newItem) {
             try {
-                newFile = File.createTempFile(USERDICT, ".txt");
+                newFile = File.createTempFile(KUROMOJI, ".txt");
                 writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(newFile), Constants.UTF_8));
             } catch (final IOException e) {
                 if (newFile != null) {
@@ -224,11 +210,10 @@ public class UserDictFile extends DictionaryFile<UserDictItem> {
                 }
                 throw new DictionaryException("Failed to write a userDict file.", e);
             }
-            oldFile = file;
             item = newItem;
         }
 
-        public UserDictItem write(final UserDictItem oldItem) {
+        public KuromojiItem write(final KuromojiItem oldItem) {
             try {
                 if (item.getId() == oldItem.getId() && item.isUpdated()) {
                     if (item.equals(oldItem)) {
@@ -237,7 +222,7 @@ public class UserDictFile extends DictionaryFile<UserDictItem> {
                                 // update
                                 writer.write(item.toLineString());
                                 writer.write(Constants.LINE_SEPARATOR);
-                                return new UserDictItem(item.getId(), item.getNewToken(), item.getNewSegmentation(), item.getNewReading(),
+                                return new KuromojiItem(item.getId(), item.getNewToken(), item.getNewSegmentation(), item.getNewReading(),
                                         item.getNewPos());
                             } else {
                                 return null;
@@ -267,10 +252,21 @@ public class UserDictFile extends DictionaryFile<UserDictItem> {
             }
         }
 
-        public void commit() {
+        public KuromojiItem commit() {
             isCommit = true;
+            if (item.isUpdated()) {
+                try {
+                    writer.write(item.toLineString());
+                    writer.write(Constants.LINE_SEPARATOR);
+                    return item;
+                } catch (final IOException e) {
+                    throw new DictionaryException("Failed to write: " + item, e);
+                }
+            }
+            return null;
         }
 
+        @Override
         public void close() {
             try {
                 writer.flush();
@@ -281,11 +277,9 @@ public class UserDictFile extends DictionaryFile<UserDictItem> {
 
             if (isCommit) {
                 try {
-                    FileUtils.copyFile(newFile, oldFile);
+                    dictionaryManager.store(KuromojiFile.this, newFile);
+                } finally {
                     newFile.delete();
-                } catch (final IOException e) {
-                    throw new DictionaryException("Failed to replace " + oldFile.getAbsolutePath() + " with " + newFile.getAbsolutePath(),
-                            e);
                 }
             } else {
                 newFile.delete();
@@ -293,21 +287,4 @@ public class UserDictFile extends DictionaryFile<UserDictItem> {
         }
     }
 
-    public String getSimpleName() {
-        return file.getName();
-    }
-
-    public InputStream getInputStream() throws IOException {
-        return new BufferedInputStream(new FileInputStream(file));
-    }
-
-    public void update(final InputStream in) throws IOException {
-        CopyUtil.copy(in, file);
-        reload(null);
-    }
-
-    @Override
-    public String toString() {
-        return "UserDictFile [file=" + file + ", userDictItemList=" + userDictItemList + ", id=" + id + "]";
-    }
 }

+ 5 - 5
src/main/java/org/codelibs/fess/dict/userdict/UserDictItem.java → src/main/java/org/codelibs/fess/dict/kuromoji/KuromojiItem.java

@@ -14,11 +14,11 @@
  * governing permissions and limitations under the License.
  */
 
-package org.codelibs.fess.dict.userdict;
+package org.codelibs.fess.dict.kuromoji;
 
 import org.codelibs.fess.dict.DictionaryItem;
 
-public class UserDictItem extends DictionaryItem {
+public class KuromojiItem extends DictionaryItem {
     private final String token;
 
     private final String segmentation;
@@ -35,7 +35,7 @@ public class UserDictItem extends DictionaryItem {
 
     private String newPos;
 
-    public UserDictItem(final long id, final String token, final String segmentation, final String reading, final String pos) {
+    public KuromojiItem(final long id, final String token, final String segmentation, final String reading, final String pos) {
         this.id = id;
         this.token = token;
         this.segmentation = segmentation;
@@ -129,7 +129,7 @@ public class UserDictItem extends DictionaryItem {
         if (getClass() != obj.getClass()) {
             return false;
         }
-        final UserDictItem other = (UserDictItem) obj;
+        final KuromojiItem other = (KuromojiItem) obj;
         if (pos == null) {
             if (other.pos != null) {
                 return false;
@@ -163,7 +163,7 @@ public class UserDictItem extends DictionaryItem {
 
     @Override
     public String toString() {
-        return "UserDictItem [token=" + token + ", segmentation=" + segmentation + ", reading=" + reading + ", pos=" + pos + ", newToken="
+        return "KuromojiItem [token=" + token + ", segmentation=" + segmentation + ", reading=" + reading + ", pos=" + pos + ", newToken="
                 + newToken + ", newSegmentation=" + newSegmentation + ", newReading=" + newReading + ", newPos=" + newPos + "]";
     }
 

+ 24 - 0
src/main/java/org/codelibs/fess/dict/synonym/SynonymCreator.java

@@ -0,0 +1,24 @@
+package org.codelibs.fess.dict.synonym;
+
+import java.util.Date;
+
+import org.codelibs.fess.dict.DictionaryCreator;
+import org.codelibs.fess.dict.DictionaryFile;
+import org.codelibs.fess.dict.DictionaryItem;
+
+public class SynonymCreator extends DictionaryCreator {
+
+    public SynonymCreator() {
+        super("synonym.*\\.txt");
+    }
+
+    public SynonymCreator(String pattern) {
+        super(pattern);
+    }
+
+    @Override
+    protected DictionaryFile<? extends DictionaryItem> newDictionaryFile(String id, String path, Date timestamp) {
+        return new SynonymFile(id, path, timestamp).manager(dictionaryManager);
+    }
+
+}

+ 50 - 81
src/main/java/org/codelibs/fess/dict/synonym/SynonymFile.java

@@ -16,24 +16,21 @@
 
 package org.codelibs.fess.dict.synonym;
 
-import java.io.BufferedInputStream;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.Closeable;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
 
-import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
-import org.codelibs.core.io.CopyUtil;
 import org.codelibs.core.lang.StringUtil;
 import org.codelibs.fess.Constants;
 import org.codelibs.fess.dict.DictionaryException;
@@ -42,12 +39,10 @@ import org.codelibs.fess.dict.DictionaryFile;
 public class SynonymFile extends DictionaryFile<SynonymItem> {
     private static final String SYNONYM = "synonym";
 
-    private final File file;
-
     List<SynonymItem> synonymItemList;
 
-    public SynonymFile(final File file) {
-        this.file = file;
+    public SynonymFile(String id, String path, Date timestamp) {
+        super(id, path, timestamp);
     }
 
     @Override
@@ -55,11 +50,6 @@ public class SynonymFile extends DictionaryFile<SynonymItem> {
         return SYNONYM;
     }
 
-    @Override
-    public String getName() {
-        return file.getAbsolutePath();
-    }
-
     @Override
     public SynonymItem get(final long id) {
         for (final SynonymItem synonymItem : synonymItemList) {
@@ -90,37 +80,15 @@ public class SynonymFile extends DictionaryFile<SynonymItem> {
 
     @Override
     public synchronized void insert(final SynonymItem item) {
-        final SynonymItem synonymItem = item;
-        BufferedWriter bw = null;
-        try {
-            bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true), Constants.UTF_8));
-            bw.newLine();
-            bw.write(synonymItem.toLineString());
-            bw.flush();
-
-            long nextId = 1;
-            if (!synonymItemList.isEmpty()) {
-                final SynonymItem lastItem = synonymItemList.get(synonymItemList.size() - 1);
-                nextId = lastItem.getId() + 1;
-            }
-            synonymItemList.add(new SynonymItem(nextId, synonymItem.getNewInputs(), synonymItem.getNewOutputs()));
-        } catch (final IOException e) {
-            throw new DictionaryException("Failed to write: " + item, e);
-        } finally {
-            IOUtils.closeQuietly(bw);
+        try (SynonymUpdater updater = new SynonymUpdater(item)) {
+            reload(updater);
         }
     }
 
     @Override
     public synchronized void update(final SynonymItem item) {
-        SynonymUpdater updater = null;
-        try {
-            updater = new SynonymUpdater(file, item);
+        try (SynonymUpdater updater = new SynonymUpdater(item)) {
             reload(updater);
-        } finally {
-            if (updater != null) {
-                updater.close();
-            }
         }
     }
 
@@ -129,22 +97,15 @@ public class SynonymFile extends DictionaryFile<SynonymItem> {
         final SynonymItem synonymItem = item;
         synonymItem.setNewInputs(StringUtil.EMPTY_STRINGS);
         synonymItem.setNewOutputs(StringUtil.EMPTY_STRINGS);
-        SynonymUpdater updater = null;
-        try {
-            updater = new SynonymUpdater(file, synonymItem);
+        try (SynonymUpdater updater = new SynonymUpdater(item)) {
             reload(updater);
-        } finally {
-            if (updater != null) {
-                updater.close();
-            }
         }
     }
 
     protected void reload(final SynonymUpdater updater) {
         final List<SynonymItem> itemList = new ArrayList<SynonymItem>();
-        BufferedReader reader = null;
-        try {
-            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), Constants.UTF_8));
+        try (BufferedReader reader =
+                new BufferedReader(new InputStreamReader(dictionaryManager.getContentInputStream(this), Constants.UTF_8))) {
             long id = 0;
             String line = null;
             while ((line = reader.readLine()) != null) {
@@ -213,13 +174,14 @@ public class SynonymFile extends DictionaryFile<SynonymItem> {
                 }
             }
             if (updater != null) {
-                updater.commit();
+                SynonymItem item = updater.commit();
+                if (item != null) {
+                    itemList.add(item);
+                }
             }
             synonymItemList = itemList;
         } catch (final IOException e) {
-            throw new DictionaryException("Failed to parse " + file.getAbsolutePath(), e);
-        } finally {
-            IOUtils.closeQuietly(reader);
+            throw new DictionaryException("Failed to parse " + path, e);
         }
     }
 
@@ -273,11 +235,28 @@ public class SynonymFile extends DictionaryFile<SynonymItem> {
         return s;
     }
 
-    protected static class SynonymUpdater {
+    public String getSimpleName() {
+        return new File(path).getName();
+    }
+
+    // TODO
+    //    public InputStream getInputStream() throws IOException {
+    //        return new BufferedInputStream(new FileInputStream(file));
+    //    }
+    //
+    //    public void update(final InputStream in) throws IOException {
+    //        CopyUtil.copy(in, file);
+    //        reload(null);
+    //    }
 
-        protected boolean isCommit = false;
+    @Override
+    public String toString() {
+        return "SynonymFile [path=" + path + ", synonymItemList=" + synonymItemList + ", id=" + id + "]";
+    }
 
-        protected File oldFile;
+    protected class SynonymUpdater implements Closeable {
+
+        protected boolean isCommit = false;
 
         protected File newFile;
 
@@ -285,7 +264,7 @@ public class SynonymFile extends DictionaryFile<SynonymItem> {
 
         protected SynonymItem item;
 
-        protected SynonymUpdater(final File file, final SynonymItem newItem) {
+        protected SynonymUpdater(final SynonymItem newItem) {
             try {
                 newFile = File.createTempFile(SYNONYM, ".txt");
                 writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(newFile), Constants.UTF_8));
@@ -295,7 +274,6 @@ public class SynonymFile extends DictionaryFile<SynonymItem> {
                 }
                 throw new DictionaryException("Failed to write a synonym file.", e);
             }
-            oldFile = file;
             item = newItem;
         }
 
@@ -338,10 +316,21 @@ public class SynonymFile extends DictionaryFile<SynonymItem> {
             }
         }
 
-        public void commit() {
+        public SynonymItem commit() {
             isCommit = true;
+            if (item.isUpdated()) {
+                try {
+                    writer.write(item.toLineString());
+                    writer.write(Constants.LINE_SEPARATOR);
+                    return item;
+                } catch (final IOException e) {
+                    throw new DictionaryException("Failed to write: " + item, e);
+                }
+            }
+            return null;
         }
 
+        @Override
         public void close() {
             try {
                 writer.flush();
@@ -352,33 +341,13 @@ public class SynonymFile extends DictionaryFile<SynonymItem> {
 
             if (isCommit) {
                 try {
-                    FileUtils.copyFile(newFile, oldFile);
+                    dictionaryManager.store(SynonymFile.this, newFile);
+                } finally {
                     newFile.delete();
-                } catch (final IOException e) {
-                    throw new DictionaryException("Failed to replace " + oldFile.getAbsolutePath() + " with " + newFile.getAbsolutePath(),
-                            e);
                 }
             } else {
                 newFile.delete();
             }
         }
     }
-
-    public String getSimpleName() {
-        return file.getName();
-    }
-
-    public InputStream getInputStream() throws IOException {
-        return new BufferedInputStream(new FileInputStream(file));
-    }
-
-    public void update(final InputStream in) throws IOException {
-        CopyUtil.copy(in, file);
-        reload(null);
-    }
-
-    @Override
-    public String toString() {
-        return "SynonymFile [file=" + file + ", synonymItemList=" + synonymItemList + ", id=" + id + "]";
-    }
 }

+ 0 - 55
src/main/java/org/codelibs/fess/dict/synonym/SynonymLocator.java

@@ -1,55 +0,0 @@
-/*
- * Copyright 2009-2015 the CodeLibs Project and the Others.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language
- * governing permissions and limitations under the License.
- */
-
-package org.codelibs.fess.dict.synonym;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import org.codelibs.fess.dict.DictionaryFile;
-import org.codelibs.fess.dict.DictionaryItem;
-import org.codelibs.fess.dict.DictionaryLocator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class SynonymLocator extends DictionaryLocator {
-    private static final Logger logger = LoggerFactory.getLogger(SynonymLocator.class);
-
-    public String synonymFilePrefix = "synonym";
-
-    public List<String> excludedSynonymList;
-
-    @Override
-    public List<DictionaryFile<? extends DictionaryItem>> find() {
-        final List<DictionaryFile<? extends DictionaryItem>> fileList = new ArrayList<DictionaryFile<? extends DictionaryItem>>();
-        for (final String path : searchPathList) {
-            if (logger.isInfoEnabled()) {
-                logger.info("Synonym Files from " + path);
-            }
-            final File[] files = findFiles(path, synonymFilePrefix, excludedSynonymList);
-            for (final File file : files) {
-                if (logger.isInfoEnabled()) {
-                    logger.info("Synonym File: " + file.getAbsolutePath());
-                }
-                fileList.add(new SynonymFile(file));
-            }
-        }
-        Collections.sort(fileList, (o1, o2) -> o1.getName().compareTo(o2.getName()));
-        return fileList;
-    }
-}

+ 0 - 55
src/main/java/org/codelibs/fess/dict/userdict/UserDictLocator.java

@@ -1,55 +0,0 @@
-/*
- * Copyright 2009-2015 the CodeLibs Project and the Others.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language
- * governing permissions and limitations under the License.
- */
-
-package org.codelibs.fess.dict.userdict;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import org.codelibs.fess.dict.DictionaryFile;
-import org.codelibs.fess.dict.DictionaryItem;
-import org.codelibs.fess.dict.DictionaryLocator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class UserDictLocator extends DictionaryLocator {
-    private static final Logger logger = LoggerFactory.getLogger(UserDictLocator.class);
-
-    public String userDictFilePrefix = "userdict";
-
-    public List<String> excludedUserDictList;
-
-    @Override
-    public List<DictionaryFile<? extends DictionaryItem>> find() {
-        final List<DictionaryFile<? extends DictionaryItem>> fileList = new ArrayList<DictionaryFile<? extends DictionaryItem>>();
-        for (final String path : searchPathList) {
-            if (logger.isInfoEnabled()) {
-                logger.info("UserDict Files from " + path);
-            }
-            final File[] files = findFiles(path, userDictFilePrefix, excludedUserDictList);
-            for (final File file : files) {
-                if (logger.isInfoEnabled()) {
-                    logger.info("UserDict File: " + file.getAbsolutePath());
-                }
-                fileList.add(new UserDictFile(file));
-            }
-        }
-        Collections.sort(fileList, (o1, o2) -> o1.getName().compareTo(o2.getName()));
-        return fileList;
-    }
-}

+ 1 - 1
src/main/java/org/codelibs/fess/exec/Crawler.java

@@ -304,7 +304,7 @@ public class Crawler implements Serializable {
                 // ignore
             }
 
-            final FileTemplateLoader loader = new FileTemplateLoader(new File(ResourceUtil.getMailTemplatePath(StringUtil.EMPTY)));
+            final FileTemplateLoader loader = new FileTemplateLoader(ResourceUtil.getMailTemplatePath(StringUtil.EMPTY).toFile());
             final Handlebars handlebars = new Handlebars(loader);
 
             try {

+ 1 - 1
src/main/java/org/codelibs/fess/helper/ViewHelper.java

@@ -388,7 +388,7 @@ public class ViewHelper implements Serializable {
 
     public String createCacheContent(final Map<String, Object> doc, final String[] queries) {
         final FieldHelper fieldHelper = ComponentUtil.getFieldHelper();
-        final FileTemplateLoader loader = new FileTemplateLoader(new File(ResourceUtil.getViewTemplatePath(StringUtil.EMPTY)));
+        final FileTemplateLoader loader = new FileTemplateLoader(ResourceUtil.getViewTemplatePath().toFile());
         final Handlebars handlebars = new Handlebars(loader);
 
         Locale locale = LaRequestUtil.getRequest().getLocale();

+ 18 - 18
src/main/java/org/codelibs/fess/mylasta/action/FessHtmlPath.java

@@ -59,6 +59,24 @@ public interface FessHtmlPath {
     /** The path of the HTML: /admin/dict/index.jsp */
     HtmlNext path_AdminDict_IndexJsp = new HtmlNext("/admin/dict/index.jsp");
 
+    /** The path of the HTML: /admin/dict/kuromoji/confirm.jsp */
+    HtmlNext path_AdminDictKuromoji_ConfirmJsp = new HtmlNext("/admin/dict/kuromoji/confirm.jsp");
+
+    /** The path of the HTML: /admin/dict/kuromoji/download.jsp */
+    HtmlNext path_AdminDictKuromoji_DownloadJsp = new HtmlNext("/admin/dict/kuromoji/download.jsp");
+
+    /** The path of the HTML: /admin/dict/kuromoji/edit.jsp */
+    HtmlNext path_AdminDictKuromoji_EditJsp = new HtmlNext("/admin/dict/kuromoji/edit.jsp");
+
+    /** The path of the HTML: /admin/dict/kuromoji/error.jsp */
+    HtmlNext path_AdminDictKuromoji_ErrorJsp = new HtmlNext("/admin/dict/kuromoji/error.jsp");
+
+    /** The path of the HTML: /admin/dict/kuromoji/index.jsp */
+    HtmlNext path_AdminDictKuromoji_IndexJsp = new HtmlNext("/admin/dict/kuromoji/index.jsp");
+
+    /** The path of the HTML: /admin/dict/kuromoji/upload.jsp */
+    HtmlNext path_AdminDictKuromoji_UploadJsp = new HtmlNext("/admin/dict/kuromoji/upload.jsp");
+
     /** The path of the HTML: /admin/dict/synonym/confirm.jsp */
     HtmlNext path_AdminDictSynonym_ConfirmJsp = new HtmlNext("/admin/dict/synonym/confirm.jsp");
 
@@ -77,24 +95,6 @@ public interface FessHtmlPath {
     /** The path of the HTML: /admin/dict/synonym/upload.jsp */
     HtmlNext path_AdminDictSynonym_UploadJsp = new HtmlNext("/admin/dict/synonym/upload.jsp");
 
-    /** The path of the HTML: /admin/dict/userdict/confirm.jsp */
-    HtmlNext path_AdminDictUserdict_ConfirmJsp = new HtmlNext("/admin/dict/userdict/confirm.jsp");
-
-    /** The path of the HTML: /admin/dict/userdict/download.jsp */
-    HtmlNext path_AdminDictUserdict_DownloadJsp = new HtmlNext("/admin/dict/userdict/download.jsp");
-
-    /** The path of the HTML: /admin/dict/userdict/edit.jsp */
-    HtmlNext path_AdminDictUserdict_EditJsp = new HtmlNext("/admin/dict/userdict/edit.jsp");
-
-    /** The path of the HTML: /admin/dict/userdict/error.jsp */
-    HtmlNext path_AdminDictUserdict_ErrorJsp = new HtmlNext("/admin/dict/userdict/error.jsp");
-
-    /** The path of the HTML: /admin/dict/userdict/index.jsp */
-    HtmlNext path_AdminDictUserdict_IndexJsp = new HtmlNext("/admin/dict/userdict/index.jsp");
-
-    /** The path of the HTML: /admin/dict/userdict/upload.jsp */
-    HtmlNext path_AdminDictUserdict_UploadJsp = new HtmlNext("/admin/dict/userdict/upload.jsp");
-
     /** The path of the HTML: /admin/failureurl/confirm.jsp */
     HtmlNext path_AdminFailureurl_ConfirmJsp = new HtmlNext("/admin/failureurl/confirm.jsp");
 

+ 8 - 0
src/main/java/org/codelibs/fess/util/ComponentUtil.java

@@ -20,6 +20,7 @@ import org.codelibs.core.crypto.CachedCipher;
 import org.codelibs.core.misc.DynamicProperties;
 import org.codelibs.fess.api.WebApiManagerFactory;
 import org.codelibs.fess.app.web.base.login.FessLoginAssist;
+import org.codelibs.fess.dict.DictionaryManager;
 import org.codelibs.fess.ds.DataStoreFactory;
 import org.codelibs.fess.es.client.FessEsClient;
 import org.codelibs.fess.helper.AdRoleHelper;
@@ -52,6 +53,8 @@ import org.lastaflute.di.core.SingletonLaContainer;
 import org.lastaflute.di.core.factory.SingletonLaContainerFactory;
 
 public final class ComponentUtil {
+    private static final String DICTIONARY_MANAGER = "dictionaryManager";
+
     private static final String DATA_SERVICE = "dataService";
 
     private static final String MESSAGE_MANAGER = "messageManager";
@@ -247,6 +250,11 @@ public final class ComponentUtil {
         return SingletonLaContainer.getComponent(MESSAGE_MANAGER);
     }
 
+    public static DictionaryManager getDictionaryManager() {
+        return SingletonLaContainer.getComponent(DICTIONARY_MANAGER);
+
+    }
+
     public static DataService<EsAccessResult> getDataService() {
         return SingletonLaContainer.getComponent(DATA_SERVICE);
     }

+ 2 - 2
src/main/java/org/codelibs/fess/util/UserDictCSVUtil.java → src/main/java/org/codelibs/fess/util/KuromojiCSVUtil.java

@@ -24,7 +24,7 @@ import java.util.regex.Pattern;
 /**
  * Utility class for parsing CSV text
  */
-public final class UserDictCSVUtil {
+public final class KuromojiCSVUtil {
     private static final char QUOTE = '"';
 
     private static final char COMMA = ',';
@@ -33,7 +33,7 @@ public final class UserDictCSVUtil {
 
     private static final String ESCAPED_QUOTE = "\"\"";
 
-    private UserDictCSVUtil() {
+    private KuromojiCSVUtil() {
     } // no instance!!!
 
     /**

+ 33 - 18
src/main/java/org/codelibs/fess/util/ResourceUtil.java

@@ -18,6 +18,9 @@ package org.codelibs.fess.util;
 
 import java.io.File;
 import java.io.FilenameFilter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -32,43 +35,55 @@ public class ResourceUtil {
         // nothing
     }
 
-    public static String getDbPath(final String name) {
-        return getBasePath("WEB-INF/db/", name);
+    public static Path getConfPath(final String... names) {
+        return getPath("conf", names);
     }
 
-    public static String getConfPath(final String name) {
-        return getBasePath("WEB-INF/conf/", name);
+    public static Path getClassesPath(final String... names) {
+        return getPath("classes", names);
     }
 
-    public static String getClassesPath(final String name) {
-        return getBasePath("WEB-INF/classes/", name);
+    public static Path getOrigPath(final String... names) {
+        return getPath("orig", names);
     }
 
-    public static String getOrigPath(final String name) {
-        return getBasePath("WEB-INF/orig/", name);
+    public static Path getMailTemplatePath(final String... names) {
+        return getPath("mail", names);
     }
 
-    public static String getMailTemplatePath(final String name) {
-        return getBasePath("WEB-INF/mail/", name);
+    public static Path getViewTemplatePath(final String... names) {
+        return getPath("view", names);
     }
 
-    public static String getViewTemplatePath(final String name) {
-        return getBasePath("WEB-INF/view/", name);
+    public static Path getDictionaryPath(final String... names) {
+        return getPath("dict", names);
     }
 
-    protected static String getBasePath(final String baseName, final String name) {
+    protected static Path getPath(final String base, String... names) {
 
-        String path = null;
         try {
             final ServletContext servletContext = SingletonLaContainer.getComponent(ServletContext.class);
-            if (servletContext != null) {
-                path = servletContext.getRealPath("/" + baseName + name);
+            String webinfoPath = servletContext.getRealPath("/WEB-INF/" + base);
+            if (webinfoPath != null) {
+                Path path = Paths.get(webinfoPath, names);
+                if (Files.exists(path)) {
+                    return path;
+                }
             }
         } catch (final Throwable e) { // NOSONAR
             // ignore
         }
-        if (path == null) {
-            path = new File(baseName + name).getAbsolutePath();
+        Path path = Paths.get(".", names);
+        if (Files.exists(path)) {
+            return path;
+        }
+        path = Paths.get("src/main/webapps/WEB-INF/" + base, names);
+        if (Files.exists(path)) {
+            return path;
+        }
+        path = Paths.get("target/fess/WEB-INF/" + base, names);
+        if (Files.exists(path)) {
+            return path;
         }
         return path;
     }

+ 7 - 16
src/main/resources/fess_dict.xml

@@ -3,28 +3,19 @@
 	"http://dbflute.org/meta/lastadi10.dtd">
 <components>
 	<component name="dictionaryManager" class="org.codelibs.fess.dict.DictionaryManager">
-		<postConstruct name="addLocator">
-			<arg>userDictLocator</arg>
+		<property name="esUrl">"http://localhost:9201"</property>
+		<postConstruct name="addCreator">
+			<arg>userDictCreator</arg>
 		</postConstruct>
-		<postConstruct name="addLocator">
-			<arg>synonymLocator</arg>
+		<postConstruct name="addCreator">
+			<arg>synonymCreator</arg>
 		</postConstruct>
 	</component>
 
-	<component name="synonymLocator" class="org.codelibs.fess.dict.synonym.SynonymLocator">
-		<property name="excludedSynonymList">["data", "txlog",
-			"lib", "bin", "contrib"]</property>
-		<postConstruct name="addSearchPath">
-			<arg>"${solr.solr.home}"</arg>
-		</postConstruct>
+	<component name="synonymCreator" class="org.codelibs.fess.dict.synonym.SynonymCreator">
 	</component>
 
-	<component name="userDictLocator" class="org.codelibs.fess.dict.userdict.UserDictLocator">
-		<property name="excludedUserDictList">["data", "txlog",
-			"lib", "bin", "contrib"]</property>
-		<postConstruct name="addSearchPath">
-			<arg>"${solr.solr.home}"</arg>
-		</postConstruct>
+	<component name="userDictCreator" class="org.codelibs.fess.dict.kuromoji.KuromojiCreator">
 	</component>
 
 </components>

+ 1 - 1
src/main/webapp/WEB-INF/view/admin/dict/error.jsp

@@ -9,7 +9,7 @@
 	<div class="wrapper">
 		<jsp:include page="/WEB-INF/view/common/admin2/header.jsp"></jsp:include>
 		<jsp:include page="/WEB-INF/view/common/admin2/sidebar.jsp">
-			<jsp:param name="menuCategoryType" value="crawl" />
+			<jsp:param name="menuCategoryType" value="system" />
 			<jsp:param name="menuType" value="dict" />
 		</jsp:include>
 

+ 2 - 2
src/main/webapp/WEB-INF/view/admin/dict/index.jsp

@@ -9,7 +9,7 @@
 	<div class="wrapper">
 		<jsp:include page="/WEB-INF/view/common/admin2/header.jsp"></jsp:include>
 		<jsp:include page="/WEB-INF/view/common/admin2/sidebar.jsp">
-			<jsp:param name="menuCategoryType" value="crawl" />
+			<jsp:param name="menuCategoryType" value="system" />
 			<jsp:param name="menuType" value="dict" />
 		</jsp:include>
 
@@ -63,7 +63,7 @@
 											<c:forEach var="data" varStatus="s" items="${dictFiles}">
 												<tr class="${s.index % 2 == 0 ? 'row1' : 'row2'}">
 														<td>${f:h(data.type)}</td>
-														<td><la:link href="${f:h(data.type)}/index?dictId=${f:h(data.id)}">${f:h(data.name)}</la:link></td>
+														<td><la:link href="${f:h(data.type)}/?dictId=${f:h(data.id)}">${f:h(data.path)}</la:link></td>
 												</tr>
 											</c:forEach>
 										</tbody>

+ 1 - 1
src/main/webapp/WEB-INF/view/admin/dict/userdict/confirm.jsp → src/main/webapp/WEB-INF/view/admin/dict/kuromoji/confirm.jsp

@@ -9,7 +9,7 @@
 	<div class="wrapper">
 	<jsp:include page="/WEB-INF/view/common/admin2/header.jsp"></jsp:include>
 	<jsp:include page="/WEB-INF/view/common/admin2/sidebar.jsp">
-		<jsp:param name="menuCategoryType" value="crawl" />
+		<jsp:param name="menuCategoryType" value="system" />
 		<jsp:param name="menuType" value="dict" />
 	</jsp:include>
 

+ 1 - 1
src/main/webapp/WEB-INF/view/admin/dict/userdict/download.jsp → src/main/webapp/WEB-INF/view/admin/dict/kuromoji/download.jsp

@@ -9,7 +9,7 @@
 	<div class="wrapper">
 	<jsp:include page="/WEB-INF/view/common/admin2/header.jsp"></jsp:include>
 	<jsp:include page="/WEB-INF/view/common/admin2/sidebar.jsp">
-		<jsp:param name="menuCategoryType" value="crawl" />
+		<jsp:param name="menuCategoryType" value="system" />
 		<jsp:param name="menuType" value="dict" />
 	</jsp:include>
 

+ 1 - 1
src/main/webapp/WEB-INF/view/admin/dict/userdict/edit.jsp → src/main/webapp/WEB-INF/view/admin/dict/kuromoji/edit.jsp

@@ -9,7 +9,7 @@
     <div class="wrapper">
 	<jsp:include page="/WEB-INF/view/common/admin2/header.jsp"></jsp:include>
 	<jsp:include page="/WEB-INF/view/common/admin2/sidebar.jsp">
-	    <jsp:param name="menuCategoryType" value="crawl" />
+	    <jsp:param name="menuCategoryType" value="system" />
 	    <jsp:param name="menuType" value="dict" />
 	</jsp:include>
 	<div class="content-wrapper">

+ 1 - 1
src/main/webapp/WEB-INF/view/admin/dict/userdict/error.jsp → src/main/webapp/WEB-INF/view/admin/dict/kuromoji/error.jsp

@@ -9,7 +9,7 @@
 	<div class="wrapper">
 		<jsp:include page="/WEB-INF/view/common/admin2/header.jsp"></jsp:include>
 		<jsp:include page="/WEB-INF/view/common/admin2/sidebar.jsp">
-			<jsp:param name="menuCategoryType" value="crawl" />
+			<jsp:param name="menuCategoryType" value="system" />
 			<jsp:param name="menuType" value="dict" />
 		</jsp:include>
 

+ 1 - 1
src/main/webapp/WEB-INF/view/admin/dict/userdict/index.jsp → src/main/webapp/WEB-INF/view/admin/dict/kuromoji/index.jsp

@@ -9,7 +9,7 @@
 	<div class="wrapper">
 	<jsp:include page="/WEB-INF/view/common/admin2/header.jsp"></jsp:include>
 	<jsp:include page="/WEB-INF/view/common/admin2/sidebar.jsp">
-		<jsp:param name="menuCategoryType" value="crawl" />
+		<jsp:param name="menuCategoryType" value="system" />
 		<jsp:param name="menuType" value="dict" />
 	</jsp:include>
 

+ 1 - 1
src/main/webapp/WEB-INF/view/admin/dict/userdict/upload.jsp → src/main/webapp/WEB-INF/view/admin/dict/kuromoji/upload.jsp

@@ -9,7 +9,7 @@
 	<div class="wrapper">
 	<jsp:include page="/WEB-INF/view/common/admin2/header.jsp"></jsp:include>
 	<jsp:include page="/WEB-INF/view/common/admin2/sidebar.jsp">
-		<jsp:param name="menuCategoryType" value="crawl" />
+		<jsp:param name="menuCategoryType" value="system" />
 		<jsp:param name="menuType" value="dict" />
 	</jsp:include>
 

+ 1 - 1
src/main/webapp/WEB-INF/view/admin/dict/synonym/confirm.jsp

@@ -9,7 +9,7 @@
 	<div class="wrapper">
 	<jsp:include page="/WEB-INF/view/common/admin2/header.jsp"></jsp:include>
 	<jsp:include page="/WEB-INF/view/common/admin2/sidebar.jsp">
-		<jsp:param name="menuCategoryType" value="crawl" />
+		<jsp:param name="menuCategoryType" value="system" />
 		<jsp:param name="menuType" value="dict" />
 	</jsp:include>
 

+ 1 - 1
src/main/webapp/WEB-INF/view/admin/dict/synonym/download.jsp

@@ -9,7 +9,7 @@
 	<div class="wrapper">
 	<jsp:include page="/WEB-INF/view/common/admin2/header.jsp"></jsp:include>
 	<jsp:include page="/WEB-INF/view/common/admin2/sidebar.jsp">
-		<jsp:param name="menuCategoryType" value="crawl" />
+		<jsp:param name="menuCategoryType" value="system" />
 		<jsp:param name="menuType" value="dict" />
 	</jsp:include>
 

+ 1 - 1
src/main/webapp/WEB-INF/view/admin/dict/synonym/edit.jsp

@@ -9,7 +9,7 @@
     <div class="wrapper">
 	<jsp:include page="/WEB-INF/view/common/admin2/header.jsp"></jsp:include>
 	<jsp:include page="/WEB-INF/view/common/admin2/sidebar.jsp">
-	    <jsp:param name="menuCategoryType" value="crawl" />
+	    <jsp:param name="menuCategoryType" value="system" />
 	    <jsp:param name="menuType" value="dict" />
 	</jsp:include>
 	<div class="content-wrapper">

+ 1 - 1
src/main/webapp/WEB-INF/view/admin/dict/synonym/error.jsp

@@ -9,7 +9,7 @@
 	<div class="wrapper">
 		<jsp:include page="/WEB-INF/view/common/admin2/header.jsp"></jsp:include>
 		<jsp:include page="/WEB-INF/view/common/admin2/sidebar.jsp">
-			<jsp:param name="menuCategoryType" value="crawl" />
+			<jsp:param name="menuCategoryType" value="system" />
 			<jsp:param name="menuType" value="dict" />
 		</jsp:include>
 

+ 1 - 1
src/main/webapp/WEB-INF/view/admin/dict/synonym/index.jsp

@@ -9,7 +9,7 @@
 	<div class="wrapper">
 	<jsp:include page="/WEB-INF/view/common/admin2/header.jsp"></jsp:include>
 	<jsp:include page="/WEB-INF/view/common/admin2/sidebar.jsp">
-		<jsp:param name="menuCategoryType" value="crawl" />
+		<jsp:param name="menuCategoryType" value="system" />
 		<jsp:param name="menuType" value="dict" />
 	</jsp:include>
 

+ 1 - 1
src/main/webapp/WEB-INF/view/admin/dict/synonym/upload.jsp

@@ -9,7 +9,7 @@
 	<div class="wrapper">
 	<jsp:include page="/WEB-INF/view/common/admin2/header.jsp"></jsp:include>
 	<jsp:include page="/WEB-INF/view/common/admin2/sidebar.jsp">
-		<jsp:param name="menuCategoryType" value="crawl" />
+		<jsp:param name="menuCategoryType" value="system" />
 		<jsp:param name="menuType" value="dict" />
 	</jsp:include>