1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.app.web.admin.wizard;
17
18 import java.io.UnsupportedEncodingException;
19 import java.net.URLEncoder;
20 import java.util.List;
21
22 import org.apache.commons.lang3.StringUtils;
23 import org.apache.logging.log4j.LogManager;
24 import org.apache.logging.log4j.Logger;
25 import org.codelibs.core.lang.StringUtil;
26 import org.codelibs.core.misc.DynamicProperties;
27 import org.codelibs.fess.Constants;
28 import org.codelibs.fess.annotation.Secured;
29 import org.codelibs.fess.app.service.FileConfigService;
30 import org.codelibs.fess.app.service.ScheduledJobService;
31 import org.codelibs.fess.app.service.WebConfigService;
32 import org.codelibs.fess.app.web.base.FessAdminAction;
33 import org.codelibs.fess.crawler.util.CharUtil;
34 import org.codelibs.fess.helper.ProcessHelper;
35 import org.codelibs.fess.opensearch.config.exentity.FileConfig;
36 import org.codelibs.fess.opensearch.config.exentity.ScheduledJob;
37 import org.codelibs.fess.opensearch.config.exentity.WebConfig;
38 import org.codelibs.fess.util.ComponentUtil;
39 import org.lastaflute.job.JobManager;
40 import org.lastaflute.job.key.LaJobUnique;
41 import org.lastaflute.web.Execute;
42 import org.lastaflute.web.response.HtmlResponse;
43 import org.lastaflute.web.ruts.process.ActionRuntime;
44
45 import jakarta.annotation.Resource;
46
47
48
49
50
51 public class AdminWizardAction extends FessAdminAction {
52
53
54
55
56 public AdminWizardAction() {
57 super();
58 }
59
60
61 public static final String ROLE = "admin-wizard";
62
63
64
65
66 private static final Logger logger = LogManager.getLogger(AdminWizardAction.class);
67
68
69
70
71
72 @Resource
73 protected DynamicProperties systemProperties;
74
75
76 @Resource
77 protected WebConfigService webConfigService;
78
79
80 @Resource
81 protected FileConfigService fileConfigService;
82
83
84 @Resource
85 protected ProcessHelper processHelper;
86
87
88 @Resource
89 protected ScheduledJobService scheduledJobService;
90
91
92
93
94 @Override
95 protected void setupHtmlData(final ActionRuntime runtime) {
96 super.setupHtmlData(runtime);
97 runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNameWizard()));
98 }
99
100 @Override
101 protected String getActionRole() {
102 return ROLE;
103 }
104
105
106
107
108
109
110
111
112
113
114 @Execute
115 @Secured({ ROLE, ROLE + VIEW })
116 public HtmlResponse index() {
117 return asIndexHtml();
118 }
119
120 private HtmlResponse asIndexHtml() {
121 return asHtml(path_AdminWizard_AdminWizardJsp).useForm(IndexForm.class);
122 }
123
124
125
126
127
128
129 @Execute
130 @Secured({ ROLE })
131 public HtmlResponse crawlingConfigForm() {
132 saveToken();
133 return asHtml(path_AdminWizard_AdminWizardConfigJsp).useForm(CrawlingConfigForm.class);
134 }
135
136
137
138
139
140
141
142 @Execute
143 @Secured({ ROLE })
144 public HtmlResponse crawlingConfig(final CrawlingConfigForm form) {
145 validate(form, messages -> {}, () -> asHtml(path_AdminWizard_AdminWizardConfigJsp));
146 verifyTokenKeep(this::asIndexHtml);
147 final String name = crawlingConfigInternal(form);
148 saveInfo(messages -> messages.addSuccessCreateCrawlingConfigAtWizard(GLOBAL, name));
149 return redirectWith(getClass(), moreUrl("crawlingConfigForm"));
150 }
151
152
153
154
155
156
157
158 @Execute
159 @Secured({ ROLE })
160 public HtmlResponse crawlingConfigNext(final CrawlingConfigForm form) {
161 validate(form, messages -> {}, () -> asHtml(path_AdminWizard_AdminWizardConfigJsp));
162 verifyToken(this::asIndexHtml);
163 final String name = crawlingConfigInternal(form);
164 saveInfo(messages -> messages.addSuccessCreateCrawlingConfigAtWizard(GLOBAL, name));
165 return redirectWith(getClass(), moreUrl("startCrawlingForm"));
166 }
167
168
169
170
171
172
173
174
175 protected String crawlingConfigInternal(final CrawlingConfigForm form) {
176
177 String configName = form.crawlingConfigName;
178 String configPath = form.crawlingConfigPath.trim();
179 if (StringUtil.isBlank(configName)) {
180 configName = StringUtils.abbreviate(configPath, 30);
181 }
182
183
184 final StringBuilder buf = new StringBuilder(1000);
185 for (int i = 0; i < configPath.length(); i++) {
186 final char c = configPath.charAt(i);
187 if (c == '\\') {
188 buf.append('/');
189 } else if (c == ' ') {
190 buf.append("%20");
191 } else if (CharUtil.isUrlChar(c)) {
192 buf.append(c);
193 } else {
194 try {
195 buf.append(URLEncoder.encode(String.valueOf(c), Constants.UTF_8));
196 } catch (final UnsupportedEncodingException e) {
197
198 logger.warn("UTF-8 encoding not supported - this should not happen: char={}", c, e);
199 }
200 }
201 }
202 configPath = convertCrawlingPath(buf.toString());
203
204 final String username = systemHelper.getUsername();
205 final long now = systemHelper.getCurrentTimeAsLong();
206
207 try {
208 if (isWebCrawlingPath(configPath)) {
209
210 final WebConfig wConfig = new WebConfig();
211 wConfig.setAvailable(Constants.T);
212 wConfig.setBoost(1.0f);
213 wConfig.setCreatedBy(username);
214 wConfig.setCreatedTime(now);
215 if (form.depth != null) {
216 wConfig.setDepth(form.depth);
217 }
218 wConfig.setExcludedDocUrls(getDefaultString("default.config.web.excludedDocUrls", StringUtil.EMPTY));
219 wConfig.setExcludedUrls(getDefaultString("default.config.web.excludedUrls",
220 fessConfig.getCrawlerDocumentHtmlDefaultExcludeIndexPatterns()));
221 wConfig.setIncludedDocUrls(getDefaultString("default.config.web.includedDocUrls", StringUtil.EMPTY));
222 wConfig.setIncludedUrls(getDefaultString("default.config.web.includedUrls", StringUtil.EMPTY));
223 wConfig.setIntervalTime(getDefaultInteger("default.config.web.intervalTime", Constants.DEFAULT_INTERVAL_TIME_FOR_WEB));
224 if (form.maxAccessCount != null) {
225 wConfig.setMaxAccessCount(form.maxAccessCount);
226 }
227 wConfig.setName(configName);
228 wConfig.setNumOfThread(getDefaultInteger("default.config.web.numOfThread", Constants.DEFAULT_NUM_OF_THREAD_FOR_WEB));
229 wConfig.setSortOrder(getDefaultInteger("default.config.web.sortOrder", 1));
230 wConfig.setUpdatedBy(username);
231 wConfig.setUpdatedTime(now);
232 wConfig.setUrls(configPath);
233 wConfig.setUserAgent(getDefaultString("default.config.web.userAgent", fessConfig.getUserAgentName()));
234 wConfig.setPermissions(ComponentUtil.getFessConfig().getSearchDefaultDisplayEncodedPermissions());
235
236 webConfigService.store(wConfig);
237
238 } else {
239
240 final FileConfig fConfig = new FileConfig();
241 fConfig.setAvailable(Constants.T);
242 fConfig.setBoost(1.0f);
243 fConfig.setCreatedBy(username);
244 fConfig.setCreatedTime(now);
245 if (form.depth != null) {
246 fConfig.setDepth(form.depth);
247 }
248 fConfig.setExcludedDocPaths(getDefaultString("default.config.file.excludedDocPaths", StringUtil.EMPTY));
249 fConfig.setExcludedPaths(getDefaultString("default.config.file.excludedPaths", StringUtil.EMPTY));
250 fConfig.setIncludedDocPaths(getDefaultString("default.config.file.includedDocPaths", StringUtil.EMPTY));
251 fConfig.setIncludedPaths(getDefaultString("default.config.file.includedPaths", StringUtil.EMPTY));
252 fConfig.setIntervalTime(getDefaultInteger("default.config.file.intervalTime", Constants.DEFAULT_INTERVAL_TIME_FOR_FS));
253 if (form.maxAccessCount != null) {
254 fConfig.setMaxAccessCount(form.maxAccessCount);
255 }
256 fConfig.setName(configName);
257 fConfig.setNumOfThread(getDefaultInteger("default.config.file.numOfThread", Constants.DEFAULT_NUM_OF_THREAD_FOR_FS));
258 fConfig.setSortOrder(getDefaultInteger("default.config.file.sortOrder", 1));
259 fConfig.setUpdatedBy(username);
260 fConfig.setUpdatedTime(now);
261 fConfig.setPaths(configPath);
262 fConfig.setPermissions(ComponentUtil.getFessConfig().getSearchDefaultDisplayEncodedPermissions());
263
264 fileConfigService.store(fConfig);
265 }
266 return configName;
267 } catch (final Exception e) {
268 logger.warn("Failed to create crawling config: {}", form.crawlingConfigPath, e);
269 throwValidationError(messages -> messages.addErrorsFailedToCreateCrawlingConfigAtWizard(GLOBAL),
270 () -> asHtml(path_AdminWizard_AdminWizardConfigJsp));
271 return null;
272 }
273 }
274
275
276
277
278
279
280
281
282 protected Integer getDefaultInteger(final String key, final Integer defaultValue) {
283 final String value = systemProperties.getProperty(key);
284 if (value != null) {
285 try {
286 return Integer.parseInt(value);
287 } catch (final NumberFormatException e) {
288 if (logger.isDebugEnabled()) {
289 logger.debug("Invalid integer property value, using default: key={}, value={}, default={}", key, value, defaultValue);
290 }
291 }
292 }
293 return defaultValue;
294 }
295
296
297
298
299
300
301
302
303 protected Long getDefaultLong(final String key, final Long defaultValue) {
304 final String value = systemProperties.getProperty(key);
305 if (value != null) {
306 try {
307 return Long.parseLong(value);
308 } catch (final NumberFormatException e) {
309 if (logger.isDebugEnabled()) {
310 logger.debug("Invalid long property value, using default: key={}, value={}, default={}", key, value, defaultValue);
311 }
312 }
313 }
314 return defaultValue;
315 }
316
317
318
319
320
321
322
323
324 protected String getDefaultString(final String key, final String defaultValue) {
325 final String value = systemProperties.getProperty(key);
326 if (value != null) {
327 return value;
328 }
329 return defaultValue;
330 }
331
332
333
334
335
336
337
338
339 protected boolean isWebCrawlingPath(final String path) {
340 if (path.startsWith("http:") || path.startsWith("https:")) {
341 return true;
342 }
343
344 return false;
345 }
346
347
348
349
350
351
352
353
354 protected String convertCrawlingPath(final String path) {
355 if (ComponentUtil.getProtocolHelper().hasKnownProtocol(path)) {
356 return path;
357 }
358
359 if (path.startsWith("www.")) {
360 return "http://" + path;
361 }
362
363 if (path.startsWith("//")) {
364 return "file://" + path;
365 }
366 if (path.startsWith("/")) {
367 return "file:" + path;
368 }
369 if (!path.startsWith("file:")) {
370 return "file:/" + path.replace('\\', '/');
371 }
372 return path;
373 }
374
375
376
377
378
379
380 @Execute
381 @Secured({ ROLE })
382 public HtmlResponse startCrawlingForm() {
383 saveToken();
384 return asHtml(path_AdminWizard_AdminWizardStartJsp).useForm(StartCrawlingForm.class);
385 }
386
387
388
389
390
391
392
393 @Execute
394 @Secured({ ROLE })
395 public HtmlResponse startCrawling(final StartCrawlingForm form) {
396 verifyToken(this::asIndexHtml);
397 if (!processHelper.isProcessRunning()) {
398 final List<ScheduledJob> scheduledJobList = scheduledJobService.getCrawlerJobList();
399 final JobManager jobManager = ComponentUtil.getJobManager();
400 for (final ScheduledJob scheduledJob : scheduledJobList) {
401 jobManager.findJobByUniqueOf(LaJobUnique.of(scheduledJob.getId())).ifPresent(job -> {
402 job.launchNow();
403 });
404 }
405 saveInfo(messages -> messages.addSuccessStartCrawlProcess(GLOBAL));
406 } else {
407 saveError(messages -> messages.addErrorsFailedToStartCrawlProcess(GLOBAL));
408 }
409 return redirect(AdminWizardAction.class);
410 }
411 }