View Javadoc
1   /*
2    * Copyright 2012-2017 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.app.web.admin.dict.synonym;
17  
18  import java.io.File;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  import javax.annotation.Resource;
25  
26  import org.codelibs.core.beans.util.BeanUtil;
27  import org.codelibs.core.lang.StringUtil;
28  import org.codelibs.fess.Constants;
29  import org.codelibs.fess.app.pager.SynonymPager;
30  import org.codelibs.fess.app.service.SynonymService;
31  import org.codelibs.fess.app.web.CrudMode;
32  import org.codelibs.fess.app.web.admin.dict.AdminDictAction;
33  import org.codelibs.fess.app.web.base.FessAdminAction;
34  import org.codelibs.fess.dict.synonym.SynonymItem;
35  import org.codelibs.fess.util.ComponentUtil;
36  import org.codelibs.fess.util.RenderDataUtil;
37  import org.dbflute.optional.OptionalEntity;
38  import org.dbflute.optional.OptionalThing;
39  import org.lastaflute.web.Execute;
40  import org.lastaflute.web.response.ActionResponse;
41  import org.lastaflute.web.response.HtmlResponse;
42  import org.lastaflute.web.response.render.RenderData;
43  import org.lastaflute.web.ruts.process.ActionRuntime;
44  import org.lastaflute.web.validation.VaErrorHook;
45  
46  /**
47   * @author shinsuke
48   * @author Keiichi Watanabe
49   */
50  public class AdminDictSynonymAction extends FessAdminAction {
51  
52      // ===================================================================================
53      //                                                                           Attribute
54      //                                                                           =========
55      @Resource
56      private SynonymService synonymService;
57      @Resource
58      private SynonymPager synonymPager;
59  
60      // ===================================================================================
61      //                                                                               Hook
62      //                                                                              ======
63      @Override
64      protected void setupHtmlData(final ActionRuntime runtime) {
65          super.setupHtmlData(runtime);
66          runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNameDictSynonym()));
67      }
68  
69      // ===================================================================================
70      //                                                                      Search Execute
71      //                                                                      ==============
72      @Execute
73      public HtmlResponse index(final SearchForm form) {
74          validate(form, messages -> {}, () -> asDictIndexHtml());
75          return asHtml(path_AdminDictSynonym_AdminDictSynonymJsp).renderWith(data -> {
76              searchPaging(data, form);
77          });
78      }
79  
80      @Execute
81      public HtmlResponse list(final OptionalThing<Integer> pageNumber, final SearchForm form) {
82          validate(form, messages -> {}, () -> asDictIndexHtml());
83          pageNumber.ifPresent(num -> {
84              synonymPager.setCurrentPageNumber(pageNumber.get());
85          }).orElse(() -> {
86              synonymPager.setCurrentPageNumber(0);
87          });
88          return asHtml(path_AdminDictSynonym_AdminDictSynonymJsp).renderWith(data -> {
89              searchPaging(data, form);
90          });
91      }
92  
93      @Execute
94      public HtmlResponse search(final SearchForm form) {
95          validate(form, messages -> {}, () -> asDictIndexHtml());
96          copyBeanToBean(form, synonymPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
97          return asHtml(path_AdminDictSynonym_AdminDictSynonymJsp).renderWith(data -> {
98              searchPaging(data, form);
99          });
100     }
101 
102     @Execute
103     public HtmlResponse reset(final SearchForm form) {
104         validate(form, messages -> {}, () -> asDictIndexHtml());
105         synonymPager.clear();
106         return asHtml(path_AdminDictSynonym_AdminDictSynonymJsp).renderWith(data -> {
107             searchPaging(data, form);
108         });
109     }
110 
111     protected void searchPaging(final RenderData data, final SearchForm form) {
112         // page navi
113         RenderDataUtil.register(data, "synonymItemItems", synonymService.getSynonymList(form.dictId, synonymPager));
114 
115         // restore from pager
116         BeanUtil.copyBeanToBean(synonymPager, form, op -> {
117             op.exclude(Constants.PAGER_CONVERSION_RULE);
118         });
119     }
120 
121     // ===================================================================================
122     //                                                                        Edit Execute
123     //                                                                        ============
124     // -----------------------------------------------------
125     //                                            Entry Page
126     //                                            ----------
127     @Execute
128     public HtmlResponse createnew(final String dictId) {
129         saveToken();
130         return asHtml(path_AdminDictSynonym_AdminDictSynonymEditJsp).useForm(CreateForm.class, op -> {
131             op.setup(form -> {
132                 form.initialize();
133                 form.crudMode = CrudMode.CREATE;
134                 form.dictId = dictId;
135             });
136         });
137     }
138 
139     @Execute
140     public HtmlResponse edit(final EditForm form) {
141         validate(form, messages -> {}, () -> asListHtml(form.dictId));
142         synonymService
143                 .getSynonymItem(form.dictId, form.id)
144                 .ifPresent(entity -> {
145                     form.inputs = entity.getInputsValue();
146                     form.outputs = entity.getOutputsValue();
147                 })
148                 .orElse(() -> {
149                     throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()),
150                             () -> asListHtml(form.dictId));
151                 });
152         saveToken();
153         if (form.crudMode.intValue() == CrudMode.EDIT) {
154             // back
155             form.crudMode = CrudMode.DETAILS;
156             return asDetailsHtml();
157         } else {
158             form.crudMode = CrudMode.EDIT;
159             return asEditHtml();
160         }
161     }
162 
163     // -----------------------------------------------------
164     //                                               Details
165     //                                               -------
166     @Execute
167     public HtmlResponse details(final String dictId, final int crudMode, final long id) {
168         verifyCrudMode(crudMode, CrudMode.DETAILS, dictId);
169         saveToken();
170         return asDetailsHtml().useForm(
171                 EditForm.class,
172                 op -> {
173                     op.setup(form -> {
174                         synonymService
175                                 .getSynonymItem(dictId, id)
176                                 .ifPresent(entity -> {
177                                     form.inputs = entity.getInputsValue();
178                                     form.outputs = entity.getOutputsValue();
179                                 })
180                                 .orElse(() -> {
181                                     throwValidationError(
182                                             messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, dictId + ":" + id),
183                                             () -> asListHtml(dictId));
184                                 });
185                         form.id = id;
186                         form.crudMode = crudMode;
187                         form.dictId = dictId;
188                     });
189                 });
190     }
191 
192     // -----------------------------------------------------
193     //                                              Download
194     //                                               -------
195     @Execute
196     public HtmlResponse downloadpage(final String dictId) {
197         saveToken();
198         return asHtml(path_AdminDictSynonym_AdminDictSynonymDownloadJsp).useForm(DownloadForm.class, op -> {
199             op.setup(form -> {
200                 form.dictId = dictId;
201             });
202         }).renderWith(data -> {
203             synonymService.getSynonymFile(dictId).ifPresent(file -> {
204                 RenderDataUtil.register(data, "path", file.getPath());
205             }).orElse(() -> {
206                 throwValidationError(messages -> messages.addErrorsFailedToDownloadSynonymFile(GLOBAL), () -> asDictIndexHtml());
207             });
208         });
209     }
210 
211     @Execute
212     public ActionResponse download(final DownloadForm form) {
213         validate(form, messages -> {}, () -> downloadpage(form.dictId));
214         verifyTokenKeep(() -> downloadpage(form.dictId));
215         return synonymService.getSynonymFile(form.dictId).map(file -> {
216             return asStream(new File(file.getPath()).getName()).contentTypeOctetStream().stream(out -> {
217                 try (InputStream inputStream = file.getInputStream()) {
218                     out.write(inputStream);
219                 }
220             });
221         }).orElseGet(() -> {
222             throwValidationError(messages -> messages.addErrorsFailedToDownloadSynonymFile(GLOBAL), () -> downloadpage(form.dictId));
223             return null;
224         });
225     }
226 
227     // -----------------------------------------------------
228     //                                                Upload
229     //                                               -------
230     @Execute
231     public HtmlResponse uploadpage(final String dictId) {
232         saveToken();
233         return asHtml(path_AdminDictSynonym_AdminDictSynonymUploadJsp).useForm(UploadForm.class, op -> {
234             op.setup(form -> {
235                 form.dictId = dictId;
236             });
237         }).renderWith(data -> {
238             synonymService.getSynonymFile(dictId).ifPresent(file -> {
239                 RenderDataUtil.register(data, "path", file.getPath());
240             }).orElse(() -> {
241                 throwValidationError(messages -> messages.addErrorsFailedToDownloadSynonymFile(GLOBAL), () -> asDictIndexHtml());
242             });
243         });
244     }
245 
246     @Execute
247     public HtmlResponse upload(final UploadForm form) {
248         validate(form, messages -> {}, () -> uploadpage(form.dictId));
249         verifyToken(() -> uploadpage(form.dictId));
250         return synonymService.getSynonymFile(form.dictId).map(file -> {
251             try (InputStream inputStream = form.synonymFile.getInputStream()) {
252                 file.update(inputStream);
253             } catch (final IOException e) {
254                 throwValidationError(messages -> messages.addErrorsFailedToUploadSynonymFile(GLOBAL), () -> {
255                     return redirectWith(getClass(), moreUrl("uploadpage/" + form.dictId));
256                 });
257             }
258             saveInfo(messages -> messages.addSuccessUploadSynonymFile(GLOBAL));
259             return redirectWith(getClass(), moreUrl("uploadpage/" + form.dictId));
260         }).orElseGet(() -> {
261             throwValidationError(messages -> messages.addErrorsFailedToUploadSynonymFile(GLOBAL), () -> uploadpage(form.dictId));
262             return null;
263         });
264 
265     }
266 
267     // -----------------------------------------------------
268     //                                         Actually Crud
269     //                                         -------------
270     @Execute
271     public HtmlResponse create(final CreateForm form) {
272         verifyCrudMode(form.crudMode, CrudMode.CREATE, form.dictId);
273         validate(form, messages -> {}, () -> asEditHtml());
274         verifyToken(() -> asEditHtml());
275         createSynonymItem(form, () -> asEditHtml()).ifPresent(
276                 entity -> {
277                     try {
278                         synonymService.store(form.dictId, entity);
279                         saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
280                     } catch (final Exception e) {
281                         throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)),
282                                 () -> asEditHtml());
283                     }
284                 }).orElse(() -> {
285             throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), () -> asEditHtml());
286         });
287         return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId));
288     }
289 
290     @Execute
291     public HtmlResponse update(final EditForm form) {
292         verifyCrudMode(form.crudMode, CrudMode.EDIT, form.dictId);
293         validate(form, messages -> {}, () -> asEditHtml());
294         verifyToken(() -> asEditHtml());
295         createSynonymItem(form, () -> asEditHtml()).ifPresent(
296                 entity -> {
297                     try {
298                         synonymService.store(form.dictId, entity);
299                         saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL));
300                     } catch (final Exception e) {
301                         throwValidationError(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)),
302                                 () -> asEditHtml());
303                     }
304                 }).orElse(() -> {
305             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()), () -> asEditHtml());
306         });
307         return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId));
308     }
309 
310     @Execute
311     public HtmlResponse delete(final EditForm form) {
312         verifyCrudMode(form.crudMode, CrudMode.DETAILS, form.dictId);
313         validate(form, messages -> {}, () -> asDetailsHtml());
314         verifyToken(() -> asDetailsHtml());
315         synonymService
316                 .getSynonymItem(form.dictId, form.id)
317                 .ifPresent(
318                         entity -> {
319                             try {
320                                 synonymService.delete(form.dictId, entity);
321                                 saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL));
322                             } catch (final Exception e) {
323                                 throwValidationError(
324                                         messages -> messages.addErrorsCrudFailedToDeleteCrudTable(GLOBAL, buildThrowableMessage(e)),
325                                         () -> asEditHtml());
326                             }
327                         })
328                 .orElse(() -> {
329                     throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()),
330                             () -> asDetailsHtml());
331                 });
332         return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId));
333     }
334 
335     //===================================================================================
336     //                                                                        Assist Logic
337     //                                                                        ============
338 
339     private OptionalEntity<SynonymItem> getEntity(final CreateForm form) {
340         switch (form.crudMode) {
341         case CrudMode.CREATE:
342             final SynonymItem entity = new SynonymItem(0, StringUtil.EMPTY_STRINGS, StringUtil.EMPTY_STRINGS);
343             return OptionalEntity.of(entity);
344         case CrudMode.EDIT:
345             if (form instanceof EditForm) {
346                 return ComponentUtil.getComponent(SynonymService.class).getSynonymItem(form.dictId, ((EditForm) form).id);
347             }
348             break;
349         default:
350             break;
351         }
352         return OptionalEntity.empty();
353     }
354 
355     public OptionalEntity<SynonymItem> createSynonymItem(final CreateForm form, final VaErrorHook hook) {
356         return getEntity(form).map(entity -> {
357             final String[] newInputs = splitLine(form.inputs);
358             validateSynonymString(newInputs, "inputs", hook);
359             entity.setNewInputs(newInputs);
360             final String[] newOutputs = splitLine(form.outputs);
361             validateSynonymString(newOutputs, "outputs", hook);
362             entity.setNewOutputs(newOutputs);
363             return entity;
364         });
365     }
366 
367     // ===================================================================================
368     //                                                                        Small Helper
369     //                                                                        ============
370     protected void verifyCrudMode(final int crudMode, final int expectedMode, final String dictId) {
371         if (crudMode != expectedMode) {
372             throwValidationError(messages -> {
373                 messages.addErrorsCrudInvalidMode(GLOBAL, String.valueOf(expectedMode), String.valueOf(crudMode));
374             }, () -> asListHtml(dictId));
375         }
376     }
377 
378     private void validateSynonymString(final String[] values, final String propertyName, final VaErrorHook hook) {
379         if (values.length == 0) {
380             return;
381         }
382         for (final String value : values) {
383             if (value.indexOf(',') >= 0) {
384                 throwValidationError(messages -> {
385                     messages.addErrorsInvalidStrIsIncluded(propertyName, value, ",");
386                 }, hook);
387             }
388             if (value.indexOf("=>") >= 0) {
389                 throwValidationError(messages -> {
390                     messages.addErrorsInvalidStrIsIncluded(propertyName, value, "=>");
391                 }, hook);
392             }
393         }
394     }
395 
396     private String[] splitLine(final String value) {
397         if (StringUtil.isBlank(value)) {
398             return StringUtil.EMPTY_STRINGS;
399         }
400         final String[] values = value.split("[\r\n]");
401         final List<String> list = new ArrayList<>(values.length);
402         for (final String line : values) {
403             if (StringUtil.isNotBlank(line)) {
404                 list.add(line.trim());
405             }
406         }
407         return list.toArray(new String[list.size()]);
408     }
409 
410     // ===================================================================================
411     //                                                                              JSP
412     //                                                                           =========
413 
414     protected HtmlResponse asDictIndexHtml() {
415         return redirect(AdminDictAction.class);
416     }
417 
418     private HtmlResponse asListHtml(final String dictId) {
419         return asHtml(path_AdminDictSynonym_AdminDictSynonymJsp).renderWith(data -> {
420             RenderDataUtil.register(data, "synonymItemItems", synonymService.getSynonymList(dictId, synonymPager));
421         }).useForm(SearchForm.class, setup -> {
422             setup.setup(form -> {
423                 copyBeanToBean(synonymPager, form, op -> op.include("id"));
424             });
425         });
426     }
427 
428     private HtmlResponse asEditHtml() {
429         return asHtml(path_AdminDictSynonym_AdminDictSynonymEditJsp);
430     }
431 
432     private HtmlResponse asDetailsHtml() {
433         return asHtml(path_AdminDictSynonym_AdminDictSynonymDetailsJsp);
434     }
435 
436 }