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.scheduler;
17  
18  import java.text.MessageFormat;
19  import java.util.Base64;
20  
21  import javax.annotation.Resource;
22  
23  import org.codelibs.fess.Constants;
24  import org.codelibs.fess.app.pager.SchedulerPager;
25  import org.codelibs.fess.app.service.ScheduledJobService;
26  import org.codelibs.fess.app.web.CrudMode;
27  import org.codelibs.fess.app.web.base.FessAdminAction;
28  import org.codelibs.fess.es.config.exentity.ScheduledJob;
29  import org.codelibs.fess.helper.ProcessHelper;
30  import org.codelibs.fess.helper.SystemHelper;
31  import org.codelibs.fess.util.ComponentUtil;
32  import org.codelibs.fess.util.RenderDataUtil;
33  import org.dbflute.optional.OptionalEntity;
34  import org.dbflute.optional.OptionalThing;
35  import org.lastaflute.web.Execute;
36  import org.lastaflute.web.response.HtmlResponse;
37  import org.lastaflute.web.response.render.RenderData;
38  import org.lastaflute.web.ruts.process.ActionRuntime;
39  import org.lastaflute.web.util.LaRequestUtil;
40  
41  /**
42   * @author shinsuke
43   * @author Keiichi Watanabe
44   */
45  public class AdminSchedulerAction extends FessAdminAction {
46  
47      // ===================================================================================
48      //                                                                           Attribute
49      //                                                                           =========
50      @Resource
51      private ScheduledJobService scheduledJobService;
52      @Resource
53      private SchedulerPager schedulerPager;
54      @Resource
55      protected ProcessHelper processHelper;
56  
57      // ===================================================================================
58      //                                                                               Hook
59      //                                                                              ======
60      @Override
61      protected void setupHtmlData(final ActionRuntime runtime) {
62          super.setupHtmlData(runtime);
63          runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNameScheduler()));
64      }
65  
66      // ===================================================================================
67      //                                                                      Search Execute
68      //                                                                      ==============
69      @Execute
70      public HtmlResponse index(final SearchForm form) {
71          return asListHtml();
72      }
73  
74      @Execute
75      public HtmlResponse list(final OptionalThing<Integer> pageNumber, final SearchForm form) {
76          pageNumber.ifPresent(num -> {
77              schedulerPager.setCurrentPageNumber(pageNumber.get());
78          }).orElse(() -> {
79              schedulerPager.setCurrentPageNumber(0);
80          });
81          return asHtml(path_AdminScheduler_AdminSchedulerJsp).renderWith(data -> {
82              searchPaging(data, form);
83          });
84      }
85  
86      @Execute
87      public HtmlResponse search(final SearchForm form) {
88          copyBeanToBean(form, schedulerPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
89          return asHtml(path_AdminScheduler_AdminSchedulerJsp).renderWith(data -> {
90              searchPaging(data, form);
91          });
92      }
93  
94      @Execute
95      public HtmlResponse reset(final SearchForm form) {
96          schedulerPager.clear();
97          return asHtml(path_AdminScheduler_AdminSchedulerJsp).renderWith(data -> {
98              searchPaging(data, form);
99          });
100     }
101 
102     protected void searchPaging(final RenderData data, final SearchForm form) {
103         RenderDataUtil.register(data, "scheduledJobItems", scheduledJobService.getScheduledJobList(schedulerPager)); // page navi
104 
105         // restore from pager
106         copyBeanToBean(schedulerPager, form, op -> op.include("id"));
107     }
108 
109     // ===================================================================================
110     //                                                                        Edit Execute
111     //                                                                        ============
112     // -----------------------------------------------------
113     //                                            Entry Page
114     //                                            ----------
115 
116     @Execute
117     public HtmlResponse createnewjob(final String type, final String id, final String name) {
118         saveToken();
119         return asHtml(path_AdminScheduler_AdminSchedulerEditJsp).useForm(CreateForm.class, op -> {
120             op.setup(scheduledJobForm -> {
121                 scheduledJobForm.initialize();
122                 scheduledJobForm.crudMode = CrudMode.CREATE;
123                 scheduledJobForm.jobLogging = Constants.ON;
124                 scheduledJobForm.crawler = Constants.ON;
125                 scheduledJobForm.available = Constants.ON;
126                 scheduledJobForm.cronExpression = null;
127                 final String decodedName = new String(Base64.getUrlDecoder().decode(name), Constants.CHARSET_UTF_8);
128                 scheduledJobForm.name = MessageFormat.format(fessConfig.getJobTemplateTitle(type), decodedName);
129                 final String[] ids = new String[] { "", "", "" };
130                 if (Constants.WEB_CRAWLER_TYPE.equals(type)) {
131                     ids[0] = "\"" + id + "\"";
132                 } else if (Constants.FILE_CRAWLER_TYPE.equals(type)) {
133                     ids[1] = "\"" + id + "\"";
134                 } else if (Constants.DATA_CRAWLER_TYPE.equals(type)) {
135                     ids[2] = "\"" + id + "\"";
136                 }
137                 scheduledJobForm.scriptData = MessageFormat.format(fessConfig.getJobTemplateScript(), ids[0], ids[1], ids[2], id);
138             });
139         });
140     }
141 
142     @Execute
143     public HtmlResponse createnew() {
144         saveToken();
145         return asHtml(path_AdminScheduler_AdminSchedulerEditJsp).useForm(CreateForm.class, op -> {
146             op.setup(form -> {
147                 form.initialize();
148                 form.crudMode = CrudMode.CREATE;
149             });
150         });
151     }
152 
153     @Execute
154     public HtmlResponse edit(final EditForm form) {
155         validate(form, messages -> {}, () -> asListHtml());
156         final String id = form.id;
157         scheduledJobService.getScheduledJob(id).ifPresent(entity -> {
158             loadScheduledJob(form, entity);
159         }).orElse(() -> {
160             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), () -> asListHtml());
161         });
162         saveToken();
163         if (form.crudMode.intValue() == CrudMode.EDIT) {
164             // back
165             form.crudMode = CrudMode.DETAILS;
166             return asDetailsHtml(id);
167         } else {
168             form.crudMode = CrudMode.EDIT;
169             return asEditHtml();
170         }
171     }
172 
173     // -----------------------------------------------------
174     //                                               Details
175     //                                               -------
176     @Execute
177     public HtmlResponse details(final int crudMode, final String id) {
178         verifyCrudMode(crudMode, CrudMode.DETAILS);
179         saveToken();
180         return asHtml(path_AdminScheduler_AdminSchedulerDetailsJsp).renderWith(data -> {
181             RenderDataUtil.register(data, "systemJobId", fessConfig.isSystemJobId(id));
182         }).useForm(EditForm.class, op -> {
183             op.setup(form -> {
184                 scheduledJobService.getScheduledJob(id).ifPresent(entity -> {
185                     loadScheduledJob(form, entity);
186                     form.crudMode = crudMode;
187                     LaRequestUtil.getOptionalRequest().ifPresent(request -> {
188                         request.setAttribute("running", entity.isRunning());
189                         request.setAttribute("enabled", entity.isEnabled());
190                     });
191                 }).orElse(() -> {
192                     throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), () -> asListHtml());
193                 });
194             });
195         });
196     }
197 
198     // -----------------------------------------------------
199     //                                         Actually Crud
200     //                                         -------------
201     @Execute
202     public HtmlResponse create(final CreateForm form) {
203         verifyCrudMode(form.crudMode, CrudMode.CREATE);
204         validate(form, messages -> {}, () -> asEditHtml());
205         verifyToken(() -> asEditHtml());
206         getScheduledJob(form).ifPresent(
207                 entity -> {
208                     try {
209                         scheduledJobService.store(entity);
210                         saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
211                     } catch (final Exception e) {
212                         throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)),
213                                 () -> asEditHtml());
214                     }
215                 }).orElse(() -> {
216             throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), () -> asEditHtml());
217         });
218         return redirect(getClass());
219     }
220 
221     @Execute
222     public HtmlResponse update(final EditForm form) {
223         verifyCrudMode(form.crudMode, CrudMode.EDIT);
224         validate(form, messages -> {}, () -> asEditHtml());
225         verifyToken(() -> asEditHtml());
226         getScheduledJob(form).ifPresent(
227                 entity -> {
228                     try {
229                         scheduledJobService.store(entity);
230                         saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL));
231                     } catch (final Exception e) {
232                         throwValidationError(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)),
233                                 () -> asEditHtml());
234                     }
235                 }).orElse(() -> {
236             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.id), () -> asEditHtml());
237         });
238         return redirect(getClass());
239     }
240 
241     @Execute
242     public HtmlResponse delete(final EditForm form) {
243         verifyCrudMode(form.crudMode, CrudMode.DETAILS);
244         final String id = form.id;
245         validate(form, messages -> {}, () -> asDetailsHtml(id));
246         verifyToken(() -> asDetailsHtml(id));
247         scheduledJobService
248                 .getScheduledJob(id)
249                 .ifPresent(
250                         entity -> {
251                             try {
252                                 scheduledJobService.delete(entity);
253                                 saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL));
254                             } catch (final Exception e) {
255                                 throwValidationError(
256                                         messages -> messages.addErrorsCrudFailedToDeleteCrudTable(GLOBAL, buildThrowableMessage(e)),
257                                         () -> asEditHtml());
258                             }
259                         }).orElse(() -> {
260                     throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), () -> asDetailsHtml(id));
261                 });
262         return redirect(getClass());
263     }
264 
265     @Execute
266     public HtmlResponse start(final EditForm form) {
267         verifyCrudMode(form.crudMode, CrudMode.DETAILS);
268         final String id = form.id;
269         validate(form, messages -> {}, () -> asDetailsHtml(id));
270         verifyToken(() -> asDetailsHtml(id));
271         scheduledJobService.getScheduledJob(id).ifPresent(entity -> {
272             if (!entity.isEnabled() || entity.isRunning()) {
273                 throwValidationError(messages -> {
274                     messages.addErrorsFailedToStartJob(GLOBAL, entity.getName());
275                 }, () -> asDetailsHtml(id));
276             }
277             try {
278                 entity.start();
279                 saveInfo(messages -> messages.addSuccessJobStarted(GLOBAL, entity.getName()));
280             } catch (final Exception e) {
281                 throwValidationError(messages -> {
282                     messages.addErrorsFailedToStartJob(GLOBAL, entity.getName());
283                 }, () -> asDetailsHtml(id));
284             }
285         }).orElse(() -> {
286             throwValidationError(messages -> {
287                 messages.addErrorsFailedToStartJob(GLOBAL, id);
288             }, () -> asDetailsHtml(id));
289         });
290         return redirect(getClass());
291     }
292 
293     @Execute
294     public HtmlResponse stop(final EditForm form) {
295         verifyCrudMode(form.crudMode, CrudMode.DETAILS);
296         final String id = form.id;
297         validate(form, messages -> {}, () -> asDetailsHtml(id));
298         verifyToken(() -> asDetailsHtml(id));
299         scheduledJobService.getScheduledJob(id).ifPresent(entity -> {
300             try {
301                 entity.stop();
302                 saveInfo(messages -> messages.addSuccessJobStopped(GLOBAL, entity.getName()));
303             } catch (final Exception e) {
304                 throwValidationError(messages -> {
305                     messages.addErrorsFailedToStopJob(GLOBAL, entity.getName());
306                 }, () -> asDetailsHtml(id));
307             }
308         }).orElse(() -> {
309             throwValidationError(messages -> {
310                 messages.addErrorsFailedToStartJob(GLOBAL, id);
311             }, () -> asDetailsHtml(id));
312         });
313         return redirect(getClass());
314     }
315 
316     // ===================================================================================
317     //                                                                        Assist Logic
318     //                                                                        ============
319     protected void loadScheduledJob(final EditForm form, final ScheduledJob entity) {
320         copyBeanToBean(entity, form, op -> op.exclude("crudMode").excludeNull());
321         form.jobLogging = entity.isLoggingEnabled() ? Constants.ON : null;
322         form.crawler = entity.isCrawlerJob() ? Constants.ON : null;
323         form.available = entity.isEnabled() ? Constants.ON : null;
324     }
325 
326     private static OptionalEntity<ScheduledJob> getEntity(final CreateForm form, final String username, final long currentTime) {
327         switch (form.crudMode) {
328         case CrudMode.CREATE:
329             return OptionalEntity.of(new ScheduledJob()).map(entity -> {
330                 entity.setCreatedBy(username);
331                 entity.setCreatedTime(currentTime);
332                 return entity;
333             });
334         case CrudMode.EDIT:
335             if (form instanceof EditForm) {
336                 return ComponentUtil.getComponent(ScheduledJobService.class).getScheduledJob(((EditForm) form).id);
337             }
338             break;
339         default:
340             break;
341         }
342         return OptionalEntity.empty();
343     }
344 
345     public static OptionalEntity<ScheduledJob> getScheduledJob(final CreateForm form) {
346         final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
347         final String username = systemHelper.getUsername();
348         final long currentTime = systemHelper.getCurrentTimeAsLong();
349         return getEntity(form, username, currentTime).map(entity -> {
350             entity.setUpdatedBy(username);
351             entity.setUpdatedTime(currentTime);
352             copyBeanToBean(form, entity, op -> op.exclude(Constants.COMMON_CONVERSION_RULE));
353             entity.setJobLogging(Constants.ON.equals(form.jobLogging) ? Constants.T : Constants.F);
354             entity.setCrawler(Constants.ON.equals(form.crawler) ? Constants.T : Constants.F);
355             entity.setAvailable(Constants.ON.equals(form.available) ? Constants.T : Constants.F);
356             return entity;
357         });
358     }
359 
360     // ===================================================================================
361     //                                                                        Small Helper
362     //                                                                        ============
363     protected void verifyCrudMode(final int crudMode, final int expectedMode) {
364         if (crudMode != expectedMode) {
365             throwValidationError(messages -> {
366                 messages.addErrorsCrudInvalidMode(GLOBAL, String.valueOf(expectedMode), String.valueOf(crudMode));
367             }, () -> asListHtml());
368         }
369     }
370 
371     // ===================================================================================
372     //                                                                              JSP
373     //                                                                           =========
374 
375     private HtmlResponse asListHtml() {
376         return asHtml(path_AdminScheduler_AdminSchedulerJsp).renderWith(data -> {
377             RenderDataUtil.register(data, "scheduledJobItems", scheduledJobService.getScheduledJobList(schedulerPager)); // page navi
378             }).useForm(SearchForm.class, setup -> {
379             setup.setup(form -> {
380                 copyBeanToBean(schedulerPager, form, op -> op.include("id"));
381             });
382         });
383     }
384 
385     private HtmlResponse asEditHtml() {
386         return asHtml(path_AdminScheduler_AdminSchedulerEditJsp);
387     }
388 
389     private HtmlResponse asDetailsHtml(final String id) {
390         return asHtml(path_AdminScheduler_AdminSchedulerDetailsJsp).renderWith(data -> {
391             RenderDataUtil.register(data, "systemJobId", fessConfig.isSystemJobId(id));
392         });
393     }
394 }