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