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.dataconfig;
17  
18  import static org.codelibs.core.stream.StreamUtil.split;
19  import static org.codelibs.core.stream.StreamUtil.stream;
20  
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.stream.Collectors;
26  import java.util.stream.Stream;
27  
28  import javax.annotation.Resource;
29  
30  import org.codelibs.core.lang.StringUtil;
31  import org.codelibs.fess.Constants;
32  import org.codelibs.fess.annotation.Secured;
33  import org.codelibs.fess.app.pager.DataConfigPager;
34  import org.codelibs.fess.app.service.DataConfigService;
35  import org.codelibs.fess.app.service.RoleTypeService;
36  import org.codelibs.fess.app.web.CrudMode;
37  import org.codelibs.fess.app.web.base.FessAdminAction;
38  import org.codelibs.fess.ds.DataStoreFactory;
39  import org.codelibs.fess.es.config.exentity.CrawlingConfig.ConfigType;
40  import org.codelibs.fess.es.config.exentity.DataConfig;
41  import org.codelibs.fess.helper.PermissionHelper;
42  import org.codelibs.fess.helper.SystemHelper;
43  import org.codelibs.fess.util.ComponentUtil;
44  import org.codelibs.fess.util.RenderDataUtil;
45  import org.dbflute.optional.OptionalEntity;
46  import org.dbflute.optional.OptionalThing;
47  import org.lastaflute.web.Execute;
48  import org.lastaflute.web.response.HtmlResponse;
49  import org.lastaflute.web.response.render.RenderData;
50  import org.lastaflute.web.ruts.process.ActionRuntime;
51  
52  /**
53   * @author shinsuke
54   * @author Keiichi Watanabe
55   */
56  public class AdminDataconfigAction extends FessAdminAction {
57  
58      public static final String ROLE = "admin-dataconfig";
59  
60      // ===================================================================================
61      //                                                                           Attribute
62      //                                                                           =========
63      @Resource
64      private DataConfigService dataConfigService;
65      @Resource
66      private DataConfigPager dataConfigPager;
67      @Resource
68      private RoleTypeService roleTypeService;
69      @Resource
70      protected DataStoreFactory dataStoreFactory;
71  
72      // ===================================================================================
73      //                                                                               Hook
74      //                                                                              ======
75      @Override
76      protected void setupHtmlData(final ActionRuntime runtime) {
77          super.setupHtmlData(runtime);
78          runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNameDataconfig()));
79      }
80  
81      @Override
82      protected String getActionRole() {
83          return ROLE;
84      }
85  
86      // ===================================================================================
87      //                                                                      Search Execute
88      //                                                                      ==============
89      @Execute
90      @Secured({ ROLE, ROLE + VIEW })
91      public HtmlResponse index() {
92          return asListHtml();
93      }
94  
95      @Execute
96      @Secured({ ROLE, ROLE + VIEW })
97      public HtmlResponse list(final OptionalThing<Integer> pageNumber, final SearchForm form) {
98          pageNumber.ifPresent(num -> {
99              dataConfigPager.setCurrentPageNumber(pageNumber.get());
100         }).orElse(() -> {
101             dataConfigPager.setCurrentPageNumber(0);
102         });
103         return asHtml(path_AdminDataconfig_AdminDataconfigJsp).renderWith(data -> {
104             searchPaging(data, form);
105         });
106     }
107 
108     @Execute
109     @Secured({ ROLE, ROLE + VIEW })
110     public HtmlResponse search(final SearchForm form) {
111         copyBeanToBean(form, dataConfigPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
112         return asHtml(path_AdminDataconfig_AdminDataconfigJsp).renderWith(data -> {
113             searchPaging(data, form);
114         });
115     }
116 
117     @Execute
118     @Secured({ ROLE, ROLE + VIEW })
119     public HtmlResponse reset(final SearchForm form) {
120         dataConfigPager.clear();
121         return asHtml(path_AdminDataconfig_AdminDataconfigJsp).renderWith(data -> {
122             searchPaging(data, form);
123         });
124     }
125 
126     protected void searchPaging(final RenderData data, final SearchForm form) {
127         RenderDataUtil.register(data, "dataConfigItems", dataConfigService.getDataConfigList(dataConfigPager)); // page navi
128         registerHandlerNames(data);
129 
130         // restore from pager
131         copyBeanToBean(dataConfigPager, form, op -> op.include("name", "handlerName", "description"));
132     }
133 
134     // ===================================================================================
135     //                                                                        Edit Execute
136     //                                                                        ============
137     // -----------------------------------------------------
138     //                                            Entry Page
139     //                                            ----------
140     @Execute
141     @Secured({ ROLE })
142     public HtmlResponse createnew() {
143         saveToken();
144         return asEditHtml().useForm(CreateForm.class, op -> {
145             op.setup(form -> {
146                 form.initialize();
147                 ComponentUtil.getCrawlingConfigHelper().getDefaultConfig(ConfigType.DATA).ifPresent(entity -> {
148                     copyBeanToBean(entity, form, copyOp -> {
149                         copyOp.excludeNull();
150                         copyOp.exclude(Stream.concat(Stream.of(Constants.COMMON_CONVERSION_RULE),
151                                 Stream.of(Constants.PERMISSIONS, Constants.VIRTUAL_HOSTS)).toArray(n -> new String[n]));
152                     });
153                     final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
154                     form.permissions = stream(entity.getPermissions()).get(stream -> stream.map(s -> permissionHelper.decode(s))
155                             .filter(StringUtil::isNotBlank).distinct().collect(Collectors.joining("\n")));
156                     form.virtualHosts = stream(entity.getVirtualHosts())
157                             .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.joining("\n")));
158                     form.name = null;
159                 });
160                 form.crudMode = CrudMode.CREATE;
161             });
162         });
163     }
164 
165     @Execute
166     @Secured({ ROLE })
167     public HtmlResponse edit(final EditForm form) {
168         validate(form, messages -> {}, this::asListHtml);
169         final String id = form.id;
170         dataConfigService.getDataConfig(id).ifPresent(entity -> {
171             copyBeanToBean(entity, form, copyOp -> {
172                 copyOp.excludeNull();
173                 copyOp.exclude(Constants.PERMISSIONS, Constants.VIRTUAL_HOSTS);
174             });
175             final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
176             form.permissions = stream(entity.getPermissions()).get(stream -> stream.map(permissionHelper::decode)
177                     .filter(StringUtil::isNotBlank).distinct().collect(Collectors.joining("\n")));
178             form.virtualHosts = stream(entity.getVirtualHosts())
179                     .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.joining("\n")));
180         }).orElse(() -> {
181             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml);
182         });
183         saveToken();
184         if (form.crudMode.intValue() == CrudMode.EDIT) {
185             // back
186             form.crudMode = CrudMode.DETAILS;
187             return asDetailsHtml();
188         }
189         form.crudMode = CrudMode.EDIT;
190         return asEditHtml();
191     }
192 
193     // -----------------------------------------------------
194     //                                               Details
195     //                                               -------
196     @Execute
197     @Secured({ ROLE, ROLE + VIEW })
198     public HtmlResponse details(final int crudMode, final String id) {
199         verifyCrudMode(crudMode, CrudMode.DETAILS);
200         saveToken();
201         return asDetailsHtml().useForm(EditForm.class, op -> {
202             op.setup(form -> {
203                 dataConfigService.getDataConfig(id).ifPresent(entity -> {
204                     copyBeanToBean(entity, form, copyOp -> {
205                         copyOp.excludeNull();
206                         copyOp.exclude(Constants.PERMISSIONS, Constants.VIRTUAL_HOSTS);
207                     });
208                     final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
209                     form.permissions = stream(entity.getPermissions()).get(stream -> stream.map(s -> permissionHelper.decode(s))
210                             .filter(StringUtil::isNotBlank).distinct().collect(Collectors.joining("\n")));
211                     form.virtualHosts = stream(entity.getVirtualHosts())
212                             .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.joining("\n")));
213                     form.crudMode = crudMode;
214                 }).orElse(
215                         () -> throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml));
216             });
217         });
218     }
219 
220     // -----------------------------------------------------
221     //                                         Actually Crud
222     //                                         -------------
223     @Execute
224     @Secured({ ROLE })
225     public HtmlResponse create(final CreateForm form) {
226         verifyCrudMode(form.crudMode, CrudMode.CREATE);
227         validate(form, messages -> {}, this::asEditHtml);
228         verifyToken(this::asEditHtml);
229         getDataConfig(form).ifPresent(entity -> {
230             try {
231                 dataConfigService.store(entity);
232                 saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
233             } catch (final Exception e) {
234                 throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)),
235                         this::asEditHtml);
236             }
237         }).orElse(() -> {
238             throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), this::asEditHtml);
239         });
240         return redirect(getClass());
241     }
242 
243     @Execute
244     @Secured({ ROLE })
245     public HtmlResponse update(final EditForm form) {
246         verifyCrudMode(form.crudMode, CrudMode.EDIT);
247         validate(form, messages -> {}, this::asEditHtml);
248         verifyToken(this::asEditHtml);
249         getDataConfig(form).ifPresent(entity -> {
250             try {
251                 dataConfigService.store(entity);
252                 saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL));
253             } catch (final Exception e) {
254                 throwValidationError(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)),
255                         this::asEditHtml);
256             }
257         }).orElse(() -> {
258             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.id), this::asEditHtml);
259         });
260         return redirect(getClass());
261     }
262 
263     @Execute
264     @Secured({ ROLE })
265     public HtmlResponse delete(final EditForm form) {
266         verifyCrudMode(form.crudMode, CrudMode.DETAILS);
267         validate(form, messages -> {}, this::asDetailsHtml);
268         verifyToken(this::asDetailsHtml);
269         final String id = form.id;
270         dataConfigService.getDataConfig(id).ifPresent(entity -> {
271             try {
272                 dataConfigService.delete(entity);
273                 saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL));
274             } catch (final Exception e) {
275                 throwValidationError(messages -> messages.addErrorsCrudFailedToDeleteCrudTable(GLOBAL, buildThrowableMessage(e)),
276                         this::asEditHtml);
277             }
278         }).orElse(() -> throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asDetailsHtml));
279         return redirect(getClass());
280     }
281 
282     // ===================================================================================
283     //                                                                        Assist Logic
284     //                                                                        ============
285     public static OptionalEntity<DataConfig> getEntity(final CreateForm form, final String username, final long currentTime) {
286         switch (form.crudMode) {
287         case CrudMode.CREATE:
288             return OptionalEntity.of(new DataConfig()).map(entity -> {
289                 entity.setCreatedBy(username);
290                 entity.setCreatedTime(currentTime);
291                 return entity;
292             });
293         case CrudMode.EDIT:
294             if (form instanceof EditForm) {
295                 return ComponentUtil.getComponent(DataConfigService.class).getDataConfig(((EditForm) form).id);
296             }
297             break;
298         default:
299             break;
300         }
301         return OptionalEntity.empty();
302     }
303 
304     public static OptionalEntity<DataConfig> getDataConfig(final CreateForm form) {
305         final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
306         final String username = systemHelper.getUsername();
307         final long currentTime = systemHelper.getCurrentTimeAsLong();
308         return getEntity(form, username, currentTime).map(entity -> {
309             entity.setUpdatedBy(username);
310             entity.setUpdatedTime(currentTime);
311             copyBeanToBean(form, entity,
312                     op -> op.exclude(Stream
313                             .concat(Stream.of(Constants.COMMON_CONVERSION_RULE), Stream.of(Constants.PERMISSIONS, Constants.VIRTUAL_HOSTS))
314                             .toArray(n -> new String[n])));
315             final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
316             entity.setPermissions(split(form.permissions, "\n").get(stream -> stream.map(s -> permissionHelper.encode(s))
317                     .filter(StringUtil::isNotBlank).distinct().toArray(n -> new String[n])));
318             entity.setVirtualHosts(split(form.virtualHosts, "\n")
319                     .get(stream -> stream.filter(StringUtil::isNotBlank).distinct().map(String::trim).toArray(n -> new String[n])));
320             return entity;
321         });
322     }
323 
324     protected void registerRolesAndLabels(final RenderData data) {
325         RenderDataUtil.register(data, "roleTypeItems", roleTypeService.getRoleTypeList());
326     }
327 
328     protected void registerHandlerNames(final RenderData data) {
329         final String[] dataStoreNames = dataStoreFactory.getDataStoreNames();
330         final List<Map<String, String>> itemList = new ArrayList<>();
331         for (final String name : dataStoreNames) {
332             final Map<String, String> map = new HashMap<>();
333             map.put(Constants.ITEM_LABEL, name);
334             map.put(Constants.ITEM_VALUE, name);
335             itemList.add(map);
336         }
337         RenderDataUtil.register(data, "handlerNameItems", itemList);
338     }
339 
340     // ===================================================================================
341     //                                                                        Small Helper
342     //                                                                        ============
343     protected void verifyCrudMode(final int crudMode, final int expectedMode) {
344         if (crudMode != expectedMode) {
345             throwValidationError(messages -> {
346                 messages.addErrorsCrudInvalidMode(GLOBAL, String.valueOf(expectedMode), String.valueOf(crudMode));
347             }, this::asListHtml);
348         }
349     }
350 
351     // ===================================================================================
352     //                                                                              JSP
353     //                                                                           =========
354 
355     private HtmlResponse asListHtml() {
356         return asHtml(path_AdminDataconfig_AdminDataconfigJsp).renderWith(data -> {
357             RenderDataUtil.register(data, "dataConfigItems", dataConfigService.getDataConfigList(dataConfigPager));
358             registerHandlerNames(data);
359         }).useForm(SearchForm.class, setup -> {
360             setup.setup(form -> {
361                 copyBeanToBean(dataConfigPager, form, op -> op.include("name", "handlerName", "description"));
362             });
363         });
364     }
365 
366     private HtmlResponse asEditHtml() {
367         return asHtml(path_AdminDataconfig_AdminDataconfigEditJsp).renderWith(data -> {
368             registerRolesAndLabels(data);
369             registerHandlerNames(data);
370         });
371     }
372 
373     private HtmlResponse asDetailsHtml() {
374         return asHtml(path_AdminDataconfig_AdminDataconfigDetailsJsp).renderWith(data -> {
375             registerRolesAndLabels(data);
376             registerHandlerNames(data);
377         });
378     }
379 
380 }