1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.app.web.admin.dict.mapping;
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.annotation.Secured;
30 import org.codelibs.fess.app.pager.CharMappingPager;
31 import org.codelibs.fess.app.service.CharMappingService;
32 import org.codelibs.fess.app.web.CrudMode;
33 import org.codelibs.fess.app.web.admin.dict.AdminDictAction;
34 import org.codelibs.fess.app.web.base.FessAdminAction;
35 import org.codelibs.fess.app.web.base.FessBaseAction;
36 import org.codelibs.fess.dict.mapping.CharMappingItem;
37 import org.codelibs.fess.util.ComponentUtil;
38 import org.codelibs.fess.util.RenderDataUtil;
39 import org.dbflute.optional.OptionalEntity;
40 import org.dbflute.optional.OptionalThing;
41 import org.lastaflute.web.Execute;
42 import org.lastaflute.web.response.ActionResponse;
43 import org.lastaflute.web.response.HtmlResponse;
44 import org.lastaflute.web.response.render.RenderData;
45 import org.lastaflute.web.ruts.process.ActionRuntime;
46 import org.lastaflute.web.validation.VaErrorHook;
47 import org.lastaflute.web.validation.exception.ValidationErrorException;
48
49
50
51
52
53 public class AdminDictMappingAction extends FessAdminAction {
54
55 public static final String ROLE = "admin-dict";
56
57
58
59
60 @Resource
61 private CharMappingService charMappingService;
62 @Resource
63 private CharMappingPager charMappingPager;
64
65
66
67
68 @Override
69 protected void setupHtmlData(final ActionRuntime runtime) {
70 super.setupHtmlData(runtime);
71 runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNameDictMapping()));
72 }
73
74 @Override
75 protected String getActionRole() {
76 return ROLE;
77 }
78
79
80
81
82 @Execute
83 @Secured({ ROLE, ROLE + VIEW })
84 public HtmlResponse index(final SearchForm form) {
85 validate(form, messages -> {}, this::asDictIndexHtml);
86 charMappingPager.clear();
87 return asHtml(path_AdminDictMapping_AdminDictMappingJsp).renderWith(data -> {
88 searchPaging(data, form);
89 });
90 }
91
92 @Execute
93 @Secured({ ROLE, ROLE + VIEW })
94 public HtmlResponse list(final OptionalThing<Integer> pageNumber, final SearchForm form) {
95 validate(form, messages -> {}, this::asDictIndexHtml);
96 pageNumber.ifPresent(num -> {
97 charMappingPager.setCurrentPageNumber(pageNumber.get());
98 }).orElse(() -> {
99 charMappingPager.setCurrentPageNumber(0);
100 });
101 return asHtml(path_AdminDictMapping_AdminDictMappingJsp).renderWith(data -> {
102 searchPaging(data, form);
103 });
104 }
105
106 @Execute
107 @Secured({ ROLE, ROLE + VIEW })
108 public HtmlResponse search(final SearchForm form) {
109 validate(form, messages -> {}, this::asDictIndexHtml);
110 copyBeanToBean(form, charMappingPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
111 return asHtml(path_AdminDictMapping_AdminDictMappingJsp).renderWith(data -> {
112 searchPaging(data, form);
113 });
114 }
115
116 @Execute
117 @Secured({ ROLE, ROLE + VIEW })
118 public HtmlResponse reset(final SearchForm form) {
119 validate(form, messages -> {}, this::asDictIndexHtml);
120 charMappingPager.clear();
121 return asHtml(path_AdminDictMapping_AdminDictMappingJsp).renderWith(data -> {
122 searchPaging(data, form);
123 });
124 }
125
126 protected void searchPaging(final RenderData data, final SearchForm form) {
127
128 RenderDataUtil.register(data, "charMappingItemItems", charMappingService.getCharMappingList(form.dictId, charMappingPager));
129
130
131 BeanUtil.copyBeanToBean(charMappingPager, form, op -> {
132 op.exclude(Constants.PAGER_CONVERSION_RULE);
133 });
134 }
135
136
137
138
139
140
141
142 @Execute
143 @Secured({ ROLE })
144 public HtmlResponse createnew(final String dictId) {
145 saveToken();
146 return asHtml(path_AdminDictMapping_AdminDictMappingEditJsp).useForm(CreateForm.class, op -> {
147 op.setup(form -> {
148 form.initialize();
149 form.crudMode = CrudMode.CREATE;
150 form.dictId = dictId;
151 });
152 });
153 }
154
155 @Execute
156 @Secured({ ROLE })
157 public HtmlResponse edit(final EditForm form) {
158 validate(form, messages -> {}, () -> asListHtml(form.dictId));
159 charMappingService.getCharMappingItem(form.dictId, form.id).ifPresent(entity -> {
160 form.inputs = entity.getInputsValue();
161 form.output = entity.getOutput();
162 }).orElse(() -> {
163 throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()),
164 () -> asListHtml(form.dictId));
165 });
166 saveToken();
167 if (form.crudMode.intValue() == CrudMode.EDIT) {
168
169 form.crudMode = CrudMode.DETAILS;
170 return asDetailsHtml();
171 }
172 form.crudMode = CrudMode.EDIT;
173 return asEditHtml();
174 }
175
176
177
178
179 @Execute
180 @Secured({ ROLE, ROLE + VIEW })
181 public HtmlResponse details(final String dictId, final int crudMode, final long id) {
182 verifyCrudMode(crudMode, CrudMode.DETAILS, dictId);
183 saveToken();
184 return asDetailsHtml().useForm(EditForm.class, op -> {
185 op.setup(form -> {
186 charMappingService.getCharMappingItem(dictId, id).ifPresent(entity -> {
187 form.inputs = entity.getInputsValue();
188 form.output = entity.getOutput();
189 }).orElse(() -> {
190 throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, dictId + ":" + id),
191 () -> asListHtml(dictId));
192 });
193 form.id = id;
194 form.crudMode = crudMode;
195 form.dictId = dictId;
196 });
197 });
198 }
199
200
201
202
203 @Execute
204 @Secured({ ROLE, ROLE + VIEW })
205 public HtmlResponse downloadpage(final String dictId) {
206 saveToken();
207 return asHtml(path_AdminDictMapping_AdminDictMappingDownloadJsp).useForm(DownloadForm.class, op -> {
208 op.setup(form -> {
209 form.dictId = dictId;
210 });
211 }).renderWith(data -> {
212 charMappingService.getCharMappingFile(dictId).ifPresent(file -> {
213 RenderDataUtil.register(data, "path", file.getPath());
214 }).orElse(() -> {
215 throwValidationError(messages -> messages.addErrorsFailedToDownloadMappingFile(GLOBAL), this::asDictIndexHtml);
216 });
217 });
218 }
219
220 @Execute
221 @Secured({ ROLE, ROLE + VIEW })
222 public ActionResponse download(final DownloadForm form) {
223 validate(form, messages -> {}, () -> downloadpage(form.dictId));
224 verifyTokenKeep(() -> downloadpage(form.dictId));
225 return charMappingService.getCharMappingFile(form.dictId)
226 .map(file -> asStream(new File(file.getPath()).getName()).contentTypeOctetStream().stream(out -> {
227 file.writeOut(out);
228 })).orElseGet(() -> {
229 throwValidationError(messages -> messages.addErrorsFailedToDownloadMappingFile(GLOBAL),
230 () -> downloadpage(form.dictId));
231 return null;
232 });
233 }
234
235
236
237
238 @Execute
239 @Secured({ ROLE })
240 public HtmlResponse uploadpage(final String dictId) {
241 saveToken();
242 return asHtml(path_AdminDictMapping_AdminDictMappingUploadJsp).useForm(UploadForm.class, op -> {
243 op.setup(form -> {
244 form.dictId = dictId;
245 });
246 }).renderWith(data -> {
247 charMappingService.getCharMappingFile(dictId).ifPresent(file -> {
248 RenderDataUtil.register(data, "path", file.getPath());
249 }).orElse(() -> {
250 throwValidationError(messages -> messages.addErrorsFailedToDownloadMappingFile(GLOBAL), this::asDictIndexHtml);
251 });
252 });
253 }
254
255 @Execute
256 @Secured({ ROLE })
257 public HtmlResponse upload(final UploadForm form) {
258 validate(form, messages -> {}, () -> uploadpage(form.dictId));
259 verifyToken(() -> uploadpage(form.dictId));
260 return charMappingService.getCharMappingFile(form.dictId).map(file -> {
261 try (InputStream inputStream = form.charMappingFile.getInputStream()) {
262 file.update(inputStream);
263 } catch (final IOException e) {
264 throwValidationError(messages -> messages.addErrorsFailedToUploadMappingFile(GLOBAL),
265 () -> redirectWith(getClass(), moreUrl("uploadpage/" + form.dictId)));
266 }
267 saveInfo(messages -> messages.addSuccessUploadMappingFile(GLOBAL));
268 return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId));
269 }).orElseGet(() -> {
270 throwValidationError(messages -> messages.addErrorsFailedToUploadMappingFile(GLOBAL), () -> uploadpage(form.dictId));
271 return null;
272 });
273
274 }
275
276
277
278
279 @Execute
280 @Secured({ ROLE })
281 public HtmlResponse create(final CreateForm form) {
282 verifyCrudMode(form.crudMode, CrudMode.CREATE, form.dictId);
283 validate(form, messages -> {}, this::asEditHtml);
284 verifyToken(this::asEditHtml);
285 createCharMappingItem(form, this::asEditHtml).ifPresent(entity -> {
286 try {
287 charMappingService.store(form.dictId, entity);
288 saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
289 } catch (final Exception e) {
290 throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)),
291 this::asEditHtml);
292 }
293 }).orElse(() -> {
294 throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), this::asEditHtml);
295 });
296 return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId));
297 }
298
299 @Execute
300 @Secured({ ROLE })
301 public HtmlResponse update(final EditForm form) {
302 verifyCrudMode(form.crudMode, CrudMode.EDIT, form.dictId);
303 validate(form, messages -> {}, this::asEditHtml);
304 verifyToken(this::asEditHtml);
305 createCharMappingItem(form, this::asEditHtml).ifPresent(entity -> {
306 try {
307 charMappingService.store(form.dictId, entity);
308 saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL));
309 } catch (final Exception e) {
310 throwValidationError(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)),
311 this::asEditHtml);
312 }
313 }).orElse(() -> {
314 throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()), this::asEditHtml);
315 });
316 return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId));
317 }
318
319 @Execute
320 @Secured({ ROLE })
321 public HtmlResponse delete(final EditForm form) {
322 verifyCrudMode(form.crudMode, CrudMode.DETAILS, form.dictId);
323 validate(form, messages -> {}, this::asDetailsHtml);
324 verifyToken(this::asDetailsHtml);
325 charMappingService.getCharMappingItem(form.dictId, form.id).ifPresent(entity -> {
326 try {
327 charMappingService.delete(form.dictId, entity);
328 saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL));
329 } catch (final Exception e) {
330 throwValidationError(messages -> messages.addErrorsCrudFailedToDeleteCrudTable(GLOBAL, buildThrowableMessage(e)),
331 this::asEditHtml);
332 }
333 }).orElse(() -> {
334 throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()), this::asDetailsHtml);
335 });
336 return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId));
337 }
338
339
340
341
342
343 private static OptionalEntity<CharMappingItem> getEntity(final CreateForm form) {
344 switch (form.crudMode) {
345 case CrudMode.CREATE:
346 final CharMappingItem entity = new CharMappingItem(0, StringUtil.EMPTY_STRINGS, StringUtil.EMPTY);
347 return OptionalEntity.of(entity);
348 case CrudMode.EDIT:
349 if (form instanceof EditForm) {
350 return ComponentUtil.getComponent(CharMappingService.class).getCharMappingItem(form.dictId, ((EditForm) form).id);
351 }
352 break;
353 default:
354 break;
355 }
356 return OptionalEntity.empty();
357 }
358
359 protected OptionalEntity<CharMappingItem> createCharMappingItem(final CreateForm form, final VaErrorHook hook) {
360 try {
361 return createCharMappingItem(this, form, hook);
362 } catch (final ValidationErrorException e) {
363 saveToken();
364 throw e;
365 }
366 }
367
368 public static OptionalEntity<CharMappingItem> createCharMappingItem(final FessBaseAction action, final CreateForm form,
369 final VaErrorHook hook) {
370 return getEntity(form).map(entity -> {
371 final String[] newInputs = splitLine(form.inputs);
372 validateMappingString(action, newInputs, "inputs", hook);
373 entity.setNewInputs(newInputs);
374 final String newOutput = form.output;
375 entity.setNewOutput(newOutput);
376 return entity;
377 });
378 }
379
380
381
382
383 protected void verifyCrudMode(final int crudMode, final int expectedMode, final String dictId) {
384 if (crudMode != expectedMode) {
385 throwValidationError(messages -> {
386 messages.addErrorsCrudInvalidMode(GLOBAL, String.valueOf(expectedMode), String.valueOf(crudMode));
387 }, () -> asListHtml(dictId));
388 }
389 }
390
391 private static void validateMappingString(final FessBaseAction action, final String[] values, final String propertyName,
392 final VaErrorHook hook) {
393 if (values.length == 0) {
394 return;
395 }
396 for (final String value : values) {
397 if (value.indexOf(',') >= 0) {
398 action.throwValidationError(messages -> {
399 messages.addErrorsInvalidStrIsIncluded(propertyName, value, ",");
400 }, hook);
401 }
402 if (value.indexOf("=>") >= 0) {
403 action.throwValidationError(messages -> {
404 messages.addErrorsInvalidStrIsIncluded(propertyName, value, "=>");
405 }, hook);
406 }
407 }
408 }
409
410 private static String[] splitLine(final String value) {
411 if (StringUtil.isBlank(value)) {
412 return StringUtil.EMPTY_STRINGS;
413 }
414 final String[] values = value.split("[\r\n]");
415 final List<String> list = new ArrayList<>(values.length);
416 for (final String line : values) {
417 if (StringUtil.isNotBlank(line)) {
418 list.add(line.trim());
419 }
420 }
421 return list.toArray(new String[list.size()]);
422 }
423
424
425
426
427
428 protected HtmlResponse asDictIndexHtml() {
429 return redirect(AdminDictAction.class);
430 }
431
432 private HtmlResponse asListHtml(final String dictId) {
433 return asHtml(path_AdminDictMapping_AdminDictMappingJsp).renderWith(data -> {
434 RenderDataUtil.register(data, "charMappingItemItems", charMappingService.getCharMappingList(dictId, charMappingPager));
435 }).useForm(SearchForm.class, setup -> {
436 setup.setup(form -> {
437 copyBeanToBean(charMappingPager, form, op -> op.include("id"));
438 });
439 });
440 }
441
442 private HtmlResponse asEditHtml() {
443 return asHtml(path_AdminDictMapping_AdminDictMappingEditJsp);
444 }
445
446 private HtmlResponse asDetailsHtml() {
447 return asHtml(path_AdminDictMapping_AdminDictMappingDetailsJsp);
448 }
449
450 }