View Javadoc
1   /*
2    * Copyright 2012-2021 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.kuromoji;
17  
18  import java.io.File;
19  import java.io.IOException;
20  import java.io.InputStream;
21  
22  import javax.annotation.Resource;
23  
24  import org.codelibs.core.beans.util.BeanUtil;
25  import org.codelibs.core.lang.StringUtil;
26  import org.codelibs.fess.Constants;
27  import org.codelibs.fess.annotation.Secured;
28  import org.codelibs.fess.app.pager.KuromojiPager;
29  import org.codelibs.fess.app.service.KuromojiService;
30  import org.codelibs.fess.app.web.CrudMode;
31  import org.codelibs.fess.app.web.admin.dict.AdminDictAction;
32  import org.codelibs.fess.app.web.base.FessAdminAction;
33  import org.codelibs.fess.app.web.base.FessBaseAction;
34  import org.codelibs.fess.dict.kuromoji.KuromojiItem;
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  import org.lastaflute.web.validation.exception.ValidationErrorException;
46  
47  /**
48   * @author shinsuke
49   * @author Keiichi Watanabe
50   */
51  public class AdminDictKuromojiAction extends FessAdminAction {
52  
53      public static final String ROLE = "admin-dict";
54  
55      // ===================================================================================
56      //                                                                           Attribute
57      //                                                                           =========
58      @Resource
59      private KuromojiService kuromojiService;
60      @Resource
61      private KuromojiPager kuromojiPager;
62  
63      // ===================================================================================
64      //                                                                               Hook
65      //                                                                              ======
66      @Override
67      protected void setupHtmlData(final ActionRuntime runtime) {
68          super.setupHtmlData(runtime);
69          runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNameDictKuromoji()));
70      }
71  
72      @Override
73      protected String getActionRole() {
74          return ROLE;
75      }
76  
77      // ===================================================================================
78      //                                                                      Search Execute
79      //                                                                      ==============
80      @Execute
81      @Secured({ ROLE, ROLE + VIEW })
82      public HtmlResponse index(final SearchForm form) {
83          validate(form, messages -> {}, this::asDictIndexHtml);
84          kuromojiPager.clear();
85          return asHtml(path_AdminDictKuromoji_AdminDictKuromojiJsp).renderWith(data -> {
86              searchPaging(data, form);
87          });
88      }
89  
90      @Execute
91      @Secured({ ROLE, ROLE + VIEW })
92      public HtmlResponse list(final OptionalThing<Integer> pageNumber, final SearchForm form) {
93          validate(form, messages -> {}, this::asDictIndexHtml);
94          pageNumber.ifPresent(num -> {
95              kuromojiPager.setCurrentPageNumber(pageNumber.get());
96          }).orElse(() -> {
97              kuromojiPager.setCurrentPageNumber(0);
98          });
99          return asHtml(path_AdminDictKuromoji_AdminDictKuromojiJsp).renderWith(data -> {
100             searchPaging(data, form);
101         });
102     }
103 
104     @Execute
105     @Secured({ ROLE, ROLE + VIEW })
106     public HtmlResponse search(final SearchForm form) {
107         validate(form, messages -> {}, this::asDictIndexHtml);
108         copyBeanToBean(form, kuromojiPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
109         return asHtml(path_AdminDictKuromoji_AdminDictKuromojiJsp).renderWith(data -> {
110             searchPaging(data, form);
111         });
112     }
113 
114     @Execute
115     @Secured({ ROLE, ROLE + VIEW })
116     public HtmlResponse reset(final SearchForm form) {
117         validate(form, messages -> {}, this::asDictIndexHtml);
118         kuromojiPager.clear();
119         return asHtml(path_AdminDictKuromoji_AdminDictKuromojiJsp).renderWith(data -> {
120             searchPaging(data, form);
121         });
122     }
123 
124     protected void searchPaging(final RenderData data, final SearchForm form) {
125         // page navi
126         RenderDataUtil.register(data, "kuromojiItemItems", kuromojiService.getKuromojiList(form.dictId, kuromojiPager));
127 
128         // restore from pager
129         BeanUtil.copyBeanToBean(kuromojiPager, form, op -> {
130             op.exclude(Constants.PAGER_CONVERSION_RULE);
131         });
132     }
133 
134     // ===================================================================================
135     //                                                                        Edit Execute
136     //                                                                        ============
137     // -----------------------------------------------------
138     //                                            Entry Page
139     //                                            ----------
140     @Execute
141     @Secured({ ROLE })
142     public HtmlResponse createnew(final String dictId) {
143         saveToken();
144         return asHtml(path_AdminDictKuromoji_AdminDictKuromojiEditJsp).useForm(CreateForm.class, op -> {
145             op.setup(form -> {
146                 form.initialize();
147                 form.crudMode = CrudMode.CREATE;
148                 form.dictId = dictId;
149             });
150         });
151     }
152 
153     @Execute
154     @Secured({ ROLE })
155     public HtmlResponse edit(final EditForm form) {
156         validate(form, messages -> {}, () -> asListHtml(form.dictId));
157         kuromojiService.getKuromojiItem(form.dictId, form.id).ifPresent(entity -> {
158             copyBeanToBean(entity, form, op -> {});
159         }).orElse(() -> {
160             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()),
161                     () -> asListHtml(form.dictId));
162         });
163         saveToken();
164         if (form.crudMode.intValue() == CrudMode.EDIT) {
165             // back
166             form.crudMode = CrudMode.DETAILS;
167             return asDetailsHtml();
168         }
169         form.crudMode = CrudMode.EDIT;
170         return asEditHtml();
171     }
172 
173     // -----------------------------------------------------
174     //                                               Details
175     //                                               -------
176     @Execute
177     @Secured({ ROLE, ROLE + VIEW })
178     public HtmlResponse details(final String dictId, final int crudMode, final long id) {
179         verifyCrudMode(crudMode, CrudMode.DETAILS, dictId);
180         saveToken();
181         return asDetailsHtml().useForm(EditForm.class, op -> {
182             op.setup(form -> {
183                 kuromojiService.getKuromojiItem(dictId, id).ifPresent(entity -> {
184                     copyBeanToBean(entity, form, copyOp -> {
185                         copyOp.excludeNull();
186                     });
187                     form.crudMode = crudMode;
188                 }).orElse(() -> {
189                     throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, dictId + ":" + id),
190                             () -> asListHtml(dictId));
191                 });
192                 form.dictId = dictId;
193             });
194         });
195     }
196 
197     // -----------------------------------------------------
198     //                                              Download
199     //                                               -------
200     @Execute
201     @Secured({ ROLE, ROLE + VIEW })
202     public HtmlResponse downloadpage(final String dictId) {
203         saveToken();
204         return asHtml(path_AdminDictKuromoji_AdminDictKuromojiDownloadJsp).useForm(DownloadForm.class, op -> {
205             op.setup(form -> {
206                 form.dictId = dictId;
207             });
208         }).renderWith(data -> {
209             kuromojiService.getKuromojiFile(dictId).ifPresent(file -> {
210                 RenderDataUtil.register(data, "path", file.getPath());
211             }).orElse(() -> {
212                 throwValidationError(messages -> messages.addErrorsFailedToDownloadKuromojiFile(GLOBAL), this::asDictIndexHtml);
213             });
214         });
215     }
216 
217     @Execute
218     @Secured({ ROLE, ROLE + VIEW })
219     public ActionResponse download(final DownloadForm form) {
220         validate(form, messages -> {}, () -> downloadpage(form.dictId));
221         verifyTokenKeep(() -> downloadpage(form.dictId));
222         return kuromojiService.getKuromojiFile(form.dictId)
223                 .map(file -> asStream(new File(file.getPath()).getName()).contentTypeOctetStream().stream(out -> {
224                     file.writeOut(out);
225                 })).orElseGet(() -> {
226                     throwValidationError(messages -> messages.addErrorsFailedToDownloadKuromojiFile(GLOBAL),
227                             () -> downloadpage(form.dictId));
228                     return null;
229                 });
230     }
231 
232     // -----------------------------------------------------
233     //                                                Upload
234     //                                               -------
235     @Execute
236     @Secured({ ROLE })
237     public HtmlResponse uploadpage(final String dictId) {
238         saveToken();
239         return asHtml(path_AdminDictKuromoji_AdminDictKuromojiUploadJsp).useForm(UploadForm.class, op -> {
240             op.setup(form -> {
241                 form.dictId = dictId;
242             });
243         }).renderWith(data -> {
244             kuromojiService.getKuromojiFile(dictId).ifPresent(file -> {
245                 RenderDataUtil.register(data, "path", file.getPath());
246             }).orElse(() -> {
247                 throwValidationError(messages -> messages.addErrorsFailedToDownloadKuromojiFile(GLOBAL), this::asDictIndexHtml);
248             });
249         });
250     }
251 
252     @Execute
253     @Secured({ ROLE })
254     public HtmlResponse upload(final UploadForm form) {
255         validate(form, messages -> {}, () -> uploadpage(form.dictId));
256         verifyToken(() -> uploadpage(form.dictId));
257         return kuromojiService.getKuromojiFile(form.dictId).map(file -> {
258             try (InputStream inputStream = form.kuromojiFile.getInputStream()) {
259                 file.update(inputStream);
260             } catch (final IOException e) {
261                 throwValidationError(messages -> messages.addErrorsFailedToUploadKuromojiFile(GLOBAL),
262                         () -> redirectWith(getClass(), moreUrl("uploadpage/" + form.dictId)));
263             }
264             saveInfo(messages -> messages.addSuccessUploadKuromojiFile(GLOBAL));
265             return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId));
266         }).orElseGet(() -> {
267             throwValidationError(messages -> messages.addErrorsFailedToUploadKuromojiFile(GLOBAL), () -> uploadpage(form.dictId));
268             return null;
269         });
270 
271     }
272 
273     // -----------------------------------------------------
274     //                                         Actually Crud
275     //                                         -------------
276     @Execute
277     @Secured({ ROLE })
278     public HtmlResponse create(final CreateForm form) {
279         verifyCrudMode(form.crudMode, CrudMode.CREATE, form.dictId);
280         validate(form, messages -> {}, this::asEditHtml);
281         verifyToken(this::asEditHtml);
282         createKuromojiItem(form, this::asEditHtml).ifPresent(entity -> {
283             try {
284                 kuromojiService.store(form.dictId, entity);
285                 saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
286             } catch (final Exception e) {
287                 throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)),
288                         this::asEditHtml);
289             }
290         }).orElse(() -> {
291             throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), this::asEditHtml);
292         });
293         return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId));
294     }
295 
296     @Execute
297     @Secured({ ROLE })
298     public HtmlResponse update(final EditForm form) {
299         verifyCrudMode(form.crudMode, CrudMode.EDIT, form.dictId);
300         validate(form, messages -> {}, this::asEditHtml);
301         verifyToken(this::asEditHtml);
302         createKuromojiItem(form, this::asEditHtml).ifPresent(entity -> {
303             try {
304                 kuromojiService.store(form.dictId, entity);
305                 saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL));
306             } catch (final Exception e) {
307                 throwValidationError(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)),
308                         this::asEditHtml);
309             }
310         }).orElse(() -> {
311             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()), this::asEditHtml);
312         });
313         return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId));
314     }
315 
316     @Execute
317     @Secured({ ROLE })
318     public HtmlResponse delete(final EditForm form) {
319         verifyCrudMode(form.crudMode, CrudMode.DETAILS, form.dictId);
320         validate(form, messages -> {}, this::asDetailsHtml);
321         verifyToken(this::asDetailsHtml);
322         kuromojiService.getKuromojiItem(form.dictId, form.id).ifPresent(entity -> {
323             try {
324                 kuromojiService.delete(form.dictId, entity);
325                 saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL));
326             } catch (final Exception e) {
327                 throwValidationError(messages -> messages.addErrorsCrudFailedToDeleteCrudTable(GLOBAL, buildThrowableMessage(e)),
328                         this::asEditHtml);
329             }
330         }).orElse(() -> {
331             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()), this::asDetailsHtml);
332         });
333         return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId));
334     }
335 
336     //===================================================================================
337     //                                                                        Assist Logic
338     //                                                                        ============
339 
340     private static OptionalEntity<KuromojiItem> getEntity(final CreateForm form) {
341         switch (form.crudMode) {
342         case CrudMode.CREATE:
343             final KuromojiItem entity = new KuromojiItem(0, StringUtil.EMPTY, StringUtil.EMPTY, StringUtil.EMPTY, StringUtil.EMPTY);
344             return OptionalEntity.of(entity);
345         case CrudMode.EDIT:
346             if (form instanceof EditForm) {
347                 return ComponentUtil.getComponent(KuromojiService.class).getKuromojiItem(form.dictId, ((EditForm) form).id);
348             }
349             break;
350         default:
351             break;
352         }
353         return OptionalEntity.empty();
354     }
355 
356     protected OptionalEntity<KuromojiItem> createKuromojiItem(final CreateForm form, final VaErrorHook hook) {
357         try {
358             return createKuromojiItem(this, form, hook);
359         } catch (final ValidationErrorException e) {
360             saveToken();
361             throw e;
362         }
363     }
364 
365     public static OptionalEntity<KuromojiItem> createKuromojiItem(final FessBaseAction action, final CreateForm form,
366             final VaErrorHook hook) {
367         return getEntity(form).map(entity -> {
368             entity.setNewToken(form.token);
369             entity.setNewSegmentation(form.segmentation);
370             entity.setNewReading(form.reading);
371             entity.setNewPos(form.pos);
372             return entity;
373         });
374     }
375 
376     // ===================================================================================
377     //                                                                        Small Helper
378     //                                                                        ============
379     protected void verifyCrudMode(final int crudMode, final int expectedMode, final String dictId) {
380         if (crudMode != expectedMode) {
381             throwValidationError(messages -> {
382                 messages.addErrorsCrudInvalidMode(GLOBAL, String.valueOf(expectedMode), String.valueOf(crudMode));
383             }, () -> asListHtml(dictId));
384         }
385     }
386 
387     // ===================================================================================
388     //                                                                              JSP
389     //                                                                           =========
390 
391     protected HtmlResponse asDictIndexHtml() {
392         return redirect(AdminDictAction.class);
393     }
394 
395     private HtmlResponse asListHtml(final String dictId) {
396         return asHtml(path_AdminDictKuromoji_AdminDictKuromojiJsp).renderWith(data -> {
397             RenderDataUtil.register(data, "kuromojiItemItems", kuromojiService.getKuromojiList(dictId, kuromojiPager));
398         }).useForm(SearchForm.class, setup -> {
399             setup.setup(form -> {
400                 copyBeanToBean(kuromojiPager, form, op -> op.include("id"));
401             });
402         });
403     }
404 
405     private HtmlResponse asEditHtml() {
406         return asHtml(path_AdminDictKuromoji_AdminDictKuromojiEditJsp);
407     }
408 
409     private HtmlResponse asDetailsHtml() {
410         return asHtml(path_AdminDictKuromoji_AdminDictKuromojiDetailsJsp);
411     }
412 
413 }