diff --git a/src/main/java/org/codelibs/fess/app/pager/CharMappingPager.java b/src/main/java/org/codelibs/fess/app/pager/CharMappingPager.java new file mode 100644 index 000000000..ebfda01b8 --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/pager/CharMappingPager.java @@ -0,0 +1,123 @@ +/* + * Copyright 2012-2016 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.app.pager; + +import java.io.Serializable; +import java.util.List; + +import org.codelibs.fess.Constants; + +public class CharMappingPager implements Serializable { + + private static final long serialVersionUID = 1L; + + private int allRecordCount; + + private int allPageCount; + + private boolean existPrePage; + + private boolean existNextPage; + + private List pageNumberList; + + private int pageSize; + + private int currentPageNumber; + + public String id; + + public void clear() { + allRecordCount = 0; + allPageCount = 0; + existPrePage = false; + existNextPage = false; + pageSize = getDefaultPageSize(); + currentPageNumber = getDefaultCurrentPageNumber(); + + id = null; + } + + protected int getDefaultPageSize() { + return Constants.DEFAULT_ADMIN_PAGE_SIZE; + } + + protected int getDefaultCurrentPageNumber() { + return 1; + } + + public int getAllRecordCount() { + return allRecordCount; + } + + public void setAllRecordCount(final int allRecordCount) { + this.allRecordCount = allRecordCount; + } + + public int getAllPageCount() { + return allPageCount; + } + + public void setAllPageCount(final int allPageCount) { + this.allPageCount = allPageCount; + } + + public boolean isExistPrePage() { + return existPrePage; + } + + public void setExistPrePage(final boolean existPrePage) { + this.existPrePage = existPrePage; + } + + public boolean isExistNextPage() { + return existNextPage; + } + + public void setExistNextPage(final boolean existNextPage) { + this.existNextPage = existNextPage; + } + + public int getPageSize() { + if (pageSize <= 0) { + pageSize = getDefaultPageSize(); + } + return pageSize; + } + + public void setPageSize(final int pageSize) { + this.pageSize = pageSize; + } + + public int getCurrentPageNumber() { + if (currentPageNumber <= 0) { + currentPageNumber = getDefaultCurrentPageNumber(); + } + return currentPageNumber; + } + + public void setCurrentPageNumber(final int currentPageNumber) { + this.currentPageNumber = currentPageNumber; + } + + public List getPageNumberList() { + return pageNumberList; + } + + public void setPageNumberList(final List pageNumberList) { + this.pageNumberList = pageNumberList; + } +} diff --git a/src/main/java/org/codelibs/fess/app/service/CharMappingService.java b/src/main/java/org/codelibs/fess/app/service/CharMappingService.java new file mode 100644 index 000000000..5ab70646d --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/service/CharMappingService.java @@ -0,0 +1,75 @@ +/* + * Copyright 2012-2016 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.app.service; + +import java.util.Collections; +import java.util.List; + +import javax.annotation.Resource; + +import org.codelibs.core.beans.util.BeanUtil; +import org.codelibs.fess.Constants; +import org.codelibs.fess.app.pager.CharMappingPager; +import org.codelibs.fess.dict.DictionaryFile.PagingList; +import org.codelibs.fess.dict.DictionaryManager; +import org.codelibs.fess.dict.mapping.CharMappingFile; +import org.codelibs.fess.dict.mapping.CharMappingItem; +import org.dbflute.optional.OptionalEntity; + +public class CharMappingService { + @Resource + protected DictionaryManager dictionaryManager; + + public List getCharMappingList(final String dictId, final CharMappingPager charMappingPager) { + return getCharMappingFile(dictId).map(file -> { + final int pageSize = charMappingPager.getPageSize(); + final PagingList charMappingList = + file.selectList((charMappingPager.getCurrentPageNumber() - 1) * pageSize, pageSize); + + // update pager + BeanUtil.copyBeanToBean(charMappingList, charMappingPager, option -> option.include(Constants.PAGER_CONVERSION_RULE)); + charMappingList.setPageRangeSize(5); + charMappingPager.setPageNumberList(charMappingList.createPageNumberList()); + + return (List) charMappingList; + }).orElse(Collections.emptyList()); + } + + public OptionalEntity getCharMappingFile(final String dictId) { + return dictionaryManager.getDictionaryFile(dictId).filter(file -> file instanceof CharMappingFile) + .map(file -> OptionalEntity.of((CharMappingFile) file)).orElse(OptionalEntity.empty()); + } + + public OptionalEntity getCharMappingItem(final String dictId, final long id) { + return getCharMappingFile(dictId).map(file -> file.get(id).get()); + } + + public void store(final String dictId, final CharMappingItem charMappingItem) { + getCharMappingFile(dictId).ifPresent(file -> { + if (charMappingItem.getId() == 0) { + file.insert(charMappingItem); + } else { + file.update(charMappingItem); + } + }); + } + + public void delete(final String dictId, final CharMappingItem charMappingItem) { + getCharMappingFile(dictId).ifPresent(file -> { + file.delete(charMappingItem); + }); + } +} diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/AdminDictMappingAction.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/AdminDictMappingAction.java new file mode 100644 index 000000000..bf1964cc4 --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/AdminDictMappingAction.java @@ -0,0 +1,434 @@ +/* + * Copyright 2012-2016 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.app.web.admin.dict.mapping; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +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.CharMappingPager; +import org.codelibs.fess.app.service.CharMappingService; +import org.codelibs.fess.app.web.CrudMode; +import org.codelibs.fess.app.web.admin.dict.AdminDictAction; +import org.codelibs.fess.app.web.base.FessAdminAction; +import org.codelibs.fess.dict.mapping.CharMappingItem; +import org.codelibs.fess.util.RenderDataUtil; +import org.dbflute.optional.OptionalEntity; +import org.dbflute.optional.OptionalThing; +import org.lastaflute.web.Execute; +import org.lastaflute.web.response.ActionResponse; +import org.lastaflute.web.response.HtmlResponse; +import org.lastaflute.web.response.render.RenderData; +import org.lastaflute.web.ruts.process.ActionRuntime; +import org.lastaflute.web.validation.VaErrorHook; + +/** + * @author nullpos + * @author ma2tani + */ +public class AdminDictMappingAction extends FessAdminAction { + + // =================================================================================== + // Attribute + // ========= + @Resource + private CharMappingService charMappingService; + @Resource + private CharMappingPager charMappingPager; + + // =================================================================================== + // Hook + // ====== + @Override + protected void setupHtmlData(final ActionRuntime runtime) { + super.setupHtmlData(runtime); + runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNameDictMapping())); + } + + // =================================================================================== + // Search Execute + // ============== + @Execute + public HtmlResponse index(final SearchForm form) { + validate(form, messages -> {}, () -> asDictIndexHtml()); + return asHtml(path_AdminDictMapping_AdminDictMappingJsp).renderWith(data -> { + searchPaging(data, form); + }); + } + + @Execute + public HtmlResponse list(final OptionalThing pageNumber, final SearchForm form) { + validate(form, messages -> {}, () -> asDictIndexHtml()); + pageNumber.ifPresent(num -> { + charMappingPager.setCurrentPageNumber(pageNumber.get()); + }).orElse(() -> { + charMappingPager.setCurrentPageNumber(0); + }); + return asHtml(path_AdminDictMapping_AdminDictMappingJsp).renderWith(data -> { + searchPaging(data, form); + }); + } + + @Execute + public HtmlResponse search(final SearchForm form) { + validate(form, messages -> {}, () -> asDictIndexHtml()); + copyBeanToBean(form, charMappingPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE)); + return asHtml(path_AdminDictMapping_AdminDictMappingJsp).renderWith(data -> { + searchPaging(data, form); + }); + } + + @Execute + public HtmlResponse reset(final SearchForm form) { + validate(form, messages -> {}, () -> asDictIndexHtml()); + charMappingPager.clear(); + return asHtml(path_AdminDictMapping_AdminDictMappingJsp).renderWith(data -> { + searchPaging(data, form); + }); + } + + protected void searchPaging(final RenderData data, final SearchForm form) { + // page navi + RenderDataUtil.register(data, "charMappingItemItems", charMappingService.getCharMappingList(form.dictId, charMappingPager)); + + // restore from pager + BeanUtil.copyBeanToBean(charMappingPager, form, op -> { + op.exclude(Constants.PAGER_CONVERSION_RULE); + }); + } + + // =================================================================================== + // Edit Execute + // ============ + // ----------------------------------------------------- + // Entry Page + // ---------- + @Execute + public HtmlResponse createnew(final String dictId) { + saveToken(); + return asHtml(path_AdminDictMapping_AdminDictMappingEditJsp).useForm(CreateForm.class, op -> { + op.setup(form -> { + form.initialize(); + form.crudMode = CrudMode.CREATE; + form.dictId = dictId; + }); + }); + } + + @Execute + public HtmlResponse edit(final EditForm form) { + validate(form, messages -> {}, () -> asListHtml(form.dictId)); + charMappingService + .getCharMappingItem(form.dictId, form.id) + .ifPresent(entity -> { + form.inputs = entity.getInputsValue(); + form.output = entity.getOutput(); + }) + .orElse(() -> { + throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()), + () -> asListHtml(form.dictId)); + }); + saveToken(); + if (form.crudMode.intValue() == CrudMode.EDIT) { + // back + form.crudMode = CrudMode.DETAILS; + return asDetailsHtml(); + } else { + form.crudMode = CrudMode.EDIT; + return asEditHtml(); + } + } + + // ----------------------------------------------------- + // Details + // ------- + @Execute + public HtmlResponse details(final String dictId, final int crudMode, final long id) { + verifyCrudMode(crudMode, CrudMode.DETAILS, dictId); + saveToken(); + return asDetailsHtml().useForm( + EditForm.class, + op -> { + op.setup(form -> { + charMappingService + .getCharMappingItem(dictId, id) + .ifPresent(entity -> { + form.inputs = entity.getInputsValue(); + form.output = entity.getOutput(); + }) + .orElse(() -> { + throwValidationError( + messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, dictId + ":" + id), + () -> asListHtml(dictId)); + }); + form.id = id; + form.crudMode = crudMode; + form.dictId = dictId; + }); + }); + } + + // ----------------------------------------------------- + // Download + // ------- + @Execute + public HtmlResponse downloadpage(final String dictId) { + saveToken(); + return asHtml(path_AdminDictMapping_AdminDictMappingDownloadJsp).useForm(DownloadForm.class, op -> { + op.setup(form -> { + form.dictId = dictId; + }); + }).renderWith(data -> { + charMappingService.getCharMappingFile(dictId).ifPresent(file -> { + RenderDataUtil.register(data, "path", file.getPath()); + }).orElse(() -> { + throwValidationError(messages -> messages.addErrorsFailedToDownloadMappingFile(GLOBAL), () -> asDictIndexHtml()); + }); + }); + } + + @Execute + public ActionResponse download(final DownloadForm form) { + validate(form, messages -> {}, () -> downloadpage(form.dictId)); + verifyTokenKeep(() -> downloadpage(form.dictId)); + return charMappingService.getCharMappingFile(form.dictId).map(file -> { + return asStream(new File(file.getPath()).getName()).contentTypeOctetStream().stream(out -> { + try (InputStream inputStream = file.getInputStream()) { + out.write(inputStream); + } + }); + }).orElseGet(() -> { + throwValidationError(messages -> messages.addErrorsFailedToDownloadMappingFile(GLOBAL), () -> downloadpage(form.dictId)); + return null; + }); + } + + // ----------------------------------------------------- + // Upload + // ------- + @Execute + public HtmlResponse uploadpage(final String dictId) { + saveToken(); + return asHtml(path_AdminDictMapping_AdminDictMappingUploadJsp).useForm(UploadForm.class, op -> { + op.setup(form -> { + form.dictId = dictId; + }); + }).renderWith(data -> { + charMappingService.getCharMappingFile(dictId).ifPresent(file -> { + RenderDataUtil.register(data, "path", file.getPath()); + }).orElse(() -> { + throwValidationError(messages -> messages.addErrorsFailedToDownloadMappingFile(GLOBAL), () -> asDictIndexHtml()); + }); + }); + } + + @Execute + public HtmlResponse upload(final UploadForm form) { + validate(form, messages -> {}, () -> uploadpage(form.dictId)); + verifyToken(() -> uploadpage(form.dictId)); + return charMappingService.getCharMappingFile(form.dictId).map(file -> { + try (InputStream inputStream = form.charMappingFile.getInputStream()) { + file.update(inputStream); + } catch (final IOException e) { + throwValidationError(messages -> messages.addErrorsFailedToUploadMappingFile(GLOBAL), () -> { + return redirectWith(getClass(), moreUrl("uploadpage/" + form.dictId)); + }); + } + saveInfo(messages -> messages.addSuccessUploadMappingFile(GLOBAL)); + return redirectWith(getClass(), moreUrl("uploadpage/" + form.dictId)); + }).orElseGet(() -> { + throwValidationError(messages -> messages.addErrorsFailedToUploadMappingFile(GLOBAL), () -> uploadpage(form.dictId)); + return null; + }); + + } + + // ----------------------------------------------------- + // Actually Crud + // ------------- + @Execute + public HtmlResponse create(final CreateForm form) { + verifyCrudMode(form.crudMode, CrudMode.CREATE, form.dictId); + validate(form, messages -> {}, () -> asEditHtml()); + verifyToken(() -> asEditHtml()); + createCharMappingItem(form, () -> asEditHtml()).ifPresent( + entity -> { + try { + charMappingService.store(form.dictId, entity); + saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL)); + } catch (final Exception e) { + throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)), + () -> asEditHtml()); + } + }).orElse(() -> { + throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), () -> asEditHtml()); + }); + return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId)); + } + + @Execute + public HtmlResponse update(final EditForm form) { + verifyCrudMode(form.crudMode, CrudMode.EDIT, form.dictId); + validate(form, messages -> {}, () -> asEditHtml()); + verifyToken(() -> asEditHtml()); + createCharMappingItem(form, () -> asEditHtml()).ifPresent( + entity -> { + try { + charMappingService.store(form.dictId, entity); + saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL)); + } catch (final Exception e) { + throwValidationError(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)), + () -> asEditHtml()); + } + }).orElse(() -> { + throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()), () -> asEditHtml()); + }); + return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId)); + } + + @Execute + public HtmlResponse delete(final EditForm form) { + verifyCrudMode(form.crudMode, CrudMode.DETAILS, form.dictId); + verifyToken(() -> asDetailsHtml()); + validate(form, messages -> {}, () -> asDetailsHtml()); + charMappingService + .getCharMappingItem(form.dictId, form.id) + .ifPresent( + entity -> { + try { + charMappingService.delete(form.dictId, entity); + saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL)); + } catch (final Exception e) { + throwValidationError( + messages -> messages.addErrorsCrudFailedToDeleteCrudTable(GLOBAL, buildThrowableMessage(e)), + () -> asEditHtml()); + } + }) + .orElse(() -> { + throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()), + () -> asDetailsHtml()); + }); + return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId)); + } + + //=================================================================================== + // Assist Logic + // ============ + + private OptionalEntity getEntity(final CreateForm form) { + switch (form.crudMode) { + case CrudMode.CREATE: + final CharMappingItem entity = new CharMappingItem(0, StringUtil.EMPTY_STRINGS, StringUtil.EMPTY); + return OptionalEntity.of(entity); + case CrudMode.EDIT: + if (form instanceof EditForm) { + return charMappingService.getCharMappingItem(form.dictId, ((EditForm) form).id); + } + break; + default: + break; + } + return OptionalEntity.empty(); + } + + protected OptionalEntity createCharMappingItem(final CreateForm form, final VaErrorHook hook) { + return getEntity(form).map(entity -> { + final String[] newInputs = splitLine(form.inputs); + validateMappingString(newInputs, "inputs", hook); + entity.setNewInputs(newInputs); + final String newOutput = form.output; + entity.setNewOutput(newOutput); + return entity; + }); + } + + // =================================================================================== + // Small Helper + // ============ + protected void verifyCrudMode(final int crudMode, final int expectedMode, final String dictId) { + if (crudMode != expectedMode) { + throwValidationError(messages -> { + messages.addErrorsCrudInvalidMode(GLOBAL, String.valueOf(expectedMode), String.valueOf(crudMode)); + }, () -> asListHtml(dictId)); + } + } + + private void validateMappingString(final String[] values, final String propertyName, final VaErrorHook hook) { + if (values.length == 0) { + return; + } + for (final String value : values) { + if (value.indexOf(',') >= 0) { + throwValidationError(messages -> { + messages.addErrorsInvalidStrIsIncluded(propertyName, value, ","); + }, hook); + } + if (value.indexOf("=>") >= 0) { + throwValidationError(messages -> { + messages.addErrorsInvalidStrIsIncluded(propertyName, value, "=>"); + }, hook); + } + } + } + + private String[] splitLine(final String value) { + if (StringUtil.isBlank(value)) { + return StringUtil.EMPTY_STRINGS; + } + final String[] values = value.split("[\r\n]"); + final List list = new ArrayList<>(values.length); + for (final String line : values) { + if (StringUtil.isNotBlank(line)) { + list.add(line.trim()); + } + } + return list.toArray(new String[list.size()]); + } + + // =================================================================================== + // JSP + // ========= + + protected HtmlResponse asDictIndexHtml() { + return redirect(AdminDictAction.class); + } + + private HtmlResponse asListHtml(final String dictId) { + return asHtml(path_AdminDictMapping_AdminDictMappingJsp).renderWith(data -> { + RenderDataUtil.register(data, "charMappingItemItems", charMappingService.getCharMappingList(dictId, charMappingPager)); + }).useForm(SearchForm.class, setup -> { + setup.setup(form -> { + copyBeanToBean(charMappingPager, form, op -> op.include("id")); + }); + }); + } + + private HtmlResponse asEditHtml() { + return asHtml(path_AdminDictMapping_AdminDictMappingEditJsp); + } + + private HtmlResponse asDetailsHtml() { + return asHtml(path_AdminDictMapping_AdminDictMappingDetailsJsp); + } + +} diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/CreateForm.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/CreateForm.java new file mode 100644 index 000000000..90bedfba3 --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/CreateForm.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2016 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.app.web.admin.dict.mapping; + +import javax.validation.constraints.Size; + +import org.codelibs.fess.app.web.CrudMode; +import org.lastaflute.web.validation.Required; +import org.lastaflute.web.validation.theme.conversion.ValidateTypeFailure; + +/** + * @author nullpos + * @author ma2tani + */ +public class CreateForm { + + @Required + public String dictId; + + @ValidateTypeFailure + public Integer crudMode; + + @Required + @Size(max = 1000) + public String inputs; + + @Size(min = 1, max = 1000) + public String output; + + public void initialize() { + crudMode = CrudMode.CREATE; + } +} diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/DownloadForm.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/DownloadForm.java new file mode 100644 index 000000000..1519445db --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/DownloadForm.java @@ -0,0 +1,23 @@ +/* + * Copyright 2012-2016 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.app.web.admin.dict.mapping; + +import org.lastaflute.web.validation.Required; + +public class DownloadForm { + @Required + public String dictId; +} diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/EditForm.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/EditForm.java new file mode 100644 index 000000000..6cb9dd134 --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/EditForm.java @@ -0,0 +1,33 @@ +/* + * Copyright 2012-2016 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.app.web.admin.dict.mapping; + +import org.lastaflute.web.validation.Required; +import org.lastaflute.web.validation.theme.conversion.ValidateTypeFailure; + +/** + * @author nullpos + */ +public class EditForm extends CreateForm { + + @Required + @ValidateTypeFailure + public Long id; + + public String getDisplayId() { + return dictId + ":" + id; + } +} diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/SearchForm.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/SearchForm.java new file mode 100644 index 000000000..b63367a6f --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/SearchForm.java @@ -0,0 +1,27 @@ +/* + * Copyright 2012-2016 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.app.web.admin.dict.mapping; + +import org.lastaflute.web.validation.Required; + +/** + * @author nullpos + */ +public class SearchForm { + + @Required + public String dictId; +} diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/UploadForm.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/UploadForm.java new file mode 100644 index 000000000..6ec749680 --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/mapping/UploadForm.java @@ -0,0 +1,33 @@ +/* + * Copyright 2012-2016 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.app.web.admin.dict.mapping; + +import org.lastaflute.web.ruts.multipart.MultipartFormFile; +import org.lastaflute.web.validation.Required; + +/** + * @author nullpos + * @author ma2tani + */ +public class UploadForm { + + @Required + public String dictId; + + @Required + public MultipartFormFile charMappingFile; + +} \ No newline at end of file diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/AdminDictProtwordsAction.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/AdminDictProtwordsAction.java index f5aef14af..e6c4ae5da 100644 --- a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/AdminDictProtwordsAction.java +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/AdminDictProtwordsAction.java @@ -15,8 +15,6 @@ */ package org.codelibs.fess.app.web.admin.dict.protwords; -import static org.codelibs.core.stream.StreamUtil.stream; - import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -43,8 +41,7 @@ import org.lastaflute.web.ruts.process.ActionRuntime; import org.lastaflute.web.validation.VaErrorHook; /** - * @author nocode - * @author shinsuke + * @author ma2tani */ public class AdminDictProtwordsAction extends FessAdminAction { @@ -141,7 +138,7 @@ public class AdminDictProtwordsAction extends FessAdminAction { protwordsService .getProtwordsItem(form.dictId, form.id) .ifPresent(entity -> { - form.inputs = entity.getInputsValue(); + form.input = entity.getInputValue(); }) .orElse(() -> { throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()), @@ -172,7 +169,7 @@ public class AdminDictProtwordsAction extends FessAdminAction { protwordsService .getProtwordsItem(dictId, id) .ifPresent(entity -> { - form.inputs = entity.getInputsValue(); + form.input = entity.getInputValue(); }) .orElse(() -> { throwValidationError( @@ -315,7 +312,7 @@ public class AdminDictProtwordsAction extends FessAdminAction { private OptionalEntity getEntity(final CreateForm form) { switch (form.crudMode) { case CrudMode.CREATE: - final ProtwordsItem entity = new ProtwordsItem(0, StringUtil.EMPTY_STRINGS); + final ProtwordsItem entity = new ProtwordsItem(0, StringUtil.EMPTY); return OptionalEntity.of(entity); case CrudMode.EDIT: if (form instanceof EditForm) { @@ -330,9 +327,9 @@ public class AdminDictProtwordsAction extends FessAdminAction { protected OptionalEntity createProtwordsItem(final CreateForm form, final VaErrorHook hook) { return getEntity(form).map(entity -> { - final String[] newInputs = splitLine(form.inputs); - validateProtwordsString(newInputs, "inputs", hook); - entity.setNewInputs(newInputs); + final String newInput = form.input; + validateProtwordsString(newInput, "input", hook); + entity.setNewInput(newInput); return entity; }); } @@ -348,20 +345,13 @@ public class AdminDictProtwordsAction extends FessAdminAction { } } - private void validateProtwordsString(final String[] values, final String propertyName, final VaErrorHook hook) { - if (values.length == 0) { + private void validateProtwordsString(final String values, final String propertyName, final VaErrorHook hook) { + if (values.length() == 0) { return; } // TODO validation } - private String[] splitLine(final String value) { - if (StringUtil.isBlank(value)) { - return StringUtil.EMPTY_STRINGS; - } - return stream(value.split(",")).get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).toArray(n -> new String[n])); - } - // =================================================================================== // JSP // ========= diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/CreateForm.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/CreateForm.java index 9c6bdcbe4..97eceeabc 100644 --- a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/CreateForm.java +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/CreateForm.java @@ -22,7 +22,7 @@ import org.lastaflute.web.validation.Required; import org.lastaflute.web.validation.theme.conversion.ValidateTypeFailure; /** - * @author nocode + * @author ma2tani */ public class CreateForm { @@ -34,7 +34,7 @@ public class CreateForm { @Required @Size(max = 1000) - public String inputs; + public String input; public void initialize() { crudMode = CrudMode.CREATE; diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/EditForm.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/EditForm.java index db4b6b9e7..084677c49 100644 --- a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/EditForm.java +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/EditForm.java @@ -19,7 +19,7 @@ import org.lastaflute.web.validation.Required; import org.lastaflute.web.validation.theme.conversion.ValidateTypeFailure; /** - * @author nocode + * @author ma2tani */ public class EditForm extends CreateForm { diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/SearchForm.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/SearchForm.java index 9dcdb8851..23854bcd0 100644 --- a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/SearchForm.java +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/SearchForm.java @@ -18,7 +18,7 @@ package org.codelibs.fess.app.web.admin.dict.protwords; import org.lastaflute.web.validation.Required; /** - * @author nocode + * @author ma2tani */ public class SearchForm { diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/UploadForm.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/UploadForm.java index 4fd87dd6b..4c1e49b72 100644 --- a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/UploadForm.java +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/UploadForm.java @@ -19,7 +19,7 @@ import org.lastaflute.web.ruts.multipart.MultipartFormFile; import org.lastaflute.web.validation.Required; /** - * @author nocode + * @author ma2tani */ public class UploadForm { diff --git a/src/main/java/org/codelibs/fess/dict/mapping/CharMappingCreator.java b/src/main/java/org/codelibs/fess/dict/mapping/CharMappingCreator.java new file mode 100644 index 000000000..e30028795 --- /dev/null +++ b/src/main/java/org/codelibs/fess/dict/mapping/CharMappingCreator.java @@ -0,0 +1,38 @@ +/* + * Copyright 2012-2016 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.mapping; + +import java.util.Date; + +import org.codelibs.fess.dict.DictionaryCreator; +import org.codelibs.fess.dict.DictionaryFile; +import org.codelibs.fess.dict.DictionaryItem; + +public class CharMappingCreator extends DictionaryCreator { + + public CharMappingCreator() { + super("mapping.*\\.txt"); + } + + public CharMappingCreator(final String pattern) { + super(pattern); + } + + @Override + protected DictionaryFile newDictionaryFile(final String id, final String path, final Date timestamp) { + return new CharMappingFile(id, path, timestamp).manager(dictionaryManager); + } +} diff --git a/src/main/java/org/codelibs/fess/dict/mapping/CharMappingFile.java b/src/main/java/org/codelibs/fess/dict/mapping/CharMappingFile.java new file mode 100644 index 000000000..ae365a534 --- /dev/null +++ b/src/main/java/org/codelibs/fess/dict/mapping/CharMappingFile.java @@ -0,0 +1,295 @@ +/* + * Copyright 2012-2016 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.mapping; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.Closeable; +import java.io.File; +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 java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.io.IOUtils; +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.dbflute.optional.OptionalEntity; + +public class CharMappingFile extends DictionaryFile { + private static final String MAPPING = "mapping"; + + List mappingItemList; + + public CharMappingFile(final String id, final String path, final Date timestamp) { + super(id, path, timestamp); + } + + @Override + public String getType() { + return MAPPING; + } + + @Override + public String getPath() { + return path; + } + + @Override + public OptionalEntity get(long id) { + if (mappingItemList == null) { + reload(null, null); + } + + for (final CharMappingItem mappingItem : mappingItemList) { + if (id == mappingItem.getId()) { + return OptionalEntity.of(mappingItem); + } + } + return OptionalEntity.empty(); + } + + @Override + public synchronized PagingList selectList(final int offset, final int size) { + if (mappingItemList == null) { + reload(null, null); + } + + if (offset >= mappingItemList.size() || offset < 0) { + return new PagingList<>(Collections. emptyList(), offset, size, mappingItemList.size()); + } + + int toIndex = offset + size; + if (toIndex > mappingItemList.size()) { + toIndex = mappingItemList.size(); + } + + return new PagingList<>(mappingItemList.subList(offset, toIndex), offset, size, mappingItemList.size()); + } + + @Override + public synchronized void insert(final CharMappingItem item) { + try (MappingUpdater updater = new MappingUpdater(item)) { + reload(updater, null); + } + } + + @Override + public synchronized void update(final CharMappingItem item) { + try (MappingUpdater updater = new MappingUpdater(item)) { + reload(updater, null); + } + } + + @Override + public synchronized void delete(final CharMappingItem item) { + final CharMappingItem mappingItem = item; + mappingItem.setNewInputs(StringUtil.EMPTY_STRINGS); + mappingItem.setNewOutput(StringUtil.EMPTY); + try (MappingUpdater updater = new MappingUpdater(item)) { + reload(updater, null); + } + } + + protected void reload(final MappingUpdater updater, final InputStream in) { + final Pattern parsePattern = Pattern.compile("(.*)\\s*=>\\s*(.*)\\s*$"); + final List itemList = new ArrayList<>(); + try (BufferedReader reader = + new BufferedReader(new InputStreamReader(in != null ? in : dictionaryManager.getContentInputStream(this), Constants.UTF_8))) { + long id = 0; + String line = null; + while ((line = reader.readLine()) != null) { + // Remove comments + line = line.replaceAll("#.*$", StringUtil.EMPTY); + + // Skip empty lines or comment lines + if (line.trim().length() == 0) { + if (updater != null) { + updater.write(line); + } + continue; + } + + String[] inputs; + String output; + + Matcher m = parsePattern.matcher(line.trim()); + + if (!m.find()) { + throw new DictionaryException("Failed to parse " + path); + } + + inputs = m.group(1).trim().split(","); + output = m.group(2).trim(); + + if (inputs == null || output == null || inputs.length == 0) { + throw new DictionaryException("Failed to parse " + path); + } + + id++; + final CharMappingItem item = new CharMappingItem(id, inputs, output); + + if (updater != null) { + final CharMappingItem newItem = updater.write(item); + if (newItem != null) { + itemList.add(newItem); + } else { + id--; + } + } else { + itemList.add(item); + } + } + if (updater != null) { + final CharMappingItem item = updater.commit(); + if (item != null) { + itemList.add(item); + } + } + mappingItemList = itemList; + } catch (final IOException e) { + throw new DictionaryException("Failed to parse " + path, e); + } + } + + public String getSimpleName() { + return new File(path).getName(); + } + + public InputStream getInputStream() throws IOException { + return new BufferedInputStream(dictionaryManager.getContentInputStream(this)); + } + + public synchronized void update(final InputStream in) throws IOException { + try (MappingUpdater updater = new MappingUpdater(null)) { + reload(updater, in); + } + } + + @Override + public String toString() { + return "MappingFile [path=" + path + ", mappingItemList=" + mappingItemList + ", id=" + id + "]"; + } + + protected class MappingUpdater implements Closeable { + + protected boolean isCommit = false; + + protected File newFile; + + protected Writer writer; + + protected CharMappingItem item; + + protected MappingUpdater(final CharMappingItem newItem) { + try { + newFile = File.createTempFile(MAPPING, ".txt"); + writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(newFile), Constants.UTF_8)); + } catch (final IOException e) { + if (newFile != null) { + newFile.delete(); + } + throw new DictionaryException("Failed to write a userDict file.", e); + } + item = newItem; + } + + public CharMappingItem write(final CharMappingItem oldItem) { + try { + if (item != null && item.getId() == oldItem.getId() && item.isUpdated()) { + if (item.equals(oldItem)) { + try { + if (!item.isDeleted()) { + // update + writer.write(item.toLineString()); + writer.write(Constants.LINE_SEPARATOR); + return new CharMappingItem(item.getId(), item.getNewInputs(), item.getNewOutput()); + } else { + return null; + } + } finally { + item.setNewInputs(null); + item.setNewOutput(null); + } + } else { + throw new DictionaryException("Mapping file was updated: old=" + oldItem + " : new=" + item); + } + } else { + writer.write(oldItem.toLineString()); + writer.write(Constants.LINE_SEPARATOR); + return oldItem; + } + } catch (final IOException e) { + throw new DictionaryException("Failed to write: " + oldItem + " -> " + item, e); + } + } + + public void write(final String line) { + try { + writer.write(line); + writer.write(Constants.LINE_SEPARATOR); + } catch (final IOException e) { + throw new DictionaryException("Failed to write: " + line, e); + } + } + + public CharMappingItem commit() { + isCommit = true; + if (item != null && 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(); + } catch (final IOException e) { + // ignore + } + IOUtils.closeQuietly(writer); + + if (isCommit) { + try { + dictionaryManager.store(CharMappingFile.this, newFile); + } finally { + newFile.delete(); + } + } else { + newFile.delete(); + } + } + } + +} diff --git a/src/main/java/org/codelibs/fess/dict/mapping/CharMappingItem.java b/src/main/java/org/codelibs/fess/dict/mapping/CharMappingItem.java new file mode 100644 index 000000000..616c8ee07 --- /dev/null +++ b/src/main/java/org/codelibs/fess/dict/mapping/CharMappingItem.java @@ -0,0 +1,140 @@ +/* + * Copyright 2012-2016 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.mapping; + +import java.util.Arrays; + +import org.apache.commons.lang3.StringUtils; +import org.codelibs.core.lang.StringUtil; +import org.codelibs.fess.dict.DictionaryItem; + +public class CharMappingItem extends DictionaryItem { + private final String[] inputs; + + private final String output; + + private String[] newInputs; + + private String newOutput; + + public CharMappingItem(final long id, final String[] inputs, final String output) { + this.id = id; + this.inputs = inputs; + this.output = output; + Arrays.sort(inputs); + + if (id == 0) { + // create + newInputs = inputs; + newOutput = output; + } + } + + public String[] getNewInputs() { + return newInputs; + } + + public void setNewInputs(final String[] newInputs) { + this.newInputs = newInputs; + } + + public String getNewOutput() { + return newOutput; + } + + public void setNewOutput(final String newOutput) { + this.newOutput = newOutput; + } + + public String[] getInputs() { + return inputs; + } + + public String getInputsValue() { + if (inputs == null) { + return StringUtil.EMPTY; + } + return String.join("\n", inputs); + } + + public String getOutput() { + return output; + } + + public boolean isUpdated() { + return newInputs != null && newOutput != null; + } + + public boolean isDeleted() { + return isUpdated() && newInputs.length == 0; + } + + public void sort() { + if (inputs != null) { + Arrays.sort(inputs); + } + if (newInputs != null) { + Arrays.sort(newInputs); + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(inputs); + result = prime * result + (output == null ? 0 : output.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final CharMappingItem other = (CharMappingItem) obj; + sort(); + other.sort(); + if (!Arrays.equals(inputs, other.inputs)) { + return false; + } + if (!output.equals(other.getOutput())) { + return false; + } + return true; + } + + @Override + public String toString() { + return "MappingItem [id=" + id + ", inputs=" + Arrays.toString(inputs) + ", output=" + output + ", newInputs=" + + Arrays.toString(newInputs) + ", newOutput=" + newOutput + "]"; + } + + public String toLineString() { + if (isUpdated()) { + return StringUtils.join(newInputs, ",") + "=>" + newOutput; + } else { + return StringUtils.join(inputs, ",") + "=>" + output; + } + } + +} diff --git a/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsFile.java b/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsFile.java index c627e7d7d..a270cdb16 100644 --- a/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsFile.java +++ b/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsFile.java @@ -106,7 +106,7 @@ public class ProtwordsFile extends DictionaryFile { @Override public synchronized void delete(final ProtwordsItem item) { final ProtwordsItem ProtwordsItem = item; - ProtwordsItem.setNewInputs(StringUtil.EMPTY_STRINGS); + ProtwordsItem.setNewInput(StringUtil.EMPTY); try (SynonymUpdater updater = new SynonymUpdater(item)) { reload(updater, null); } @@ -126,15 +126,15 @@ public class ProtwordsFile extends DictionaryFile { continue; // ignore empty lines and comments } - final List inputStrings = split(line, ","); - final String[] inputs = new String[inputStrings.size()]; - for (int i = 0; i < inputs.length; i++) { - inputs[i] = unescape(inputStrings.get(i)).trim(); + final String inputStrings = line; + String input = null; + if (inputStrings != null) { + input = unescape(inputStrings); } - if (inputs.length > 0) { + if (input.length() > 0) { id++; - final ProtwordsItem item = new ProtwordsItem(id, inputs); + final ProtwordsItem item = new ProtwordsItem(id, input); if (updater != null) { final ProtwordsItem newItem = updater.write(item); if (newItem != null) { @@ -159,40 +159,6 @@ public class ProtwordsFile extends DictionaryFile { } } - private static List split(final String s, final String separator) { - final List list = new ArrayList<>(2); - StringBuilder sb = new StringBuilder(); - int pos = 0; - final int end = s.length(); - while (pos < end) { - if (s.startsWith(separator, pos)) { - if (sb.length() > 0) { - list.add(sb.toString()); - sb = new StringBuilder(); - } - pos += separator.length(); - continue; - } - - char ch = s.charAt(pos++); - if (ch == '\\') { - sb.append(ch); - if (pos >= end) { - break; // ERROR, or let it go? - } - ch = s.charAt(pos++); - } - - sb.append(ch); - } - - if (sb.length() > 0) { - list.add(sb.toString()); - } - - return list; - } - private String unescape(final String s) { if (s.indexOf('\\') >= 0) { final StringBuilder sb = new StringBuilder(); @@ -260,12 +226,12 @@ public class ProtwordsFile extends DictionaryFile { // update writer.write(item.toLineString()); writer.write(Constants.LINE_SEPARATOR); - return new ProtwordsItem(item.getId(), item.getNewInputs()); + return new ProtwordsItem(item.getId(), item.getNewInput()); } else { return null; } } finally { - item.setNewInputs(null); + item.setNewInput(null); } } else { throw new DictionaryException("Protwords file was updated: old=" + oldItem + " : new=" + item); diff --git a/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsItem.java b/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsItem.java index 49f2fe991..3c0c26bb3 100644 --- a/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsItem.java +++ b/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsItem.java @@ -15,59 +15,57 @@ */ package org.codelibs.fess.dict.protwords; -import java.util.Arrays; - import org.apache.commons.lang3.StringUtils; import org.codelibs.core.lang.StringUtil; import org.codelibs.fess.dict.DictionaryItem; public class ProtwordsItem extends DictionaryItem { - private final String[] inputs; + private final String input; - private String[] newInputs; + private String newInput; - public ProtwordsItem(final long id, final String[] inputs) { + public ProtwordsItem(final long id, final String input) { this.id = id; - this.inputs = inputs; + this.input = input; if (id == 0) { // create - newInputs = inputs; + newInput = input; } } - public String[] getNewInputs() { - return newInputs; + public String getNewInput() { + return newInput; } - public void setNewInputs(final String[] newInputs) { - this.newInputs = newInputs; + public void setNewInput(final String newInput) { + this.newInput = newInput; } - public String[] getInputs() { - return inputs; + public String getInput() { + return input; } - public String getInputsValue() { - if (inputs == null) { + public String getInputValue() { + if (input == null) { return StringUtil.EMPTY; } - return String.join(",", inputs); + return input; } public boolean isUpdated() { - return newInputs != null; + return newInput != null; } public boolean isDeleted() { - return isUpdated() && newInputs.length == 0; + return isUpdated() && newInput.length() == 0; } @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + Arrays.hashCode(inputs); + result = prime * result + input.hashCode(); return result; } @@ -83,7 +81,7 @@ public class ProtwordsItem extends DictionaryItem { return false; } final ProtwordsItem other = (ProtwordsItem) obj; - if (!Arrays.equals(inputs, other.inputs)) { + if (!input.equals(other.input)) { return false; } return true; @@ -91,14 +89,14 @@ public class ProtwordsItem extends DictionaryItem { @Override public String toString() { - return "ProtwordsItem [id=" + id + ", inputs=" + Arrays.toString(inputs) + ", newInputs=" + Arrays.toString(newInputs) + "]"; + return "ProtwordsItem [id=" + id + ", inputs=" + input + ", newInputs=" + newInput + "]"; } public String toLineString() { if (isUpdated()) { - return StringUtils.join(newInputs, ","); + return StringUtils.join(newInput); } else { - return StringUtils.join(inputs, ","); + return StringUtils.join(input); } } diff --git a/src/main/java/org/codelibs/fess/mylasta/action/FessHtmlPath.java b/src/main/java/org/codelibs/fess/mylasta/action/FessHtmlPath.java index aa5a706e6..2623c98d0 100644 --- a/src/main/java/org/codelibs/fess/mylasta/action/FessHtmlPath.java +++ b/src/main/java/org/codelibs/fess/mylasta/action/FessHtmlPath.java @@ -92,6 +92,21 @@ public interface FessHtmlPath { /** The path of the HTML: /admin/dict/kuromoji/admin_dict_kuromoji_upload.jsp */ HtmlNext path_AdminDictKuromoji_AdminDictKuromojiUploadJsp = new HtmlNext("/admin/dict/kuromoji/admin_dict_kuromoji_upload.jsp"); + /** The path of the HTML: /admin/dict/mapping/admin_dict_mapping.jsp */ + HtmlNext path_AdminDictMapping_AdminDictMappingJsp = new HtmlNext("/admin/dict/mapping/admin_dict_mapping.jsp"); + + /** The path of the HTML: /admin/dict/mapping/admin_dict_mapping_details.jsp */ + HtmlNext path_AdminDictMapping_AdminDictMappingDetailsJsp = new HtmlNext("/admin/dict/mapping/admin_dict_mapping_details.jsp"); + + /** The path of the HTML: /admin/dict/mapping/admin_dict_mapping_download.jsp */ + HtmlNext path_AdminDictMapping_AdminDictMappingDownloadJsp = new HtmlNext("/admin/dict/mapping/admin_dict_mapping_download.jsp"); + + /** The path of the HTML: /admin/dict/mapping/admin_dict_mapping_edit.jsp */ + HtmlNext path_AdminDictMapping_AdminDictMappingEditJsp = new HtmlNext("/admin/dict/mapping/admin_dict_mapping_edit.jsp"); + + /** The path of the HTML: /admin/dict/mapping/admin_dict_mapping_upload.jsp */ + HtmlNext path_AdminDictMapping_AdminDictMappingUploadJsp = new HtmlNext("/admin/dict/mapping/admin_dict_mapping_upload.jsp"); + /** The path of the HTML: /admin/dict/protwords/admin_dict_protwords.jsp */ HtmlNext path_AdminDictProtwords_AdminDictProtwordsJsp = new HtmlNext("/admin/dict/protwords/admin_dict_protwords.jsp"); diff --git a/src/main/java/org/codelibs/fess/mylasta/action/FessLabels.java b/src/main/java/org/codelibs/fess/mylasta/action/FessLabels.java index d063a6398..cb3e35347 100644 --- a/src/main/java/org/codelibs/fess/mylasta/action/FessLabels.java +++ b/src/main/java/org/codelibs/fess/mylasta/action/FessLabels.java @@ -365,6 +365,9 @@ public class FessLabels extends ActionMessages { /** The key of the message: Bad Word File */ public static final String LABELS_BAD_WORD_FILE = "{labels.badWordFile}"; + /** The key of the message: Mapping File */ + public static final String LABELS_MAPPING_FILE = "{labels.mappingFile}"; + /** The key of the message: Boost Expr */ public static final String LABELS_BOOST_EXPR = "{labels.boostExpr}"; @@ -1764,6 +1767,48 @@ public class FessLabels extends ActionMessages { /** The key of the message: Synonym File */ public static final String LABELS_dict_synonym_file = "{labels.dict_synonym_file}"; + /** The key of the message: Mapping List */ + public static final String LABELS_dict_mapping_configuration = "{labels.dict_mapping_configuration}"; + + /** The key of the message: Mapping List */ + public static final String LABELS_dict_mapping_title = "{labels.dict_mapping_title}"; + + /** The key of the message: List */ + public static final String LABELS_dict_mapping_list_link = "{labels.dict_mapping_list_link}"; + + /** The key of the message: Create New */ + public static final String LABELS_dict_mapping_link_create = "{labels.dict_mapping_link_create}"; + + /** The key of the message: Edit */ + public static final String LABELS_dict_mapping_link_edit = "{labels.dict_mapping_link_edit}"; + + /** The key of the message: Delete */ + public static final String LABELS_dict_mapping_link_delete = "{labels.dict_mapping_link_delete}"; + + /** The key of the message: Details */ + public static final String LABELS_dict_mapping_link_details = "{labels.dict_mapping_link_details}"; + + /** The key of the message: Download */ + public static final String LABELS_dict_mapping_link_download = "{labels.dict_mapping_link_download}"; + + /** The key of the message: Upload */ + public static final String LABELS_dict_mapping_link_upload = "{labels.dict_mapping_link_upload}"; + + /** The key of the message: Source */ + public static final String LABELS_dict_mapping_source = "{labels.dict_mapping_source}"; + + /** The key of the message: Target */ + public static final String LABELS_dict_mapping_target = "{labels.dict_mapping_target}"; + + /** The key of the message: Download */ + public static final String LABELS_dict_mapping_button_download = "{labels.dict_mapping_button_download}"; + + /** The key of the message: Upload */ + public static final String LABELS_dict_mapping_button_upload = "{labels.dict_mapping_button_upload}"; + + /** The key of the message: Mapping File */ + public static final String LABELS_dict_mapping_file = "{labels.dict_mapping_file}"; + /** The key of the message: Seunjeon List */ public static final String LABELS_dict_seunjeon_configuration = "{labels.dict_seunjeon_configuration}"; diff --git a/src/main/java/org/codelibs/fess/mylasta/action/FessMessages.java b/src/main/java/org/codelibs/fess/mylasta/action/FessMessages.java index 9251f73c8..03e3b7688 100644 --- a/src/main/java/org/codelibs/fess/mylasta/action/FessMessages.java +++ b/src/main/java/org/codelibs/fess/mylasta/action/FessMessages.java @@ -260,6 +260,12 @@ public class FessMessages extends FessLabels { /** The key of the message: Failed to upload the Badword file. */ public static final String ERRORS_failed_to_upload_badword_file = "{errors.failed_to_upload_badword_file}"; + /** The key of the message: Failed to download the Mapping file. */ + public static final String ERRORS_failed_to_download_mapping_file = "{errors.failed_to_download_mapping_file}"; + + /** The key of the message: Failed to upload the Mapping file. */ + public static final String ERRORS_failed_to_upload_mapping_file = "{errors.failed_to_upload_mapping_file}"; + /** The key of the message: "{1}" in "{0}" is invalid. */ public static final String ERRORS_invalid_str_is_included = "{errors.invalid_str_is_included}"; @@ -377,6 +383,9 @@ public class FessMessages extends FessLabels { /** The key of the message: Uploaded Bad Word file. */ public static final String SUCCESS_upload_bad_word = "{success.upload_bad_word}"; + /** The key of the message: Uploaded Mapping file. */ + public static final String SUCCESS_upload_mapping_file = "{success.upload_mapping_file}"; + /** The key of the message: Sent the test mail. */ public static final String SUCCESS_send_testmail = "{success.send_testmail}"; @@ -1559,6 +1568,34 @@ public class FessMessages extends FessLabels { return this; } + /** + * Add the created action message for the key 'errors.failed_to_download_mapping_file' with parameters. + *
+     * message: Failed to download the Mapping file.
+     * 
+ * @param property The property name for the message. (NotNull) + * @return this. (NotNull) + */ + public FessMessages addErrorsFailedToDownloadMappingFile(String property) { + assertPropertyNotNull(property); + add(property, new ActionMessage(ERRORS_failed_to_download_mapping_file)); + return this; + } + + /** + * Add the created action message for the key 'errors.failed_to_upload_mapping_file' with parameters. + *
+     * message: Failed to upload the Mapping file.
+     * 
+ * @param property The property name for the message. (NotNull) + * @return this. (NotNull) + */ + public FessMessages addErrorsFailedToUploadMappingFile(String property) { + assertPropertyNotNull(property); + add(property, new ActionMessage(ERRORS_failed_to_upload_mapping_file)); + return this; + } + /** * Add the created action message for the key 'errors.invalid_str_is_included' with parameters. *
@@ -2126,6 +2163,20 @@ public class FessMessages extends FessLabels {
         return this;
     }
 
+    /**
+     * Add the created action message for the key 'success.upload_mapping_file' with parameters.
+     * 
+     * message: Uploaded Mapping file.
+     * 
+ * @param property The property name for the message. (NotNull) + * @return this. (NotNull) + */ + public FessMessages addSuccessUploadMappingFile(String property) { + assertPropertyNotNull(property); + add(property, new ActionMessage(SUCCESS_upload_mapping_file)); + return this; + } + /** * Add the created action message for the key 'success.send_testmail' with parameters. *
diff --git a/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java b/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java
index d950bd20b..b69680526 100644
--- a/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java
+++ b/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java
@@ -622,6 +622,9 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
     /** The key of the configuration. e.g. protwords */
     String ONLINE_HELP_NAME_DICT_PROTWORDS = "online.help.name.dict.protwords";
 
+    /** The key of the configuration. e.g. mapping */
+    String ONLINE_HELP_NAME_DICT_MAPPING = "online.help.name.dict.mapping";
+
     /** The key of the configuration. e.g. webconfig */
     String ONLINE_HELP_NAME_WEBCONFIG = "online.help.name.webconfig";
 
@@ -2869,6 +2872,13 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
      */
     String getOnlineHelpNameDictProtwords();
 
+    /**
+     * Get the value for the key 'online.help.name.dict.mapping'. 
+ * The value is, e.g. mapping
+ * @return The value of found property. (NotNull: if not found, exception but basically no way) + */ + String getOnlineHelpNameDictMapping(); + /** * Get the value for the key 'online.help.name.webconfig'.
* The value is, e.g. webconfig
@@ -4717,6 +4727,10 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction return get(FessConfig.ONLINE_HELP_NAME_DICT_PROTWORDS); } + public String getOnlineHelpNameDictMapping() { + return get(FessConfig.ONLINE_HELP_NAME_DICT_MAPPING); + } + public String getOnlineHelpNameWebconfig() { return get(FessConfig.ONLINE_HELP_NAME_WEBCONFIG); } diff --git a/src/main/resources/fess_config.properties b/src/main/resources/fess_config.properties index 2bc6b71f0..eaf092e29 100644 --- a/src/main/resources/fess_config.properties +++ b/src/main/resources/fess_config.properties @@ -349,6 +349,7 @@ online.help.name.dict=dict online.help.name.dict.kuromoji=kuromoji online.help.name.dict.seunjeon=seunjeon online.help.name.dict.protwords=protwords +online.help.name.dict.mapping=mapping online.help.name.webconfig=webconfig online.help.name.searchlist=searchlist online.help.name.log=log diff --git a/src/main/resources/fess_dict.xml b/src/main/resources/fess_dict.xml index 5d18b9b08..b0cbc7b99 100644 --- a/src/main/resources/fess_dict.xml +++ b/src/main/resources/fess_dict.xml @@ -2,7 +2,7 @@ - + @@ -17,6 +17,9 @@ protwordsCreator + + charMappingCreator + + + diff --git a/src/main/resources/fess_indices/fess.json b/src/main/resources/fess_indices/fess.json index 0bdf1e2f3..51e91accb 100644 --- a/src/main/resources/fess_indices/fess.json +++ b/src/main/resources/fess_indices/fess.json @@ -50,7 +50,6 @@ "記号-空白", "記号-読点", "形容詞", - "形容詞-自立", "形容詞-接尾", "形容詞-非自立", "語断片", @@ -76,15 +75,8 @@ "接頭詞-数接続", "接頭詞-動詞接続", "接頭詞-名詞接続", - "動詞", - "動詞-自立", "動詞-接尾", - "動詞-非自立", "非言語音", - "副詞", - "副詞-一般", - "副詞-助詞類接続", - "未知語", "連体詞" ] }, @@ -455,20 +447,6 @@ "lowercase" ] }, - "japanese_search_analyzer": { - "type": "custom", - "char_filter": [ - "mapping_ja_filter", - "kuromoji_neologd_iteration_mark" - ], - "tokenizer": "kuromoji_neologd_tokenizer", - "filter": [ - "truncate10_filter", - "kuromoji_neologd_baseform", - "kuromoji_neologd_stemmer", - "lowercase" - ] - }, "english_analyzer": { "type": "custom", "tokenizer": "standard", diff --git a/src/main/resources/fess_indices/fess/doc.json b/src/main/resources/fess_indices/fess/doc.json index 77aa1290d..76c48c4a9 100644 --- a/src/main/resources/fess_indices/fess/doc.json +++ b/src/main/resources/fess_indices/fess/doc.json @@ -201,8 +201,7 @@ "match": "*_ja", "mapping": { "type": "string", - "analyzer": "japanese_analyzer", - "search_analyzer": "japanese_search_analyzer" + "analyzer": "japanese_analyzer" } } }, diff --git a/src/main/resources/fess_label.properties b/src/main/resources/fess_label.properties index dcb48d672..ed95dddd8 100644 --- a/src/main/resources/fess_label.properties +++ b/src/main/resources/fess_label.properties @@ -111,6 +111,7 @@ labels.token=Token labels.synonymFile=Synonym File labels.elevateWordFile=Additional Word File labels.badWordFile=Bad Word File +labels.mappingFile=Mapping File labels.boostExpr=Boost Expr labels.confirmPassword=Confirm labels.crawler=Crawler @@ -578,6 +579,20 @@ labels.dict_synonym_target=Target labels.dict_synonym_button_download=Download labels.dict_synonym_button_upload=Upload labels.dict_synonym_file=Synonym File +labels.dict_mapping_configuration=Mapping List +labels.dict_mapping_title=Mapping List +labels.dict_mapping_list_link=List +labels.dict_mapping_link_create=Create New +labels.dict_mapping_link_edit=Edit +labels.dict_mapping_link_delete=Delete +labels.dict_mapping_link_details=Details +labels.dict_mapping_link_download=Download +labels.dict_mapping_link_upload=Upload +labels.dict_mapping_source=Source +labels.dict_mapping_target=Target +labels.dict_mapping_button_download=Download +labels.dict_mapping_button_upload=Upload +labels.dict_mapping_file=Mapping File labels.dict_seunjeon_configuration = Seunjeon List labels.dict_seunjeon_title = Seunjeon List labels.dict_seunjeon_list_link = List diff --git a/src/main/resources/fess_label_en.properties b/src/main/resources/fess_label_en.properties index 433fa10a2..dbb13e507 100644 --- a/src/main/resources/fess_label_en.properties +++ b/src/main/resources/fess_label_en.properties @@ -111,6 +111,7 @@ labels.token=Token labels.synonymFile=Synonym File labels.elevateWordFile=Additional Word File labels.badWordFile=Bad Word File +labels.mappingFile=Mapping File labels.boostExpr=Boost Expr labels.confirmPassword=Confirm labels.crawler=Crawler @@ -578,6 +579,20 @@ labels.dict_synonym_target=Target labels.dict_synonym_button_download=Download labels.dict_synonym_button_upload=Upload labels.dict_synonym_file=Synonym File +labels.dict_mapping_configuration=Mapping List +labels.dict_mapping_title=Mapping List +labels.dict_mapping_list_link=List +labels.dict_mapping_link_create=Create New +labels.dict_mapping_link_edit=Edit +labels.dict_mapping_link_delete=Delete +labels.dict_mapping_link_details=Details +labels.dict_mapping_link_download=Download +labels.dict_mapping_link_upload=Upload +labels.dict_mapping_source=Source +labels.dict_mapping_target=Target +labels.dict_mapping_button_download=Download +labels.dict_mapping_button_upload=Upload +labels.dict_mapping_file=Mapping File labels.dict_seunjeon_configuration = Seunjeon List labels.dict_seunjeon_title = Seunjeon List labels.dict_seunjeon_list_link = List diff --git a/src/main/resources/fess_label_ja.properties b/src/main/resources/fess_label_ja.properties index 2b4482620..63f8474a5 100644 --- a/src/main/resources/fess_label_ja.properties +++ b/src/main/resources/fess_label_ja.properties @@ -111,6 +111,7 @@ labels.token=\u30c8\u30fc\u30af\u30f3 labels.synonymFile=\u540c\u7fa9\u8a9e\u30d5\u30a1\u30a4\u30eb labels.elevateWordFile=\u8ffd\u52a0\u30ef\u30fc\u30c9\u30d5\u30a1\u30a4\u30eb labels.badWordFile=\u9664\u5916\u30ef\u30fc\u30c9\u30d5\u30a1\u30a4\u30eb +labels.mappingFile=\u30de\u30c3\u30d4\u30f3\u30b0\u30d5\u30a1\u30a4\u30eb labels.boostExpr=\u30d6\u30fc\u30b9\u30c8\u5024\u5f0f labels.confirmPassword=\u78ba\u8a8d labels.crawler=\u30af\u30ed\u30fc\u30e9 @@ -574,6 +575,22 @@ labels.dict_synonym_target=\u5909\u63db\u5f8c labels.dict_synonym_button_download=\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9 labels.dict_synonym_button_upload=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 labels.dict_synonym_file=\u540c\u7fa9\u8a9e\u30d5\u30a1\u30a4\u30eb + +labels.dict_mapping_configuration=\u30de\u30c3\u30d4\u30f3\u30b0\u8f9e\u66f8 +labels.dict_mapping_title=\u30de\u30c3\u30d4\u30f3\u30b0\u8f9e\u66f8 +labels.dict_mapping_list_link=\u4e00\u89a7 +labels.dict_mapping_link_create=\u65b0\u898f\u4f5c\u6210 +labels.dict_mapping_link_edit=\u7de8\u96c6 +labels.dict_mapping_link_delete=\u524a\u9664 +labels.dict_mapping_link_details=\u8a73\u7d30 +labels.dict_mapping_link_download=\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9 +labels.dict_mapping_link_upload=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 +labels.dict_mapping_source=\u5909\u63db\u5143 +labels.dict_mapping_target=\u5909\u63db\u5f8c +labels.dict_mapping_button_download=\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9 +labels.dict_mapping_button_upload=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 +labels.dict_mapping_file=\u30de\u30c3\u30d4\u30f3\u30b0\u30d5\u30a1\u30a4\u30eb + labels.dict_seunjeon_configuration = Seunjeon\u5358\u8a9e\u4e00\u89a7 labels.dict_seunjeon_title = Seunjeon\u5358\u8a9e\u4e00\u89a7 labels.dict_seunjeon_list_link = \u4e00\u89a7 diff --git a/src/main/resources/fess_label_ko.properties b/src/main/resources/fess_label_ko.properties index dbbb185a6..d0439b211 100644 --- a/src/main/resources/fess_label_ko.properties +++ b/src/main/resources/fess_label_ko.properties @@ -109,6 +109,7 @@ labels.token = \ud1a0\ud070 labels.synonymFile = \ub3d9\uc758\uc5b4 \ud30c\uc77c labels.elevateWordFile = \ucd94\uac00 \uc6cc\ub4dc \ud30c\uc77c labels.badWordFile = \uc81c\uc678 \uc6cc\ub4dc \ud30c\uc77c +labels.mappingFile = Mapping \ud30c\uc77c labels.boostExpr = \ubd80\uc2a4\ud2b8 \uac12 \uc2dd labels.confirmPassword = \ud655\uc778 labels.crawler = \ud06c\ub864\ub7ec @@ -569,6 +570,20 @@ labels.dict_synonym_target = \ubcc0\ud658 \ud6c4 labels.dict_synonym_button_download = \ub2e4\uc6b4\ub85c\ub4dc labels.dict_synonym_button_upload = \uc5c5\ub85c\ub4dc labels.dict_synonym_file = \ub3d9\uc758\uc5b4 \ud30c\uc77c +labels.dict_mapping_configuration=Mapping \ubaa9\ub85d +labels.dict_mapping_title=Mapping \ubaa9\ub85d +labels.dict_mapping_list_link=\ubaa9\ub85d +labels.dict_mapping_link_create=\uc0c8\ub85c \ub9cc\ub4e4\uae30 +labels.dict_mapping_link_edit=\ud3b8\uc9d1 +labels.dict_mapping_link_delete=\uc0ad\uc81c +labels.dict_mapping_link_details=\uc0c1\uc138 +labels.dict_mapping_link_download=\ub2e4\uc6b4\ub85c\ub4dc +labels.dict_mapping_link_upload=\uc5c5\ub85c\ub4dc +labels.dict_mapping_source=\uc6d0\ubcf8 +labels.dict_mapping_target=\ubcc0\ud658 \ud6c4 +labels.dict_mapping_button_download=\ub2e4\uc6b4\ub85c\ub4dc +labels.dict_mapping_button_upload=\uc5c5\ub85c\ub4dc +labels.dict_mapping_file=Mapping \ud30c\uc77c labels.dict_seunjeon_configuration = Seunjeon \ubaa9\ub85d labels.dict_seunjeon_title = Seunjeon \ubaa9\ub85d labels.dict_seunjeon_list_link = \ubaa9\ub85d diff --git a/src/main/resources/fess_message.properties b/src/main/resources/fess_message.properties index 5adf521a9..e54cc3736 100644 --- a/src/main/resources/fess_message.properties +++ b/src/main/resources/fess_message.properties @@ -108,6 +108,8 @@ errors.failed_to_download_elevate_file=Failed to download the Elevate file. errors.failed_to_upload_elevate_file=Failed to upload the Elevate file. errors.failed_to_download_badword_file=Failed to download the Badword file. errors.failed_to_upload_badword_file=Failed to upload the Badword file. +errors.failed_to_download_mapping_file=Failed to download the Mapping file. +errors.failed_to_upload_mapping_file=Failed to upload the Mapping file. errors.invalid_str_is_included="{1}" in "{0}" is invalid. errors.blank_password=Password is required. errors.invalid_confirm_password=Confirm Password does not match. @@ -150,6 +152,7 @@ success.upload_synonym_file=Uploaded Synonym file. success.upload_kuromoji_file=Uploaded Kuromoji file. success.upload_elevate_word=Uploaded Additional Word file. success.upload_bad_word=Uploaded Bad Word file. +success.upload_mapping_file=Uploaded Mapping file. success.send_testmail=Sent the test mail. success.job_log_delete_all=Deleted job logs. success.changed_password=Changed your password. diff --git a/src/main/resources/fess_message_en.properties b/src/main/resources/fess_message_en.properties index fed189f0f..a01f33d10 100644 --- a/src/main/resources/fess_message_en.properties +++ b/src/main/resources/fess_message_en.properties @@ -108,6 +108,8 @@ errors.failed_to_download_badword_file=Failed to download the Badword file. errors.failed_to_upload_badword_file=Failed to upload the Badword file. errors.failed_to_download_protwords_file=Failed to download the Protwords file. errors.failed_to_upload_protwords_file=Failed to upload the Protwords file. +errors.failed_to_download_mapping_file=Failed to download the Mapping file. +errors.failed_to_upload_mapping_file=Failed to upload the Mapping file. errors.invalid_str_is_included="{1}" in "{0}" is invalid. errors.blank_password=Password is required. errors.invalid_confirm_password=Confirm Password does not match. @@ -150,6 +152,7 @@ success.upload_synonym_file=Uploaded Synonym file. success.upload_kuromoji_file=Uploaded Kuromoji file. success.upload_elevate_word=Uploaded Additional Word file. success.upload_bad_word=Uploaded Bad Word file. +success.upload_mapping_file=Uploaded Mapping file. success.send_testmail=Sent the test mail. success.job_log_delete_all=Deleted job logs. success.changed_password=Changed your password. diff --git a/src/main/resources/fess_message_ja.properties b/src/main/resources/fess_message_ja.properties index 1d0fb42e7..c624da16e 100644 --- a/src/main/resources/fess_message_ja.properties +++ b/src/main/resources/fess_message_ja.properties @@ -104,6 +104,8 @@ errors.failed_to_download_elevate_file = \u8ffd\u52a0\u30ef\u30fc\u30c9\u30d5\u3 errors.failed_to_upload_elevate_file = \u8ffd\u52a0\u30ef\u30fc\u30c9\u30d5\u30a1\u30a4\u30eb\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 errors.failed_to_download_badword_file = \u9664\u5916\u30ef\u30fc\u30c9\u30d5\u30a1\u30a4\u30eb\u306e\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 errors.failed_to_upload_badword_file = \u9664\u5916\u30ef\u30fc\u30c9\u30d5\u30a1\u30a4\u30eb\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 +errors.failed_to_download_mapping_file = \u30de\u30c3\u30d4\u30f3\u30b0\u30d5\u30a1\u30a4\u30eb\u306e\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +errors.failed_to_upload_mapping_file = \u30de\u30c3\u30d4\u30f3\u30b0\u30d5\u30a1\u30a4\u30eb\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 errors.invalid_str_is_included = {0}\u3067\u306f{1}\u306f\u7121\u52b9\u3067\u3059\u3002 errors.blank_password = \u30d1\u30b9\u30ef\u30fc\u30c9\u304c\u5fc5\u8981\u306b\u306a\u308a\u307e\u3059\u3002 errors.invalid_confirm_password = \u30d1\u30b9\u30ef\u30fc\u30c9\u306e\u78ba\u8a8d\u3068\u4e00\u81f4\u3057\u307e\u305b\u3093\u3002 @@ -144,6 +146,7 @@ success.upload_synonym_file = \u540c\u7fa9\u8a9e\u30d5\u30a1\u30a4\u30eb\u3092\u success.upload_kuromoji_file = Kuromoji\u30d5\u30a1\u30a4\u30eb\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3057\u307e\u3057\u305f\u3002 success.upload_elevate_word = \u8ffd\u52a0\u30ef\u30fc\u30c9\u30d5\u30a1\u30a4\u30eb\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3057\u307e\u3057\u305f\u3002 success.upload_bad_word = \u9664\u5916\u30ef\u30fc\u30c9\u30d5\u30a1\u30a4\u30eb\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3057\u307e\u3057\u305f\u3002 +success.upload_mapping_file = \u30de\u30c3\u30d4\u30f3\u30b0\u30d5\u30a1\u30a4\u30eb\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3057\u307e\u3057\u305f\u3002 success.send_testmail=\u30c6\u30b9\u30c8\u30e1\u30fc\u30eb\u3092\u9001\u4fe1\u3057\u307e\u3057\u305f\u3002 success.job_log_delete_all=\u30b8\u30e7\u30d6\u30ed\u30b0\u3092\u524a\u9664\u3057\u307e\u3057\u305f\u3002 success.changed_password=\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u5909\u66f4\u3057\u307e\u3057\u305f\u3002 diff --git a/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping.jsp b/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping.jsp new file mode 100644 index 000000000..b871bcc07 --- /dev/null +++ b/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping.jsp @@ -0,0 +1,156 @@ +<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> + + + +<la:message key="labels.admin_brand_title" /> | <la:message + key="labels.dict_mapping_configuration" /> + + + +
+ + + + + +
+
+

+ +

+ +
+
+
+
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + +
+
+ +
+ <%-- Message --%> +
+ +
${msg}
+
+ +
+ <%-- List --%> + +
+
+ + +
+
+
+ +
+
+ + + + + + + + + + + + + + + +
${f:h(data.inputs)}${f:h(data.output)}
+
+
+ +
+
+ +
+
+
    + + + + + + + +
  • class="active">${p}
  • +
    + + + + + + +
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + + diff --git a/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping_details.jsp b/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping_details.jsp new file mode 100644 index 000000000..7b4b78a08 --- /dev/null +++ b/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping_details.jsp @@ -0,0 +1,127 @@ +<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> + + + +<la:message key="labels.admin_brand_title" /> | <la:message + key="labels.dict_mapping_configuration" /> + + + +
+ + + + + +
+
+

+ +

+ +
+
+ + + + + + +
+
+
box-successbox-warningbox-dangerbox-primary"> + <%-- Box Header --%> +
+

+ + + + + + + + + + + + +

+
+ + + + + + + + + + + + + + + + + + + + +
+
+ <%-- Box Body --%> +
+ <%-- Message --%> +
+ +
${msg}
+
+ +
+ <%-- Form Fields --%> + + + + + + + + + + + +
${f:br(f:h(inputs))}
${f:br(f:h(output))}
+
+ + + +
+ +
+
+
+
+
+ +
+ + + diff --git a/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping_download.jsp b/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping_download.jsp new file mode 100644 index 000000000..eeffe31b2 --- /dev/null +++ b/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping_download.jsp @@ -0,0 +1,103 @@ +<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> + + + +<la:message key="labels.admin_brand_title" /> | <la:message + key="labels.dict_mapping_configuration" /> + + + +
+ + + + + +
+
+

+ +

+ +
+
+ + +
+
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + +
+
+ +
+ <%-- Message --%> +
+ +
${msg}
+
+ +
+
+ +
+
+ + + +
+ +
+
+
+
+
+ +
+ + + diff --git a/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping_edit.jsp b/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping_edit.jsp new file mode 100644 index 000000000..c0c1c639e --- /dev/null +++ b/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping_edit.jsp @@ -0,0 +1,129 @@ +<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> + + + +<la:message key="labels.admin_brand_title" /> | <la:message + key="labels.dict_mapping_configuration" /> + + + +
+ + + + + +
+
+

+ +

+ +
+
+ + + + + + +
+
+
box-successbox-warning"> +
+

+ + + + + + +

+
+ + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
${msg}
+
+ +
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ + + +
+ +
+
+
+
+
+ +
+ + + diff --git a/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping_upload.jsp b/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping_upload.jsp new file mode 100644 index 000000000..521caa0c4 --- /dev/null +++ b/src/main/webapp/WEB-INF/view/admin/dict/mapping/admin_dict_mapping_upload.jsp @@ -0,0 +1,107 @@ +<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> + + + +<la:message key="labels.admin_brand_title" /> | <la:message + key="labels.dict_mapping_configuration" /> + + + +
+ + + + + +
+
+

+ +

+ +
+
+ + +
+
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + +
+
+ +
+ <%-- Message --%> +
+ +
${msg}
+
+ +
+
+ +
+ +
+
+
+ + + +
+ +
+
+
+
+
+ +
+ + + diff --git a/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords.jsp b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords.jsp index a993ceaee..545fa8a77 100644 --- a/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords.jsp +++ b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords.jsp @@ -92,7 +92,7 @@ items="${protwordsItemItems}"> - ${f:h(data.inputsValue)} + ${f:h(data.inputValue)} diff --git a/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_details.jsp b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_details.jsp index 06c941008..6e9d7ad21 100644 --- a/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_details.jsp +++ b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_details.jsp @@ -99,7 +99,7 @@ - ${f:h(inputs)} + ${f:h(input)} diff --git a/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_edit.jsp b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_edit.jsp index 643eab532..211b2507a 100644 --- a/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_edit.jsp +++ b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_edit.jsp @@ -95,8 +95,8 @@
- - +
diff --git a/src/main/webapp/css/style.css b/src/main/webapp/css/style.css index 2743c8f80..0f434c205 100644 --- a/src/main/webapp/css/style.css +++ b/src/main/webapp/css/style.css @@ -202,7 +202,7 @@ ul.searchOptionLabels li { vertical-align: middle; } -#searchOptions { +body.search #searchOptions, body.help #searchOptions, body.error #searchOptions { position: fixed; top: 0; padding-top: 72px; @@ -214,7 +214,7 @@ ul.searchOptionLabels li { transition: all .4s ease 0s; } -#searchOptions.active { +body.search #searchOptions.active, body.help #searchOptions.active, body.error #searchOptions.active { right: 0; }