1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.mylasta.direction;
17
18 import static org.codelibs.core.stream.StreamUtil.split;
19 import static org.codelibs.core.stream.StreamUtil.stream;
20
21 import java.net.Authenticator;
22 import java.net.InetSocketAddress;
23 import java.net.PasswordAuthentication;
24 import java.net.Proxy;
25 import java.net.Proxy.Type;
26 import java.net.SocketAddress;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collections;
30 import java.util.Date;
31 import java.util.Enumeration;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Locale;
36 import java.util.Map;
37 import java.util.Set;
38 import java.util.concurrent.ConcurrentHashMap;
39 import java.util.regex.Pattern;
40 import java.util.stream.Collectors;
41 import java.util.stream.Stream;
42
43 import javax.naming.directory.Attribute;
44 import javax.naming.directory.BasicAttribute;
45
46 import org.codelibs.core.exception.ClassNotFoundRuntimeException;
47 import org.codelibs.core.lang.StringUtil;
48 import org.codelibs.core.misc.Pair;
49 import org.codelibs.core.misc.Tuple3;
50 import org.codelibs.core.misc.Tuple4;
51 import org.codelibs.fesen.search.sort.SortBuilder;
52 import org.codelibs.fesen.search.sort.SortBuilders;
53 import org.codelibs.fesen.search.sort.SortOrder;
54 import org.codelibs.fess.Constants;
55 import org.codelibs.fess.helper.PermissionHelper;
56 import org.codelibs.fess.mylasta.action.FessUserBean;
57 import org.codelibs.fess.taglib.FessFunctions;
58 import org.codelibs.fess.util.ComponentUtil;
59 import org.codelibs.fess.util.JvmUtil;
60 import org.codelibs.fess.util.PrunedTag;
61 import org.dbflute.optional.OptionalThing;
62 import org.dbflute.util.DfTypeUtil;
63 import org.lastaflute.job.LaJob;
64 import org.lastaflute.job.subsidiary.JobConcurrentExec;
65 import org.lastaflute.web.validation.RequiredValidator;
66 import org.lastaflute.web.validation.theme.typed.DoubleTypeValidator;
67 import org.lastaflute.web.validation.theme.typed.FloatTypeValidator;
68 import org.lastaflute.web.validation.theme.typed.IntegerTypeValidator;
69 import org.lastaflute.web.validation.theme.typed.LongTypeValidator;
70
71 public interface FessProp {
72
73 String QUERY_HIGHLIGHT_TERMINAL_CHARS = "queryHighlightTerminalChars";
74
75 String QUERY_HIGHLIGHT_BOUNDARY_CHARS = "queryHighlightBoundaryChars";
76
77 String QUERY_TRACK_TOTAL_HITS_VALUE = "queryTrackTotalHitsValue";
78
79 String CORS_ALLOW_ORIGIN = "CorsAllowOrigin";
80
81 String API_DASHBOARD_RESPONSE_HEADER_LIST = "apiDashboardResponseHeaderList";
82
83 String API_JSON_RESPONSE_HEADER_LIST = "apiJsonResponseHeaderList";
84
85 String API_GSA_RESPONSE_HEADER_LIST = "apiGsaResponseHeaderList";
86
87 String SMB_AVAILABLE_SID_TYPES = "smbAvailableSidTypes";
88
89 String LOGGING_SEARCH_DOCS_FIELDS = "loggingSearchDocsFields";
90
91 String API_SEARCH_ACCEPT_REFERERS = "apiSearchAcceptReferers";
92
93 String QUERY_GSA_RESPONSE_FIELDS = "queryGsaResponseFields";
94
95 String THUMBNAIL_HTML_IMAGE_EXCLUDE_EXTENSIONS = "ThumbnailHtmlImageExcludeExtensions";
96
97 String VIRTUAL_HOST_VALUE = "VirtualHostValue";
98
99 String QUERY_DEFAULT_LANGUAGES = "queryDefaultLanguages";
100
101 String HTML_PROXY = "httpProxy";
102
103 String CRAWLER_FAILURE_URL_STATUS_CODES = "crawlerFailureUrlStatusCodes";
104
105 String VIRTUAL_HOST_HEADERS = "virtualHostHeaders";
106
107 String QUERY_COLLAPSE_INNER_HITS_SORTS = "queryCollapseInnerHitsSorts";
108
109 String USER_CODE_PATTERN = "userCodePattern";
110
111 String API_ADMIN_ACCESS_PERMISSION_SET = "apiAdminAccessPermissionSet";
112
113 String CRAWLER_DOCUMENT_SPACE_CHARS = "crawlerDocumentSpaceChars";
114
115 String CRAWLER_DOCUMENT_SPACES = "crawlerDocumentSpaces";
116
117 String CRAWLER_DOCUMENT_FULLSTOP_CHARS = "crawlerDocumentFullstopChars";
118
119 String INDEX_ADMIN_ARRAY_FIELD_SET = "indexAdminArrayFieldSet";
120
121 String INDEX_ADMIN_DATE_FIELD_SET = "indexAdminDateFieldSet";
122
123 String INDEX_ADMIN_INTEGER_FIELD_SET = "indexAdminIntegerFieldSet";
124
125 String INDEX_ADMIN_LONG_FIELD_SET = "indexAdminLongFieldSet";
126
127 String INDEX_ADMIN_FLOAT_FIELD_SET = "indexAdminFloatFieldSet";
128
129 String INDEX_ADMIN_DOUBLE_FIELD_SET = "indexAdminDoubleFieldSet";
130
131 String AUTHENTICATION_ADMIN_ROLES = "authenticationAdminRoles";
132
133 String SEARCH_GUEST_PERMISSION_LIST = "searchGuestPermissionList";
134
135 String SUGGEST_SEARCH_LOG_PERMISSIONS = "suggestSearchLogPermissions";
136
137 String GROUP_VALUE_PREFIX = "group:";
138
139 String ROLE_VALUE_PREFIX = "role:";
140
141 String APP_VALUES = "appValues";
142
143 String DEFAULT_SORT_VALUES = "defaultSortValues";
144
145 String DEFAULT_LABEL_VALUES = "defaultLabelValues";
146
147 String VIRTUAL_HOST_VALUES = "virtualHostValues";
148
149 String QUERY_LANGUAGE_MAPPING = "queryLanguageMapping";
150
151 String CRAWLER_METADATA_NAME_MAPPING = "crawlerMetadataNameMapping";
152
153 String CRAWLER_METADATA_CONTENT_EXCLUDES = "crawlerMetadataContentExcludes";
154
155 Map<String, Object> propMap = new ConcurrentHashMap<>();
156
157
158
159
160
161 default void storeSystemProperties() {
162 ComponentUtil.getSystemProperties().store();
163 }
164
165 default String getSystemProperty(final String key) {
166 return ComponentUtil.getSystemProperties().getProperty(key, System.getProperty(Constants.SYSTEM_PROP_PREFIX + key));
167 }
168
169 default String getSystemProperty(final String key, final String defaultValue) {
170 return ComponentUtil.getSystemProperties().getProperty(key, System.getProperty(Constants.SYSTEM_PROP_PREFIX + key, defaultValue));
171 }
172
173 default void setSystemProperty(final String key, final String value) {
174 if (value != null) {
175 ComponentUtil.getSystemProperties().setProperty(key, value);
176 } else {
177 ComponentUtil.getSystemProperties().remove(key);
178 }
179 }
180
181 default boolean getSystemPropertyAsBoolean(final String key, final boolean defaultValue) {
182 return Constants.TRUE.equalsIgnoreCase(getSystemProperty(key, defaultValue ? Constants.TRUE : Constants.FALSE));
183 }
184
185 default void setSystemPropertyAsBoolean(final String key, final boolean value) {
186 setSystemProperty(key, value ? Constants.TRUE : Constants.FALSE);
187 }
188
189 default int getSystemPropertyAsInt(final String key, final int defaultValue) {
190 final String value = getSystemProperty(key);
191 if (value != null) {
192 try {
193 return Integer.parseInt(value);
194 } catch (final NumberFormatException e) {
195
196 }
197 }
198 return defaultValue;
199 }
200
201 default void setSystemPropertyAsInt(final String key, final int value) {
202 setSystemProperty(key, Integer.toString(value));
203 }
204
205 default boolean isSearchFileProxyEnabled() {
206 return getSystemPropertyAsBoolean(Constants.SEARCH_FILE_PROXY_PROPERTY, true);
207 }
208
209 default boolean isBrowserLocaleForSearchUsed() {
210 return getSystemPropertyAsBoolean(Constants.USE_BROWSER_LOCALE_FOR_SEARCH_PROPERTY, false);
211 }
212
213 default String[] getDefaultSortValues(final OptionalThing<FessUserBean> userBean) {
214 @SuppressWarnings("unchecked")
215 List<Pair<String, String>> list = (List<Pair<String, String>>) propMap.get(DEFAULT_SORT_VALUES);
216 if (list == null) {
217 final String value = getSystemProperty(Constants.DEFAULT_SORT_VALUE_PROPERTY);
218 if (StringUtil.isBlank(value)) {
219 list = Collections.emptyList();
220 } else {
221 final Set<String> keySet = new HashSet<>();
222 list = split(value, "\n").get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> {
223 final String[] pair = s.split("=");
224 if (pair.length == 1) {
225 return new Pair<>(StringUtil.EMPTY, pair[0].trim());
226 }
227 if (pair.length == 2) {
228 String sortValue = pair[1].trim();
229 if (StringUtil.isBlank(sortValue) || "score".equals(sortValue)) {
230 sortValue = "score.desc";
231 }
232 return new Pair<>(pair[0].trim(), sortValue);
233 }
234 return null;
235 }).filter(o -> o != null && keySet.add(o.getFirst())).collect(Collectors.toList()));
236 }
237 propMap.put(DEFAULT_SORT_VALUES, list);
238 }
239 return list.stream().map(p -> {
240 final String key = p.getFirst();
241 if (StringUtil.isEmpty(key)) {
242 return p.getSecond();
243 }
244 if (userBean
245 .map(user -> stream(user.getRoles()).get(stream -> stream.anyMatch(s -> (ROLE_VALUE_PREFIX + s).equals(key)))
246 || stream(user.getGroups()).get(stream -> stream.anyMatch(s -> (GROUP_VALUE_PREFIX + s).equals(key))))
247 .orElse(false)) {
248 return p.getSecond();
249 }
250 return null;
251 }).filter(StringUtil::isNotBlank).toArray(n -> new String[n]);
252 }
253
254 default void setDefaultSortValue(final String value) {
255 setSystemProperty(Constants.DEFAULT_SORT_VALUE_PROPERTY, value);
256 propMap.remove(DEFAULT_SORT_VALUES);
257 }
258
259 default String getDefaultSortValue() {
260 return getSystemProperty(Constants.DEFAULT_SORT_VALUE_PROPERTY, StringUtil.EMPTY);
261 }
262
263 default String[] getDefaultLabelValues(final OptionalThing<FessUserBean> userBean) {
264 @SuppressWarnings("unchecked")
265 Map<String, List<String>> map = (Map<String, List<String>>) propMap.get(DEFAULT_LABEL_VALUES);
266 if (map == null) {
267 final String value = getSystemProperty(Constants.DEFAULT_LABEL_VALUE_PROPERTY);
268 if (StringUtil.isBlank(value)) {
269 map = Collections.emptyMap();
270 } else {
271 final Set<String> keySet = new HashSet<>();
272 map = split(value, "\n").get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> {
273 final String[] pair = s.split("=");
274 if (pair.length == 1) {
275 return new Pair<>(StringUtil.EMPTY, pair[0].trim());
276 }
277 if (pair.length == 2) {
278 return new Pair<>(pair[0].trim(), pair[1].trim());
279 }
280 return null;
281 }).filter(o -> o != null && keySet.add(o.getFirst())).collect(HashMap<String, List<String>>::new,
282 (m, d) -> m.put(d.getFirst(), Arrays.asList(d.getSecond().split(","))), HashMap::putAll));
283 }
284 propMap.put(DEFAULT_LABEL_VALUES, map);
285 }
286 return map.entrySet().stream().flatMap(e -> {
287 final String key = e.getKey();
288 if (StringUtil.isEmpty(key)) {
289 return e.getValue().stream();
290 }
291 if (userBean
292 .map(user -> stream(user.getRoles()).get(stream -> stream.anyMatch(s -> (ROLE_VALUE_PREFIX + s).equals(key)))
293 || stream(user.getGroups()).get(stream -> stream.anyMatch(s -> (GROUP_VALUE_PREFIX + s).equals(key))))
294 .orElse(false)) {
295 return e.getValue().stream();
296 }
297 return Stream.empty();
298 }).filter(StringUtil::isNotBlank).toArray(n -> new String[n]);
299 }
300
301 default void setAppValue(final String value) {
302 setSystemProperty(Constants.APP_VALUE_PROPERTY, value);
303 propMap.remove(APP_VALUES);
304 }
305
306 default String getAppValue() {
307 return getSystemProperty(Constants.APP_VALUE_PROPERTY, StringUtil.EMPTY);
308 }
309
310 default void setDefaultLabelValue(final String value) {
311 setSystemProperty(Constants.DEFAULT_LABEL_VALUE_PROPERTY, value);
312 propMap.remove(DEFAULT_LABEL_VALUES);
313 }
314
315 default String getDefaultLabelValue() {
316 return getSystemProperty(Constants.DEFAULT_LABEL_VALUE_PROPERTY, StringUtil.EMPTY);
317 }
318
319 default void setVirtualHostValue(final String value) {
320 setSystemProperty(Constants.VIRTUAL_HOST_VALUE_PROPERTY, value);
321 propMap.remove(VIRTUAL_HOST_HEADERS);
322 }
323
324 default String getVirtualHostValue() {
325 return getSystemProperty(Constants.VIRTUAL_HOST_VALUE_PROPERTY, getVirtualHostHeaders());
326 }
327
328 default void setLoginRequired(final boolean value) {
329 setSystemPropertyAsBoolean(Constants.LOGIN_REQUIRED_PROPERTY, value);
330 }
331
332 default boolean isLoginRequired() {
333 return getSystemPropertyAsBoolean(Constants.LOGIN_REQUIRED_PROPERTY, false);
334 }
335
336 default void setResultCollapsed(final boolean value) {
337 setSystemPropertyAsBoolean(Constants.RESULT_COLLAPSED_PROPERTY, value);
338 }
339
340 default boolean isResultCollapsed() {
341 switch (getFesenType()) {
342 case Constants.FESEN_TYPE_CLOUD:
343 case Constants.FESEN_TYPE_AWS:
344 return false;
345 default:
346 return getSystemPropertyAsBoolean(Constants.RESULT_COLLAPSED_PROPERTY, false);
347 }
348 }
349
350 default void setLoginLinkEnabled(final boolean value) {
351 setSystemPropertyAsBoolean(Constants.LOGIN_LINK_ENALBED_PROPERTY, value);
352 }
353
354 default boolean isLoginLinkEnabled() {
355 return getSystemPropertyAsBoolean(Constants.LOGIN_LINK_ENALBED_PROPERTY, true);
356 }
357
358 default void setThumbnailEnabled(final boolean value) {
359 setSystemPropertyAsBoolean(Constants.THUMBNAIL_ENALBED_PROPERTY, value);
360 }
361
362 default boolean isThumbnailEnabled() {
363 return getSystemPropertyAsBoolean(Constants.THUMBNAIL_ENALBED_PROPERTY, false);
364 }
365
366 default void setIncrementalCrawling(final boolean value) {
367 setSystemPropertyAsBoolean(Constants.INCREMENTAL_CRAWLING_PROPERTY, value);
368 }
369
370 default boolean isIncrementalCrawling() {
371 return getSystemPropertyAsBoolean(Constants.INCREMENTAL_CRAWLING_PROPERTY, true);
372 }
373
374 default void setDayForCleanup(final int value) {
375 setSystemPropertyAsInt(Constants.DAY_FOR_CLEANUP_PROPERTY, value);
376 }
377
378 default int getDayForCleanup() {
379 return getSystemPropertyAsInt(Constants.DAY_FOR_CLEANUP_PROPERTY, Constants.DEFAULT_DAY_FOR_CLEANUP);
380 }
381
382 default void setCrawlingThreadCount(final int value) {
383 setSystemPropertyAsInt(Constants.CRAWLING_THREAD_COUNT_PROPERTY, value);
384 }
385
386 default int getCrawlingThreadCount() {
387 return getSystemPropertyAsInt(Constants.CRAWLING_THREAD_COUNT_PROPERTY, 5);
388 }
389
390 default void setSearchLog(final boolean value) {
391 setSystemPropertyAsBoolean(Constants.SEARCH_LOG_PROPERTY, value);
392 }
393
394 default boolean isSearchLog() {
395 return getSystemPropertyAsBoolean(Constants.SEARCH_LOG_PROPERTY, true);
396 }
397
398 default void setUserInfo(final boolean value) {
399 setSystemPropertyAsBoolean(Constants.USER_INFO_PROPERTY, value);
400 }
401
402 default boolean isUserInfo() {
403 return getSystemPropertyAsBoolean(Constants.USER_INFO_PROPERTY, true);
404 }
405
406 default void setUserFavorite(final boolean value) {
407 setSystemPropertyAsBoolean(Constants.USER_FAVORITE_PROPERTY, value);
408 }
409
410 default boolean isUserFavorite() {
411 return getSystemPropertyAsBoolean(Constants.USER_FAVORITE_PROPERTY, false);
412 }
413
414 default void setWebApiJson(final boolean value) {
415 setSystemPropertyAsBoolean(Constants.WEB_API_JSON_PROPERTY, value);
416 }
417
418 default boolean isWebApiJson() {
419 return getSystemPropertyAsBoolean(Constants.WEB_API_JSON_PROPERTY, true);
420 }
421
422 default boolean isWebApiGsa() {
423 return getSystemPropertyAsBoolean(Constants.WEB_API_GSA_PROPERTY, false);
424 }
425
426 default void setAppendQueryParameter(final boolean value) {
427 setSystemPropertyAsBoolean(Constants.APPEND_QUERY_PARAMETER_PROPERTY, value);
428 }
429
430 default boolean isAppendQueryParameter() {
431 return getSystemPropertyAsBoolean(Constants.APPEND_QUERY_PARAMETER_PROPERTY, false);
432 }
433
434 default void setIgnoreFailureType(final String value) {
435 setSystemProperty(Constants.IGNORE_FAILURE_TYPE_PROPERTY, value);
436 }
437
438 default String getIgnoreFailureType() {
439 return getSystemProperty(Constants.IGNORE_FAILURE_TYPE_PROPERTY, Constants.DEFAULT_IGNORE_FAILURE_TYPE);
440 }
441
442 default void setFailureCountThreshold(final int value) {
443 setSystemPropertyAsInt(Constants.FAILURE_COUNT_THRESHOLD_PROPERTY, value);
444 }
445
446 default int getFailureCountThreshold() {
447 return getSystemPropertyAsInt(Constants.FAILURE_COUNT_THRESHOLD_PROPERTY, Constants.DEFAULT_FAILURE_COUNT);
448 }
449
450 default void setWebApiPopularWord(final boolean value) {
451 setSystemPropertyAsBoolean(Constants.WEB_API_POPULAR_WORD_PROPERTY, value);
452 }
453
454 default boolean isWebApiPopularWord() {
455 return getSystemPropertyAsBoolean(Constants.WEB_API_POPULAR_WORD_PROPERTY, true);
456 }
457
458 default void setCsvFileEncoding(final String value) {
459 setSystemProperty(Constants.CSV_FILE_ENCODING_PROPERTY, value);
460 }
461
462 default String getCsvFileEncoding() {
463 return getSystemProperty(Constants.CSV_FILE_ENCODING_PROPERTY, Constants.UTF_8);
464 }
465
466 default void setPurgeSearchLogDay(final int value) {
467 setSystemPropertyAsInt(Constants.PURGE_SEARCH_LOG_DAY_PROPERTY, value);
468 }
469
470 default int getPurgeSearchLogDay() {
471 return getSystemPropertyAsInt(Constants.PURGE_SEARCH_LOG_DAY_PROPERTY, DfTypeUtil.toInteger(Constants.DEFAULT_PURGE_DAY));
472 }
473
474 default void setPurgeJobLogDay(final int value) {
475 setSystemPropertyAsInt(Constants.PURGE_JOB_LOG_DAY_PROPERTY, value);
476 }
477
478 default int getPurgeJobLogDay() {
479 return getSystemPropertyAsInt(Constants.PURGE_JOB_LOG_DAY_PROPERTY, DfTypeUtil.toInteger(Constants.DEFAULT_PURGE_DAY));
480 }
481
482 default void setPurgeUserInfoDay(final int value) {
483 setSystemPropertyAsInt(Constants.PURGE_USER_INFO_DAY_PROPERTY, value);
484 }
485
486 default int getPurgeUserInfoDay() {
487 return getSystemPropertyAsInt(Constants.PURGE_USER_INFO_DAY_PROPERTY, DfTypeUtil.toInteger(Constants.DEFAULT_PURGE_DAY));
488 }
489
490 default void setPurgeByBots(final String value) {
491 setSystemProperty(Constants.PURGE_BY_BOTS_PROPERTY, value);
492 }
493
494 default String getPurgeByBots() {
495 return getSystemProperty(Constants.PURGE_BY_BOTS_PROPERTY, Constants.DEFAULT_PURGE_BY_BOTS);
496 }
497
498 default boolean hasNotification() {
499 return StringUtil.isNotBlank(getNotificationTo()) || StringUtil.isNotBlank(getSlackWebhookUrls());
500 }
501
502 default void setSlackWebhookUrls(final String value) {
503 setSystemProperty(Constants.SLACK_WEBHOOK_URLS_PROPERTY, value);
504 }
505
506 default String getSlackWebhookUrls() {
507 return getSystemProperty(Constants.SLACK_WEBHOOK_URLS_PROPERTY, StringUtil.EMPTY);
508 }
509
510 default void setGoogleChatWebhookUrls(final String value) {
511 setSystemProperty(Constants.GOOGLE_CHAT_WEBHOOK_URLS_PROPERTY, value);
512 }
513
514 default String getGoogleChatWebhookUrls() {
515 return getSystemProperty(Constants.GOOGLE_CHAT_WEBHOOK_URLS_PROPERTY, StringUtil.EMPTY);
516 }
517
518 default void setNotificationTo(final String value) {
519 setSystemProperty(Constants.NOTIFICATION_TO_PROPERTY, value);
520 }
521
522 default String getNotificationTo() {
523 return getSystemProperty(Constants.NOTIFICATION_TO_PROPERTY, StringUtil.EMPTY);
524 }
525
526 default void setSuggestSearchLog(final boolean value) {
527 setSystemPropertyAsBoolean(Constants.SUGGEST_SEARCH_LOG_PROPERTY, value);
528 }
529
530 default boolean isSuggestSearchLog() {
531 return getSystemPropertyAsBoolean(Constants.SUGGEST_SEARCH_LOG_PROPERTY, true);
532 }
533
534 default void setSuggestDocuments(final boolean value) {
535 setSystemPropertyAsBoolean(Constants.SUGGEST_DOCUMENTS_PROPERTY, value);
536 }
537
538 default boolean isSuggestDocuments() {
539 return getSystemPropertyAsBoolean(Constants.SUGGEST_DOCUMENTS_PROPERTY, true);
540 }
541
542 default void setPurgeSuggestSearchLogDay(final int value) {
543 setSystemPropertyAsInt(Constants.PURGE_SUGGEST_SEARCH_LOG_DAY_PROPERTY, value);
544 }
545
546 default int getPurgeSuggestSearchLogDay() {
547 return getSystemPropertyAsInt(Constants.PURGE_SUGGEST_SEARCH_LOG_DAY_PROPERTY,
548 DfTypeUtil.toInteger(Constants.DEFAULT_SUGGEST_PURGE_DAY));
549 }
550
551 default void setLdapInitialContextFactory(final String value) {
552 setSystemProperty(Constants.LDAP_INITIAL_CONTEXT_FACTORY, value);
553 }
554
555 default String getLdapInitialContextFactory() {
556 return getSystemProperty(Constants.LDAP_INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
557 }
558
559 default void setLdapSecurityAuthentication(final String value) {
560 setSystemProperty(Constants.LDAP_SECURITY_AUTHENTICATION, value);
561 }
562
563 default String getLdapSecurityAuthentication() {
564 return getSystemProperty(Constants.LDAP_SECURITY_AUTHENTICATION, "simple");
565 }
566
567 default void setLdapProviderUrl(final String value) {
568 setSystemProperty(Constants.LDAP_PROVIDER_URL, value);
569 }
570
571 default String getLdapProviderUrl() {
572 return getSystemProperty(Constants.LDAP_PROVIDER_URL);
573 }
574
575 default void setLdapSecurityPrincipal(final String value) {
576 setSystemProperty(Constants.LDAP_SECURITY_PRINCIPAL, value);
577 }
578
579 default String getLdapMemberofAttribute() {
580 return getSystemProperty(Constants.LDAP_MEMBEROF_ATTRIBUTE, "memberOf");
581 }
582
583 default void setLdapMemberofAttribute(final String value) {
584 setSystemProperty(Constants.LDAP_MEMBEROF_ATTRIBUTE, value);
585 }
586
587 default void setStorageEndpoint(final String value) {
588 setSystemProperty(Constants.STORAGE_ENDPOINT, value);
589 }
590
591 default String getStorageEndpoint() {
592 return getSystemProperty(Constants.STORAGE_ENDPOINT, StringUtil.EMPTY);
593 }
594
595 default void setStorageAccessKey(final String value) {
596 setSystemProperty(Constants.STORAGE_ACCESS_KEY, value);
597 }
598
599 default String getStorageAccessKey() {
600 return getSystemProperty(Constants.STORAGE_ACCESS_KEY, StringUtil.EMPTY);
601 }
602
603 default void setStorageSecretKey(final String value) {
604 setSystemProperty(Constants.STORAGE_SECRET_KEY, value);
605 }
606
607 default String getStorageSecretKey() {
608 return getSystemProperty(Constants.STORAGE_SECRET_KEY, StringUtil.EMPTY);
609 }
610
611 default void setStorageBucket(final String value) {
612 setSystemProperty(Constants.STORAGE_BUCKET, value);
613 }
614
615 default String getStorageBucket() {
616 return getSystemProperty(Constants.STORAGE_BUCKET, StringUtil.EMPTY);
617 }
618
619 Integer getLdapMaxUsernameLengthAsInteger();
620
621 default String getLdapSecurityPrincipal(final String username) {
622 final String value;
623 final int maxLength = getLdapMaxUsernameLengthAsInteger();
624 if (username == null) {
625 value = StringUtil.EMPTY;
626 } else if (maxLength >= 0 && username.length() > maxLength) {
627 value = username.substring(0, maxLength);
628 } else {
629 value = username;
630 }
631 return String.format(getSystemProperty(Constants.LDAP_SECURITY_PRINCIPAL, StringUtil.EMPTY), value);
632 }
633
634 default String getLdapSecurityPrincipal() {
635 return getSystemProperty(Constants.LDAP_SECURITY_PRINCIPAL);
636 }
637
638 default void setLdapAdminSecurityPrincipal(final String value) {
639 setSystemProperty(Constants.LDAP_ADMIN_SECURITY_PRINCIPAL, value);
640 }
641
642 default String getLdapAdminSecurityPrincipal() {
643 return getSystemProperty(Constants.LDAP_ADMIN_SECURITY_PRINCIPAL);
644 }
645
646 default void setLdapAdminSecurityCredentials(final String value) {
647 setSystemProperty(Constants.LDAP_ADMIN_SECURITY_CREDENTIALS,
648 Constants.CIPHER_PREFIX + ComponentUtil.getPrimaryCipher().encrypt(value));
649 }
650
651 default String getLdapAdminSecurityCredentials() {
652 final String value = getSystemProperty(Constants.LDAP_ADMIN_SECURITY_CREDENTIALS);
653 if (StringUtil.isNotBlank(value) && value.startsWith(Constants.CIPHER_PREFIX)) {
654 return ComponentUtil.getPrimaryCipher().decrypt(value.substring(Constants.CIPHER_PREFIX.length()));
655 }
656 return value;
657 }
658
659 default void setLdapBaseDn(final String value) {
660 setSystemProperty(Constants.LDAP_BASE_DN, value);
661 }
662
663 default String getLdapBaseDn() {
664 return getSystemProperty(Constants.LDAP_BASE_DN);
665 }
666
667 default void setLdapAccountFilter(final String value) {
668 setSystemProperty(Constants.LDAP_ACCOUNT_FILTER, value);
669 }
670
671 default String getLdapAccountFilter() {
672 return getSystemProperty(Constants.LDAP_ACCOUNT_FILTER);
673 }
674
675 default void setLdapGroupFilter(final String value) {
676 setSystemProperty(Constants.LDAP_GROUP_FILTER, value);
677 }
678
679 default String getLdapGroupFilter() {
680 return getSystemProperty(Constants.LDAP_GROUP_FILTER, StringUtil.EMPTY);
681 }
682
683 default void setNotificationLogin(final String value) {
684 setSystemProperty(Constants.NOTIFICATION_LOGIN, value);
685 }
686
687 default String getNotificationLogin() {
688 return getSystemProperty(Constants.NOTIFICATION_LOGIN, StringUtil.EMPTY);
689 }
690
691 default String getNotificationAdvanceSearch() {
692 return getSystemProperty(Constants.NOTIFICATION_ADVANCE_SEARCH, StringUtil.EMPTY);
693 }
694
695 default void setNotificationSearchTop(final String value) {
696 setSystemProperty(Constants.NOTIFICATION_SEARCH_TOP, value);
697 }
698
699 default String getNotificationSearchTop() {
700 return getSystemProperty(Constants.NOTIFICATION_SEARCH_TOP, StringUtil.EMPTY);
701 }
702
703 default String getUserAgentName() {
704 return getSystemProperty(Constants.CRAWLING_USER_AGENT_PROPERTY, "Mozilla/5.0 (compatible; Fess/"
705 + ComponentUtil.getSystemHelper().getProductVersion() + "; +http://fess.codelibs.org/bot.html)");
706 }
707
708 default void setLtrModelName(final String value) {
709 setSystemProperty(Constants.LTR_MODEL_NAME_PROPERTY, value);
710 }
711
712 default String getLtrModelName() {
713 return getSystemProperty(Constants.LTR_MODEL_NAME_PROPERTY, StringUtil.EMPTY);
714 }
715
716 default void setLtrWindowSize(final int value) {
717 setSystemPropertyAsInt(Constants.LTR_WINDOW_SIZE_PROPERTY, value);
718 }
719
720 default int getLtrWindowSize() {
721 return getSystemPropertyAsInt(Constants.LTR_WINDOW_SIZE_PROPERTY, 100);
722 }
723
724 default String[] getAzureAdPermissionFields() {
725 return split(getSystemProperty("aad.permission.fields", "mail"), ",")
726 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).toArray(n -> new String[n]));
727 }
728
729
730
731
732
733 String getAuthenticationAdminRoles();
734
735 default String[] getAuthenticationAdminRolesAsArray() {
736 String[] roles = (String[]) propMap.get(AUTHENTICATION_ADMIN_ROLES);
737 if (roles == null) {
738 roles = getAuthenticationAdminRoles().split(",");
739 propMap.put(AUTHENTICATION_ADMIN_ROLES, roles);
740 }
741 return roles;
742 }
743
744 String getJvmCrawlerOptions();
745
746 default String[] getJvmCrawlerOptionsAsArray() {
747 return JvmUtil.filterJvmOptions(getJvmCrawlerOptions().split("\n"));
748 }
749
750 String getJvmSuggestOptions();
751
752 default String[] getJvmSuggestOptionsAsArray() {
753 return JvmUtil.filterJvmOptions(getJvmSuggestOptions().split("\n"));
754 }
755
756 String getJvmThumbnailOptions();
757
758 default String[] getJvmThumbnailOptionsAsArray() {
759 return JvmUtil.filterJvmOptions(getJvmThumbnailOptions().split("\n"));
760 }
761
762 String getCrawlerDocumentHtmlPrunedTags();
763
764 default PrunedTag[] getCrawlerDocumentHtmlPrunedTagsAsArray() {
765 PrunedTag[] tags = (PrunedTag[]) propMap.get("crawlerDocumentHtmlPrunedTags");
766 if (tags == null) {
767 tags = PrunedTag.parse(getCrawlerDocumentHtmlPrunedTags());
768 propMap.put("crawlerDocumentHtmlPrunedTags", tags);
769 }
770 return tags;
771 }
772
773 String getCrawlerDocumentCacheHtmlMimetypes();
774
775 default boolean isHtmlMimetypeForCache(final String mimetype) {
776 final String[] mimetypes = getCrawlerDocumentCacheHtmlMimetypes().split(",");
777 if (mimetypes.length == 1 && StringUtil.isBlank(mimetypes[0])) {
778 return true;
779 }
780 return stream(mimetypes).get(stream -> stream.anyMatch(s -> s.equalsIgnoreCase(mimetype)));
781 }
782
783 String getCrawlerDocumentCacheSupportedMimetypes();
784
785 default boolean isSupportedDocumentCacheMimetypes(final String mimetype) {
786 final String[] mimetypes = getCrawlerDocumentCacheSupportedMimetypes().split(",");
787 if (mimetypes.length == 1 && StringUtil.isBlank(mimetypes[0])) {
788 return true;
789 }
790 return stream(mimetypes).get(stream -> stream.anyMatch(s -> s.equalsIgnoreCase(mimetype)));
791 }
792
793 String getIndexerClickCountEnabled();
794
795 default boolean getIndexerClickCountEnabledAsBoolean() {
796 return Constants.TRUE.equalsIgnoreCase(getIndexerClickCountEnabled());
797 }
798
799 String getIndexerFavoriteCountEnabled();
800
801 default boolean getIndexerFavoriteCountEnabledAsBoolean() {
802 return Constants.TRUE.equalsIgnoreCase(getIndexerFavoriteCountEnabled());
803 }
804
805 String getApiAccessTokenRequired();
806
807 default boolean getApiAccessTokenRequiredAsBoolean() {
808 return Constants.TRUE.equalsIgnoreCase(getApiAccessTokenRequired());
809 }
810
811 String getIndexerThreadDumpEnabled();
812
813 default boolean getIndexerThreadDumpEnabledAsBoolean() {
814 return Constants.TRUE.equalsIgnoreCase(getIndexerThreadDumpEnabled());
815 }
816
817 String getIndexBackupTargets();
818
819 String getIndexBackupLogTargets();
820
821 default String[] getIndexBackupAllTargets() {
822 return split(getIndexBackupTargets() + "," + getIndexBackupLogTargets(), ",")
823 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).toArray(n -> new String[n]));
824 }
825
826 String getJobSystemJobIds();
827
828 default boolean isSystemJobId(final String id) {
829 if (StringUtil.isBlank(getJobSystemJobIds())) {
830 return false;
831 }
832 return split(getJobSystemJobIds(), ",").get(stream -> stream.anyMatch(s -> s.equals(id)));
833 }
834
835 String getSmbAvailableSidTypes();
836
837 default Integer getAvailableSmbSidType(final int sidType) {
838 @SuppressWarnings("unchecked")
839 Map<Integer, Integer> params = (Map<Integer, Integer>) propMap.get(SMB_AVAILABLE_SID_TYPES);
840 if (params == null) {
841 params = split(getSmbAvailableSidTypes(), ",").get(stream -> stream.map(s -> {
842 final String[] v = s.split(":");
843 if (v.length == 1) {
844 final int x = DfTypeUtil.toInteger(v[0].trim());
845 return new Pair<>(x, x);
846 }
847 if (v.length == 2) {
848 final int x = DfTypeUtil.toInteger(v[0].trim());
849 final int y = DfTypeUtil.toInteger(v[1].trim());
850 return new Pair<>(x, y);
851 }
852 return null;
853 }).filter(v -> v != null).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)));
854 propMap.put(SMB_AVAILABLE_SID_TYPES, params);
855 }
856 return params.get(sidType);
857 }
858
859 String getSupportedLanguages();
860
861 default String[] getSupportedLanguagesAsArray() {
862 return split(getSupportedLanguages(), ",").get(stream -> stream.filter(StringUtil::isNotBlank).toArray(n -> new String[n]));
863 }
864
865 String getOnlineHelpSupportedLangs();
866
867 default boolean isOnlineHelpSupportedLang(final String lang) {
868 if (StringUtil.isBlank(getOnlineHelpSupportedLangs())) {
869 return false;
870 }
871 return split(getOnlineHelpSupportedLangs(), ",").get(stream -> stream.filter(StringUtil::isNotBlank).anyMatch(s -> s.equals(lang)));
872 }
873
874 String getForumSupportedLangs();
875
876 default boolean isForumSupportedLang(final String lang) {
877 if (StringUtil.isBlank(getForumSupportedLangs())) {
878 return false;
879 }
880 return split(getForumSupportedLangs(), ",").get(stream -> stream.filter(StringUtil::isNotBlank).anyMatch(s -> s.equals(lang)));
881 }
882
883 String getSupportedUploadedJsExtentions();
884
885 default String[] getSupportedUploadedJsExtentionsAsArray() {
886 return split(getSupportedUploadedJsExtentions(), ",")
887 .get(stream -> stream.filter(StringUtil::isNotBlank).toArray(n -> new String[n]));
888 }
889
890 String getSupportedUploadedCssExtentions();
891
892 default String[] getSupportedUploadedCssExtentionsAsArray() {
893 return split(getSupportedUploadedCssExtentions(), ",")
894 .get(stream -> stream.filter(StringUtil::isNotBlank).toArray(n -> new String[n]));
895 }
896
897 String getSupportedUploadedMediaExtentions();
898
899 default String[] getSupportedUploadedMediaExtentionsAsArray() {
900 return split(getSupportedUploadedMediaExtentions(), ",")
901 .get(stream -> stream.filter(StringUtil::isNotBlank).toArray(n -> new String[n]));
902 }
903
904 String getJobTemplateTitleWeb();
905
906 String getJobTemplateTitleFile();
907
908 String getJobTemplateTitleData();
909
910 default String getJobTemplateTitle(final String type) {
911 if (Constants.WEB_CRAWLER_TYPE.equals(type)) {
912 return getJobTemplateTitleWeb();
913 }
914 if (Constants.FILE_CRAWLER_TYPE.equals(type)) {
915 return getJobTemplateTitleFile();
916 }
917 if (Constants.DATA_CRAWLER_TYPE.equals(type)) {
918 return getJobTemplateTitleData();
919 }
920 return "None";
921 }
922
923 String getSchedulerJobClass();
924
925 default Class<? extends LaJob> getSchedulerJobClassAsClass() {
926 try {
927 @SuppressWarnings("unchecked")
928 final Class<? extends LaJob> clazz = (Class<? extends LaJob>) Class.forName(getSchedulerJobClass());
929 return clazz;
930 } catch (final ClassNotFoundException e) {
931 throw new ClassNotFoundRuntimeException(e);
932 }
933 }
934
935 String getSchedulerConcurrentExecMode();
936
937 default JobConcurrentExec getSchedulerConcurrentExecModeAsEnum() {
938 return JobConcurrentExec.valueOf(getSchedulerConcurrentExecMode());
939 }
940
941 String getCrawlerMetadataContentExcludes();
942
943 default boolean isCrawlerMetadataContentIncluded(final String name) {
944 Pattern[] patterns = (Pattern[]) propMap.get(CRAWLER_METADATA_CONTENT_EXCLUDES);
945 if (patterns == null) {
946 patterns = split(getCrawlerMetadataContentExcludes(), ",")
947 .get(stream -> stream.filter(StringUtil::isNotBlank).map(v -> Pattern.compile(v)).toArray(n -> new Pattern[n]));
948 propMap.put(CRAWLER_METADATA_CONTENT_EXCLUDES, patterns);
949 }
950 return !stream(patterns).get(stream -> stream.anyMatch(p -> p.matcher(name).matches()));
951 }
952
953 String getCrawlerMetadataNameMapping();
954
955 default Tuple3<String, String, String> getCrawlerMetadataNameMapping(final String name) {
956 @SuppressWarnings("unchecked")
957 Map<String, Tuple3<String, String, String>> params =
958 (Map<String, Tuple3<String, String, String>>) propMap.get(CRAWLER_METADATA_NAME_MAPPING);
959 if (params == null) {
960 params = split(getCrawlerMetadataNameMapping(), "\n").get(stream -> stream.filter(StringUtil::isNotBlank).map(v -> {
961 final String[] values = v.split("=");
962 if (values.length == 2) {
963 final String[] subValues = values[1].split(":", 3);
964 if (subValues.length == 3) {
965 return new Tuple4<>(values[0], subValues[0], subValues[1], subValues[2]);
966 }
967 if (subValues.length == 2) {
968 return new Tuple4<>(values[0], subValues[0], subValues[1], StringUtil.EMPTY);
969 }
970 return new Tuple4<>(values[0], values[1], Constants.MAPPING_TYPE_ARRAY, StringUtil.EMPTY);
971 }
972 return null;
973 }).collect(Collectors.toMap(Tuple4::getValue1, d -> new Tuple3<>(d.getValue2(), d.getValue3(), d.getValue4()))));
974 propMap.put(CRAWLER_METADATA_NAME_MAPPING, params);
975 }
976 return params.get(name);
977 }
978
979 String getSuggestPopularWordFields();
980
981 default String[] getSuggestPopularWordFieldsAsArray() {
982 return split(getSuggestPopularWordFields(), "\n").get(stream -> stream.filter(StringUtil::isNotBlank).toArray(n -> new String[n]));
983 }
984
985 String getSuggestPopularWordTags();
986
987 default String[] getSuggestPopularWordTagsAsArray() {
988 return split(getSuggestPopularWordTags(), "\n").get(stream -> stream.filter(StringUtil::isNotBlank).toArray(n -> new String[n]));
989 }
990
991 String getSuggestPopularWordExcludes();
992
993 default String[] getSuggestPopularWordExcludesAsArray() {
994 return split(getSuggestPopularWordExcludes(), "\n")
995 .get(stream -> stream.filter(StringUtil::isNotBlank).toArray(n -> new String[n]));
996 }
997
998 String getQueryReplaceTermWithPrefixQuery();
999
1000 default boolean getQueryReplaceTermWithPrefixQueryAsBoolean() {
1001 return Boolean.parseBoolean(getQueryReplaceTermWithPrefixQuery());
1002 }
1003
1004 String getQueryDefaultLanguages();
1005
1006 String getQueryLanguageMapping();
1007
1008 default Map<String, String> getQueryLanguageMappingMap() {
1009 @SuppressWarnings("unchecked")
1010 Map<String, String> params = (Map<String, String>) propMap.get(QUERY_LANGUAGE_MAPPING);
1011 if (params == null) {
1012 params = stream(getQueryLanguageMapping().split("\n")).get(stream -> stream.filter(StringUtil::isNotBlank).map(v -> {
1013 final String[] values = v.split("=");
1014 if (values.length == 2) {
1015 return new Pair<>(values[0], values[1]);
1016 }
1017 return null;
1018 }).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)));
1019 propMap.put(QUERY_LANGUAGE_MAPPING, params);
1020 }
1021 return params;
1022 }
1023
1024 default String[] normalizeQueryLanguages(final String[] langs) {
1025 final Map<String, String> mapping = getQueryLanguageMappingMap();
1026 return stream(langs).get(stream -> stream.map(s -> {
1027 if (StringUtil.isBlank(s)) {
1028 return null;
1029 }
1030 final String lang1 = mapping.get(s);
1031 if (lang1 != null) {
1032 return lang1;
1033 }
1034 final String lang2 = mapping.get(s.split("[\\-_]")[0]);
1035 return lang2;
1036 }).filter(StringUtil::isNotBlank).distinct().toArray(n -> new String[n]));
1037 }
1038
1039 default String[] getQueryLanguages(final Enumeration<Locale> locales, final String[] requestLangs) {
1040
1041 if (StringUtil.isNotBlank(getQueryDefaultLanguages())) {
1042 String[] langs = (String[]) propMap.get(QUERY_DEFAULT_LANGUAGES);
1043 if (langs == null) {
1044 langs = split(getQueryDefaultLanguages(), ",").get(stream -> stream.map(String::trim).toArray(n -> new String[n]));
1045 propMap.put(QUERY_DEFAULT_LANGUAGES, langs);
1046
1047 }
1048 return normalizeQueryLanguages(langs);
1049 }
1050
1051 if (requestLangs != null && requestLangs.length != 0) {
1052 return normalizeQueryLanguages(requestLangs);
1053 }
1054
1055 if (locales == null) {
1056 return StringUtil.EMPTY_STRINGS;
1057 }
1058
1059 return normalizeQueryLanguages(Collections.list(locales).stream().map(locale -> {
1060 final String language = locale.getLanguage();
1061 final String country = locale.getCountry();
1062 if (StringUtil.isNotBlank(language)) {
1063 if (StringUtil.isNotBlank(country)) {
1064 return language.toLowerCase(Locale.ROOT) + "-" + country.toLowerCase(Locale.ROOT);
1065 }
1066 return language.toLowerCase(Locale.ROOT);
1067 }
1068 return null;
1069 }).toArray(n -> new String[n]));
1070 }
1071
1072 default Locale getQueryLocaleFromName(final String name) {
1073 if (name == null) {
1074 return Locale.ROOT;
1075 }
1076 final String value = name.toLowerCase(Locale.ROOT);
1077 final Map<String, String> mapping = getQueryLanguageMappingMap();
1078 for (final String key : mapping.keySet()) {
1079 if (value.endsWith("_" + key.toLowerCase(Locale.ROOT))) {
1080 final String[] values = key.split("_");
1081 if (values.length == 1) {
1082 return new Locale(values[0]);
1083 }
1084 if (values.length == 2) {
1085 return new Locale(values[0], values[1]);
1086 }
1087 if (values.length == 3) {
1088 return new Locale(values[0], values[1], values[2]);
1089 }
1090 }
1091 }
1092 return Locale.ROOT;
1093 }
1094
1095 String getSupportedUploadedFiles();
1096
1097 default boolean isSupportedUploadedFile(final String name) {
1098 return split(getSuggestPopularWordExcludes(), ",")
1099 .get(stream -> stream.filter(StringUtil::isNotBlank).anyMatch(s -> s.equals(name)));
1100 }
1101
1102 String getLdapAdminUserObjectClasses();
1103
1104 default Attribute getLdapAdminUserObjectClassAttribute() {
1105 final Attribute oc = new BasicAttribute("objectClass");
1106 split(getLdapAdminUserObjectClasses(), ",").of(stream -> stream.filter(StringUtil::isNotBlank).forEach(s -> oc.add(s.trim())));
1107 return oc;
1108 }
1109
1110 String getLdapAdminUserFilter();
1111
1112 default String getLdapAdminUserFilter(final String name) {
1113 return String.format(getLdapAdminUserFilter(), name);
1114 }
1115
1116 String getLdapAdminUserBaseDn();
1117
1118 default String getLdapAdminUserSecurityPrincipal(final String name) {
1119 final StringBuilder buf = new StringBuilder(100);
1120 buf.append(String.format(getLdapAdminUserFilter(), name));
1121 if (StringUtil.isNotBlank(getLdapAdminUserBaseDn())) {
1122 buf.append(',').append(getLdapAdminUserBaseDn());
1123 }
1124 return buf.toString();
1125 }
1126
1127 String getLdapAdminRoleObjectClasses();
1128
1129 default Attribute getLdapAdminRoleObjectClassAttribute() {
1130 final Attribute oc = new BasicAttribute("objectClass");
1131 split(getLdapAdminRoleObjectClasses(), ",").of(stream -> stream.filter(StringUtil::isNotBlank).forEach(s -> oc.add(s.trim())));
1132 return oc;
1133 }
1134
1135 String getLdapAdminRoleFilter();
1136
1137 default String getLdapAdminRoleFilter(final String name) {
1138 return String.format(getLdapAdminRoleFilter(), name);
1139 }
1140
1141 String getLdapAdminRoleBaseDn();
1142
1143 default String getLdapAdminRoleSecurityPrincipal(final String name) {
1144 final StringBuilder buf = new StringBuilder(100);
1145 buf.append(String.format(getLdapAdminRoleFilter(), name));
1146 if (StringUtil.isNotBlank(getLdapAdminRoleBaseDn())) {
1147 buf.append(',').append(getLdapAdminRoleBaseDn());
1148 }
1149 return buf.toString();
1150 }
1151
1152 String getLdapAdminGroupObjectClasses();
1153
1154 default Attribute getLdapAdminGroupObjectClassAttribute() {
1155 final Attribute oc = new BasicAttribute("objectClass");
1156 split(getLdapAdminGroupObjectClasses(), ",").of(stream -> stream.filter(StringUtil::isNotBlank).forEach(s -> oc.add(s.trim())));
1157 return oc;
1158 }
1159
1160 String getLdapAdminGroupFilter();
1161
1162 default String getLdapAdminGroupFilter(final String name) {
1163 return String.format(getLdapAdminGroupFilter(), name);
1164 }
1165
1166 String getLdapAdminGroupBaseDn();
1167
1168 default String getLdapAdminGroupSecurityPrincipal(final String name) {
1169 final StringBuilder buf = new StringBuilder(100);
1170 buf.append(String.format(getLdapAdminGroupFilter(), name));
1171 if (StringUtil.isNotBlank(getLdapAdminGroupBaseDn())) {
1172 buf.append(',').append(getLdapAdminGroupBaseDn());
1173 }
1174 return buf.toString();
1175 }
1176
1177 String getAuthenticationAdminUsers();
1178
1179 default boolean isAdminUser(final String username) {
1180 return split(getAuthenticationAdminUsers(), ",").get(stream -> stream.anyMatch(s -> s.equals(username)));
1181 }
1182
1183 boolean isLdapAdminEnabled();
1184
1185 default boolean isLdapAdminEnabled(final String username) {
1186 if (isAdminUser(username)) {
1187 return false;
1188 }
1189 return isLdapAdminEnabled();
1190 }
1191
1192 String getCrawlerWebProtocols();
1193
1194 default String[] getCrawlerWebProtocolsAsArray() {
1195 return split(getCrawlerWebProtocols(), ",")
1196 .get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim() + ":").toArray(n -> new String[n]));
1197 }
1198
1199 default boolean isValidCrawlerWebProtocol(final String url) {
1200 return stream(getCrawlerWebProtocolsAsArray()).get(stream -> stream.anyMatch(s -> url.startsWith(s)));
1201 }
1202
1203 String getCrawlerFileProtocols();
1204
1205 default String[] getCrawlerFileProtocolsAsArray() {
1206 return split(getCrawlerFileProtocols(), ",")
1207 .get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim() + ":").toArray(n -> new String[n]));
1208 }
1209
1210 default boolean isValidCrawlerFileProtocol(final String url) {
1211 return stream(getCrawlerFileProtocolsAsArray()).get(stream -> stream.anyMatch(s -> url.startsWith(s)));
1212 }
1213
1214 String getRoleSearchDefaultPermissions();
1215
1216 default String[] getSearchDefaultPermissionsAsArray() {
1217 final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
1218 return split(getRoleSearchDefaultPermissions(), ",").get(stream -> stream.map(p -> permissionHelper.encode(p))
1219 .filter(StringUtil::isNotBlank).distinct().toArray(n -> new String[n]));
1220 }
1221
1222 String getRoleSearchDefaultDisplayPermissions();
1223
1224 default String[] getSearchDefaultDisplayEncodedPermissions() {
1225 final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
1226 return split(getRoleSearchDefaultDisplayPermissions(), ",").get(stream -> stream.map(p -> permissionHelper.encode(p))
1227 .filter(StringUtil::isNotBlank).distinct().toArray(n -> new String[n]));
1228 }
1229
1230 default String getSearchDefaultDisplayPermission() {
1231 return split(getRoleSearchDefaultDisplayPermissions(), ",")
1232 .get(stream -> stream.filter(StringUtil::isNotBlank).distinct().collect(Collectors.joining("\n")));
1233 }
1234
1235 String getQueryGeoFields();
1236
1237 default String[] getQueryGeoFieldsAsArray() {
1238 return split(getQueryGeoFields(), ",")
1239 .get(stream -> stream.map(String::trim).filter(StringUtil::isNotBlank).toArray(n -> new String[n]));
1240 }
1241
1242 String getSuggestSearchLogPermissions();
1243
1244 default boolean isValidSearchLogPermissions(final String[] permissions) {
1245 if (permissions == null) {
1246 return false;
1247 }
1248 @SuppressWarnings("unchecked")
1249 List<String> validPermissionList = (List<String>) propMap.get(SUGGEST_SEARCH_LOG_PERMISSIONS);
1250 if (validPermissionList == null) {
1251 final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
1252 validPermissionList = split(getSuggestSearchLogPermissions(), ",")
1253 .get(stream -> stream.map(s -> permissionHelper.encode(s)).filter(StringUtil::isNotBlank).collect(Collectors.toList()));
1254 propMap.put(SUGGEST_SEARCH_LOG_PERMISSIONS, validPermissionList);
1255 }
1256 final List<String> list = validPermissionList;
1257 return stream(permissions).get(stream -> stream.allMatch(v -> list.contains(v)));
1258 }
1259
1260 String getRoleSearchUserPrefix();
1261
1262 String getRoleSearchGuestPermissions();
1263
1264 default List<String> getSearchGuestPermissionList() {
1265 @SuppressWarnings("unchecked")
1266 List<String> list = (List<String>) propMap.get(SEARCH_GUEST_PERMISSION_LIST);
1267 if (list == null) {
1268 final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
1269 list = split(getRoleSearchGuestPermissions(), ",")
1270 .get(stream -> stream.map(s -> permissionHelper.encode(s)).filter(StringUtil::isNotBlank).collect(Collectors.toList()));
1271 list.add(getRoleSearchUserPrefix() + Constants.GUEST_USER);
1272 propMap.put(SEARCH_GUEST_PERMISSION_LIST, list);
1273 }
1274 return list;
1275 }
1276
1277 String getIndexAdminArrayFields();
1278
1279 default Set<String> getIndexAdminArrayFieldSet() {
1280 @SuppressWarnings("unchecked")
1281 Set<String> fieldSet = (Set<String>) propMap.get(INDEX_ADMIN_ARRAY_FIELD_SET);
1282 if (fieldSet == null) {
1283 fieldSet = split(getIndexAdminArrayFields(), ",")
1284 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.toSet()));
1285 propMap.put(INDEX_ADMIN_ARRAY_FIELD_SET, fieldSet);
1286 }
1287 return fieldSet;
1288 }
1289
1290 default boolean validateIndexArrayFields(final Map<String, Object> source) {
1291 return invalidIndexArrayFields(source).isEmpty();
1292 }
1293
1294 default List<String> invalidIndexArrayFields(final Map<String, Object> source) {
1295
1296 return split(getIndexAdminArrayFields(), ",").get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim)
1297 .filter(s -> isNonEmptyValue(source.get(s))).filter(s -> false)
1298 .collect(Collectors.toList()));
1299 }
1300
1301 String getIndexAdminDateFields();
1302
1303 default Set<String> getIndexAdminDateFieldSet() {
1304 @SuppressWarnings("unchecked")
1305 Set<String> fieldSet = (Set<String>) propMap.get(INDEX_ADMIN_DATE_FIELD_SET);
1306 if (fieldSet == null) {
1307 fieldSet = split(getIndexAdminDateFields(), ",")
1308 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.toSet()));
1309 propMap.put(INDEX_ADMIN_DATE_FIELD_SET, fieldSet);
1310 }
1311 return fieldSet;
1312 }
1313
1314 default boolean validateIndexDateFields(final Map<String, Object> source) {
1315 return invalidIndexDateFields(source).isEmpty();
1316 }
1317
1318 default List<String> invalidIndexDateFields(final Map<String, Object> source) {
1319 return split(getIndexAdminDateFields(), ",")
1320 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).filter(s -> isNonEmptyValue(source.get(s)))
1321 .filter(s -> !validateDateTimeString(source.get(s))).collect(Collectors.toList()));
1322 }
1323
1324 default boolean validateDateTimeString(final Object obj) {
1325 if (FessFunctions.parseDate(obj.toString()) != null) {
1326 return true;
1327 }
1328 return false;
1329 }
1330
1331 String getIndexAdminIntegerFields();
1332
1333 default Set<String> getIndexAdminIntegerFieldSet() {
1334 @SuppressWarnings("unchecked")
1335 Set<String> fieldSet = (Set<String>) propMap.get(INDEX_ADMIN_INTEGER_FIELD_SET);
1336 if (fieldSet == null) {
1337 fieldSet = split(getIndexAdminIntegerFields(), ",")
1338 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.toSet()));
1339 propMap.put(INDEX_ADMIN_INTEGER_FIELD_SET, fieldSet);
1340 }
1341 return fieldSet;
1342 }
1343
1344 default boolean validateIndexIntegerFields(final Map<String, Object> source) {
1345 return invalidIndexIntegerFields(source).isEmpty();
1346 }
1347
1348 default List<String> invalidIndexIntegerFields(final Map<String, Object> source) {
1349 final IntegerTypeValidator integerValidator = new IntegerTypeValidator();
1350 return split(getIndexAdminIntegerFields(), ",")
1351 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).filter(s -> isNonEmptyValue(source.get(s)))
1352 .filter(s -> !integerValidator.isValid(source.get(s).toString(), null)).collect(Collectors.toList()));
1353 }
1354
1355 String getIndexAdminLongFields();
1356
1357 default Set<String> getIndexAdminLongFieldSet() {
1358 @SuppressWarnings("unchecked")
1359 Set<String> fieldSet = (Set<String>) propMap.get(INDEX_ADMIN_LONG_FIELD_SET);
1360 if (fieldSet == null) {
1361 fieldSet = split(getIndexAdminLongFields(), ",")
1362 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.toSet()));
1363 propMap.put(INDEX_ADMIN_LONG_FIELD_SET, fieldSet);
1364 }
1365 return fieldSet;
1366 }
1367
1368 default boolean validateIndexLongFields(final Map<String, Object> source) {
1369 return invalidIndexLongFields(source).isEmpty();
1370 }
1371
1372 default List<String> invalidIndexLongFields(final Map<String, Object> source) {
1373 final LongTypeValidator longValidator = new LongTypeValidator();
1374 return split(getIndexAdminLongFields(), ",")
1375 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).filter(s -> isNonEmptyValue(source.get(s)))
1376 .filter(s -> !longValidator.isValid(source.get(s).toString(), null)).collect(Collectors.toList()));
1377 }
1378
1379 String getIndexAdminFloatFields();
1380
1381 default Set<String> getIndexAdminFloatFieldSet() {
1382 @SuppressWarnings("unchecked")
1383 Set<String> fieldSet = (Set<String>) propMap.get(INDEX_ADMIN_FLOAT_FIELD_SET);
1384 if (fieldSet == null) {
1385 fieldSet = split(getIndexAdminFloatFields(), ",")
1386 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.toSet()));
1387 propMap.put(INDEX_ADMIN_FLOAT_FIELD_SET, fieldSet);
1388 }
1389 return fieldSet;
1390 }
1391
1392 default boolean validateIndexFloatFields(final Map<String, Object> source) {
1393 return invalidIndexFloatFields(source).isEmpty();
1394 }
1395
1396 default List<String> invalidIndexFloatFields(final Map<String, Object> source) {
1397 final FloatTypeValidator floatValidator = new FloatTypeValidator();
1398 return split(getIndexAdminFloatFields(), ",")
1399 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).filter(s -> isNonEmptyValue(source.get(s)))
1400 .filter(s -> !floatValidator.isValid(source.get(s).toString(), null)).collect(Collectors.toList()));
1401 }
1402
1403 String getIndexAdminDoubleFields();
1404
1405 default Set<String> getIndexAdminDoubleFieldSet() {
1406 @SuppressWarnings("unchecked")
1407 Set<String> fieldSet = (Set<String>) propMap.get(INDEX_ADMIN_DOUBLE_FIELD_SET);
1408 if (fieldSet == null) {
1409 fieldSet = split(getIndexAdminDoubleFields(), ",")
1410 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.toSet()));
1411 propMap.put(INDEX_ADMIN_DOUBLE_FIELD_SET, fieldSet);
1412 }
1413 return fieldSet;
1414 }
1415
1416 default boolean validateIndexDoubleFields(final Map<String, Object> source) {
1417 return invalidIndexDoubleFields(source).isEmpty();
1418 }
1419
1420 default List<String> invalidIndexDoubleFields(final Map<String, Object> source) {
1421 final DoubleTypeValidator doubleValidator = new DoubleTypeValidator();
1422 return split(getIndexAdminDoubleFields(), ",")
1423 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).filter(s -> isNonEmptyValue(source.get(s)))
1424 .filter(s -> !doubleValidator.isValid(source.get(s).toString(), null)).collect(Collectors.toList()));
1425 }
1426
1427 default Map<String, Object> convertToEditableDoc(final Map<String, Object> source) {
1428
1429 final Set<String> arrayFieldSet = getIndexAdminArrayFieldSet();
1430 final Set<String> dateFieldSet = getIndexAdminDateFieldSet();
1431 final Set<String> integerFieldSet = getIndexAdminIntegerFieldSet();
1432 final Set<String> longFieldSet = getIndexAdminLongFieldSet();
1433 final Set<String> floatFieldSet = getIndexAdminFloatFieldSet();
1434 final Set<String> doubleFieldSet = getIndexAdminDoubleFieldSet();
1435
1436 return source.entrySet().stream().map(e -> {
1437 final String key = e.getKey();
1438 Object value = e.getValue();
1439 if (value == null) {
1440 value = StringUtil.EMPTY;
1441 }
1442 if (value instanceof String || value == null) {
1443 return new Pair<>(key, value);
1444 }
1445 if (arrayFieldSet.contains(key)) {
1446 if (value instanceof String[]) {
1447 value = stream((String[]) value).get(stream -> stream.collect(Collectors.joining("\n")));
1448 } else if (value instanceof List) {
1449 @SuppressWarnings("unchecked")
1450 final List<String> list = (List<String>) value;
1451 value = list.stream().collect(Collectors.joining("\n"));
1452 }
1453 } else if (dateFieldSet.contains(key)) {
1454 value = FessFunctions.formatDate((Date) value);
1455 } else if (integerFieldSet.contains(key) || longFieldSet.contains(key) || floatFieldSet.contains(key)
1456 || doubleFieldSet.contains(key)) {
1457 value = value.toString();
1458 }
1459 return new Pair<>(key, value);
1460 }).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond));
1461 }
1462
1463 default Map<String, Object> convertToStorableDoc(final Map<String, Object> source) {
1464
1465 final Set<String> arrayFieldSet = getIndexAdminArrayFieldSet();
1466 final Set<String> dateFieldSet = getIndexAdminDateFieldSet();
1467 final Set<String> integerFieldSet = getIndexAdminIntegerFieldSet();
1468 final Set<String> longFieldSet = getIndexAdminLongFieldSet();
1469 final Set<String> floatFieldSet = getIndexAdminFloatFieldSet();
1470 final Set<String> doubleFieldSet = getIndexAdminDoubleFieldSet();
1471
1472 return source.entrySet().stream().filter(e -> isNonEmptyValue(e.getValue())).map(e -> {
1473 final String key = e.getKey();
1474 Object value = e.getValue();
1475 if (arrayFieldSet.contains(key)) {
1476 value = split(value.toString(), "\n")
1477 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.toList()));
1478 } else if (dateFieldSet.contains(key)) {
1479
1480 value = FessFunctions.parseDate(value.toString());
1481 } else if (integerFieldSet.contains(key)) {
1482 value = DfTypeUtil.toInteger(value.toString());
1483 } else if (longFieldSet.contains(key)) {
1484 value = DfTypeUtil.toLong(value.toString());
1485 } else if (floatFieldSet.contains(key)) {
1486 value = DfTypeUtil.toFloat(value.toString());
1487 } else if (doubleFieldSet.contains(key)) {
1488 value = DfTypeUtil.toDouble(value.toString());
1489 }
1490 return new Pair<>(key, value);
1491 }).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond));
1492 }
1493
1494 String getIndexAdminRequiredFields();
1495
1496 default boolean validateIndexRequiredFields(final Map<String, Object> source) {
1497 return invalidIndexRequiredFields(source).isEmpty();
1498 }
1499
1500 default List<String> invalidIndexRequiredFields(final Map<String, Object> source) {
1501 final RequiredValidator requiredValidator = new RequiredValidator();
1502 return split(getIndexAdminRequiredFields(), ",").get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim)
1503 .filter(s -> !requiredValidator.isValid(source.get(s), null)).collect(Collectors.toList()));
1504 }
1505
1506 default boolean isNonEmptyValue(final Object value) {
1507 final RequiredValidator requiredValidator = new RequiredValidator();
1508 return requiredValidator.isValid(value, null);
1509 }
1510
1511 String getCrawlerDocumentSpaceChars();
1512
1513 default int[] getCrawlerDocumentSpaceCharsAsArray() {
1514 return getCrawlerDocumentCharsAsArray(CRAWLER_DOCUMENT_SPACE_CHARS, getCrawlerDocumentSpaceChars());
1515 }
1516
1517 default String[] getCrawlerDocumentSpaces() {
1518 String[] spaces = (String[]) propMap.get(CRAWLER_DOCUMENT_SPACES);
1519 if (spaces == null) {
1520 spaces = Arrays.stream(getCrawlerDocumentSpaceCharsAsArray()).mapToObj(Character::toString).toArray(n -> new String[n]);
1521 propMap.put(CRAWLER_DOCUMENT_SPACES, spaces);
1522 }
1523 return spaces;
1524 }
1525
1526 default int[] getCrawlerDocumentCharsAsArray(final String key, final String spaceStr) {
1527 int[] spaceChars = (int[]) propMap.get(key);
1528 if (spaceChars == null) {
1529 if (spaceStr.startsWith("u")) {
1530 spaceChars = split(spaceStr, "u")
1531 .get(stream -> stream.filter(StringUtil::isNotBlank).mapToInt(s -> Integer.parseInt(s, 16)).toArray());
1532 } else {
1533
1534 final int length = spaceStr.length();
1535 spaceChars = new int[length];
1536 for (int i = 0; i < length; i++) {
1537 spaceChars[i] = spaceStr.codePointAt(i);
1538 }
1539 }
1540 propMap.put(key, spaceChars);
1541 }
1542 return spaceChars;
1543 }
1544
1545 String getCrawlerDocumentFullstopChars();
1546
1547 default boolean endsWithFullstop(final String s) {
1548 if (StringUtil.isBlank(s)) {
1549 return false;
1550 }
1551 for (final int i : getCrawlerDocumentFullstopCharsAsArray()) {
1552 if (s.endsWith(String.valueOf(i))) {
1553 return true;
1554 }
1555 }
1556 return false;
1557 }
1558
1559 default int[] getCrawlerDocumentFullstopCharsAsArray() {
1560 return getCrawlerDocumentCharsAsArray(CRAWLER_DOCUMENT_FULLSTOP_CHARS, getCrawlerDocumentFullstopChars());
1561 }
1562
1563 String getQueryAdditionalResponseFields();
1564
1565 default String[] getQueryAdditionalResponseFields(final String... fields) {
1566 final List<String> list = new ArrayList<>(fields.length + 10);
1567 stream(fields).of(stream -> stream.forEach(list::add));
1568 split(getQueryAdditionalResponseFields(), ",")
1569 .of(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).forEach(list::add));
1570 return list.toArray(new String[list.size()]);
1571 }
1572
1573 String getQueryAdditionalScrollResponseFields();
1574
1575 default String[] getQueryAdditionalScrollResponseFields(final String... fields) {
1576 final List<String> list = new ArrayList<>(fields.length + 10);
1577 stream(fields).of(stream -> stream.forEach(list::add));
1578 split(getQueryAdditionalScrollResponseFields(), ",")
1579 .of(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).forEach(list::add));
1580 return list.toArray(new String[list.size()]);
1581 }
1582
1583 String getQueryAdditionalCacheResponseFields();
1584
1585 default String[] getQueryAdditionalCacheResponseFields(final String... fields) {
1586 final List<String> list = new ArrayList<>(fields.length + 10);
1587 stream(fields).of(stream -> stream.forEach(list::add));
1588 split(getQueryAdditionalCacheResponseFields(), ",")
1589 .of(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).forEach(list::add));
1590 return list.toArray(new String[list.size()]);
1591 }
1592
1593 String getQueryAdditionalHighlightedFields();
1594
1595 default String[] getQueryAdditionalHighlightedFields(final String... fields) {
1596 final List<String> list = new ArrayList<>(fields.length + 10);
1597 stream(fields).of(stream -> stream.forEach(list::add));
1598 split(getQueryAdditionalHighlightedFields(), ",")
1599 .of(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).forEach(list::add));
1600 return list.toArray(new String[list.size()]);
1601 }
1602
1603 String getQueryAdditionalSearchFields();
1604
1605 default String[] getQueryAdditionalSearchFields(final String... fields) {
1606 final List<String> list = new ArrayList<>(fields.length + 10);
1607 stream(fields).of(stream -> stream.forEach(list::add));
1608 split(getQueryAdditionalSearchFields(), ",")
1609 .of(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).forEach(list::add));
1610 return list.toArray(new String[list.size()]);
1611 }
1612
1613 String getQueryAdditionalFacetFields();
1614
1615 default String[] getQueryAdditionalFacetFields(final String... fields) {
1616 final List<String> list = new ArrayList<>(fields.length + 10);
1617 stream(fields).of(stream -> stream.forEach(list::add));
1618 split(getQueryAdditionalFacetFields(), ",")
1619 .of(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).forEach(list::add));
1620 return list.toArray(new String[list.size()]);
1621 }
1622
1623 String getQueryAdditionalSortFields();
1624
1625 default String[] getQueryAdditionalSortFields(final String... fields) {
1626 final List<String> list = new ArrayList<>(fields.length + 10);
1627 stream(fields).of(stream -> stream.forEach(list::add));
1628 split(getQueryAdditionalSortFields(), ",").of(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).forEach(list::add));
1629 return list.toArray(new String[list.size()]);
1630 }
1631
1632 String getQueryAdditionalApiResponseFields();
1633
1634 default String[] getQueryAdditionalApiResponseFields(final String... fields) {
1635 final List<String> list = new ArrayList<>(fields.length + 10);
1636 stream(fields).of(stream -> stream.forEach(list::add));
1637 split(getQueryAdditionalApiResponseFields(), ",")
1638 .of(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).forEach(list::add));
1639 return list.toArray(new String[list.size()]);
1640 }
1641
1642 String getQueryAdditionalNotAnalyzedFields();
1643
1644 default String[] getQueryAdditionalNotAnalyzedFields(final String... fields) {
1645 final List<String> list = new ArrayList<>(fields.length + 10);
1646 stream(fields).of(stream -> stream.forEach(list::add));
1647 split(getQueryAdditionalNotAnalyzedFields(), ",")
1648 .of(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).forEach(list::add));
1649 return list.toArray(new String[list.size()]);
1650 }
1651
1652 String getThumbnailGeneratorTargets();
1653
1654 default String[] getThumbnailGeneratorTargetsAsArray() {
1655 return getThumbnailGeneratorTargets().split(",");
1656
1657 }
1658
1659 String getApiAdminAccessPermissions();
1660
1661 default Set<String> getApiAdminAccessPermissionSet() {
1662 @SuppressWarnings("unchecked")
1663 Set<String> fieldSet = (Set<String>) propMap.get(API_ADMIN_ACCESS_PERMISSION_SET);
1664 if (fieldSet == null) {
1665 fieldSet = split(getApiAdminAccessPermissions(), ",")
1666 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.toSet()));
1667 propMap.put(API_ADMIN_ACCESS_PERMISSION_SET, fieldSet);
1668 }
1669 return fieldSet;
1670 }
1671
1672 default boolean isApiAdminAccessAllowed(final Set<String> accessPermissions) {
1673 return getApiAdminAccessPermissionSet().stream().anyMatch(s -> accessPermissions.contains(s));
1674 }
1675
1676 String getUserCodePattern();
1677
1678 Integer getUserCodeMinLengthAsInteger();
1679
1680 Integer getUserCodeMaxLengthAsInteger();
1681
1682 default boolean isValidUserCode(final String userCode) {
1683 if (userCode == null) {
1684 return false;
1685 }
1686
1687 final int length = userCode.length();
1688 if (getUserCodeMinLengthAsInteger().intValue() > length || getUserCodeMaxLengthAsInteger().intValue() < length) {
1689 return false;
1690 }
1691
1692 Pattern pattern = (Pattern) propMap.get(USER_CODE_PATTERN);
1693 if (pattern == null) {
1694 pattern = Pattern.compile(getUserCodePattern());
1695 propMap.put(USER_CODE_PATTERN, pattern);
1696 }
1697 return pattern.matcher(userCode).matches();
1698 }
1699
1700 String getQueryCollapseInnerHitsSorts();
1701
1702 @SuppressWarnings("rawtypes")
1703 default OptionalThing<SortBuilder[]> getQueryCollapseInnerHitsSortBuilders() {
1704 @SuppressWarnings("unchecked")
1705 OptionalThing<SortBuilder[]> ot = (OptionalThing<SortBuilder[]>) propMap.get(QUERY_COLLAPSE_INNER_HITS_SORTS);
1706 if (ot == null) {
1707 final String sorts = getQueryCollapseInnerHitsSorts();
1708 if (StringUtil.isBlank(sorts)) {
1709 ot = OptionalThing.empty();
1710 } else {
1711 final SortBuilder[] sortBuilders = split(sorts, ",").get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> {
1712 final String[] values = s.split(":");
1713 if (values.length > 1) {
1714 return SortBuilders.fieldSort(values[0]).order("desc".equalsIgnoreCase(values[0]) ? SortOrder.DESC : SortOrder.ASC);
1715 }
1716 return SortBuilders.fieldSort(values[0]).order(SortOrder.ASC);
1717 }).toArray(n -> new SortBuilder[n]));
1718 ot = OptionalThing.of(sortBuilders);
1719 }
1720 propMap.put(QUERY_COLLAPSE_INNER_HITS_SORTS, ot);
1721 }
1722 return ot;
1723 }
1724
1725 String getVirtualHostHeaders();
1726
1727 default String getVirtualHostHeaderValue() {
1728 final String value = getVirtualHostValue();
1729 if (StringUtil.isNotBlank(value)) {
1730 return value;
1731 }
1732 return getVirtualHostHeaders();
1733 }
1734
1735 @SuppressWarnings("unchecked")
1736 default Tuple3<String, String, String>[] getVirtualHosts() {
1737 Tuple3<String, String, String>[] hosts = (Tuple3<String, String, String>[]) propMap.get(VIRTUAL_HOST_HEADERS);
1738 if (hosts == null) {
1739 hosts = split(getVirtualHostHeaderValue(), "\n").get(stream -> stream.map(s -> {
1740 final String[] v1 = s.split("=");
1741 if (v1.length == 2) {
1742 final String[] v2 = v1[0].split(":", 2);
1743 if (v2.length == 2) {
1744 return new Tuple3<>(v2[0].trim(), v2[1].trim(), v1[1].replaceAll("[^a-zA-Z0-9_]", StringUtil.EMPTY).trim());
1745 }
1746 }
1747 return null;
1748 }).filter(v -> {
1749 if (v == null) {
1750 return false;
1751 }
1752 if ("admin".equalsIgnoreCase(v.getValue3()) || "common".equalsIgnoreCase(v.getValue3())
1753 || "error".equalsIgnoreCase(v.getValue3()) || "login".equalsIgnoreCase(v.getValue3())
1754 || "profile".equalsIgnoreCase(v.getValue3())) {
1755 return false;
1756 }
1757 return true;
1758 }).toArray(n -> new Tuple3[n]));
1759 propMap.put(VIRTUAL_HOST_HEADERS, hosts);
1760 }
1761 return hosts;
1762 }
1763
1764 String getCrawlerFailureUrlStatusCodes();
1765
1766 default boolean isCrawlerFailureUrlStatusCodes(final int code) {
1767 int[] codes = (int[]) propMap.get(CRAWLER_FAILURE_URL_STATUS_CODES);
1768 if (codes == null) {
1769 codes = split(getCrawlerFailureUrlStatusCodes(), ",")
1770 .get(stream -> stream.filter(StringUtil::isNotBlank).mapToInt(Integer::parseInt).toArray());
1771 propMap.put(CRAWLER_FAILURE_URL_STATUS_CODES, codes);
1772 }
1773 for (final int v : codes) {
1774 if (v == code) {
1775 return true;
1776 }
1777 }
1778 return false;
1779 }
1780
1781 Integer getThumbnailHtmlImageMinWidthAsInteger();
1782
1783 Integer getThumbnailHtmlImageMinHeightAsInteger();
1784
1785 java.math.BigDecimal getThumbnailHtmlImageMaxAspectRatioAsDecimal();
1786
1787 default boolean validateThumbnailSize(final int width, final int height) {
1788 if (width <= 0 || height <= 0) {
1789 return false;
1790 }
1791
1792 if (width < getThumbnailHtmlImageMinWidthAsInteger().intValue() || height < getThumbnailHtmlImageMinHeightAsInteger().intValue()) {
1793 return false;
1794 }
1795
1796 final float ratio = getThumbnailHtmlImageMaxAspectRatioAsDecimal().floatValue();
1797 if (((float) width) / ((float) height) > ratio || ((float) height) / ((float) width) > ratio) {
1798 return false;
1799 }
1800
1801 return true;
1802 }
1803
1804 String getHttpProxyHost();
1805
1806 Integer getHttpProxyPortAsInteger();
1807
1808 String getHttpProxyUsername();
1809
1810 String getHttpProxyPassword();
1811
1812 default Proxy getHttpProxy() {
1813 Proxy proxy = (Proxy) propMap.get(HTML_PROXY);
1814 if (proxy == null) {
1815 if (StringUtil.isNotBlank(getHttpProxyHost()) && getHttpProxyPortAsInteger() != null) {
1816 final SocketAddress addr = new InetSocketAddress(getHttpProxyHost(), getHttpProxyPortAsInteger());
1817 proxy = new Proxy(Type.HTTP, addr);
1818 if (StringUtil.isNotBlank(getHttpProxyUsername())) {
1819 Authenticator.setDefault(new Authenticator() {
1820 @Override
1821 protected PasswordAuthentication getPasswordAuthentication() {
1822 return new PasswordAuthentication(getHttpProxyUsername(), getHttpProxyPassword().toCharArray());
1823 }
1824 });
1825 }
1826 } else {
1827 proxy = Proxy.NO_PROXY;
1828 }
1829 propMap.put(HTML_PROXY, proxy);
1830 }
1831 return proxy;
1832 }
1833
1834 String getThumbnailHtmlImageExcludeExtensions();
1835
1836 default boolean isThumbnailHtmlImageUrl(final String url) {
1837 if (StringUtil.isBlank(url)) {
1838 return false;
1839 }
1840
1841 String[] excludeExtensions = (String[]) propMap.get(THUMBNAIL_HTML_IMAGE_EXCLUDE_EXTENSIONS);
1842 if (excludeExtensions == null) {
1843 excludeExtensions = split(getThumbnailHtmlImageExcludeExtensions(), ",").get(stream -> stream
1844 .map(s -> s.toLowerCase(Locale.ROOT).trim()).filter(StringUtil::isNotBlank).toArray(n -> new String[n]));
1845 propMap.put(THUMBNAIL_HTML_IMAGE_EXCLUDE_EXTENSIONS, excludeExtensions);
1846 }
1847
1848 final String u = url.toLowerCase(Locale.ROOT);
1849 return !stream(excludeExtensions).get(stream -> stream.anyMatch(s -> u.endsWith(s)));
1850 }
1851
1852 String getQueryGsaResponseFields();
1853
1854 default boolean isGsaResponseFields(final String name) {
1855 @SuppressWarnings("unchecked")
1856 Set<String> gsaResponseFieldSet = (Set<String>) propMap.get(QUERY_GSA_RESPONSE_FIELDS);
1857 if (gsaResponseFieldSet == null) {
1858 gsaResponseFieldSet = split(getQueryGsaResponseFields(), ",").get(stream -> stream.map(s -> s.toLowerCase(Locale.ROOT).trim())
1859 .filter(StringUtil::isNotBlank).collect(Collectors.toSet()));
1860 propMap.put(QUERY_GSA_RESPONSE_FIELDS, gsaResponseFieldSet);
1861 }
1862 return gsaResponseFieldSet.contains(name.toLowerCase(Locale.ROOT));
1863 }
1864
1865 String getApiSearchAcceptReferers();
1866
1867 default boolean isAcceptedSearchReferer(final String referer) {
1868 Pattern[] patterns = (Pattern[]) propMap.get(API_SEARCH_ACCEPT_REFERERS);
1869 if (patterns == null) {
1870 final String refs = getApiSearchAcceptReferers();
1871 if (StringUtil.isBlank(refs)) {
1872 patterns = new Pattern[0];
1873 } else {
1874 patterns = split(refs, "\n").get(
1875 stream -> stream.filter(StringUtil::isNotBlank).map(s -> Pattern.compile(s.trim())).toArray(n -> new Pattern[n]));
1876 }
1877 propMap.put(API_SEARCH_ACCEPT_REFERERS, patterns);
1878 }
1879 if (patterns.length == 0) {
1880 return true;
1881 }
1882
1883 if (referer == null) {
1884 return false;
1885 }
1886 return Arrays.stream(patterns).anyMatch(p -> p.matcher(referer).matches());
1887 }
1888
1889 String getQueryHighlightContentDescriptionFields();
1890
1891 default String[] getQueryHighlightContentDescriptionFieldsAsArray() {
1892 return split(getQueryHighlightContentDescriptionFields(), ",")
1893 .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).toArray(n -> new String[n]));
1894 }
1895
1896 boolean isLdapIgnoreNetbiosName();
1897
1898 default String getCanonicalLdapName(final String name) {
1899 if (isLdapIgnoreNetbiosName()) {
1900 final String[] values = name.split("\\\\");
1901 if (values.length == 0) {
1902 return null;
1903 }
1904 if (values.length == 1) {
1905 return values[0];
1906 }
1907 return String.join("\\", Arrays.copyOfRange(values, 1, values.length));
1908 }
1909 return name;
1910 }
1911
1912 String getLoggingSearchDocsFields();
1913
1914 default String[] getLoggingSearchDocsFieldsAsArray() {
1915 String[] fields = (String[]) propMap.get(LOGGING_SEARCH_DOCS_FIELDS);
1916 if (fields == null) {
1917 fields = split(getLoggingSearchDocsFields(), ",").get(stream -> stream.map(String::trim).toArray(n -> new String[n]));
1918 propMap.put(LOGGING_SEARCH_DOCS_FIELDS, fields);
1919 }
1920 return fields;
1921 }
1922
1923 String getSchedulerTargetName();
1924
1925 default boolean isSchedulerTarget(final String target) {
1926 if (StringUtil.isBlank(target)) {
1927 return true;
1928 }
1929
1930 final String myName = getSchedulerTargetName();
1931
1932 final String[] targets = target.split(",");
1933 for (String name : targets) {
1934 name = name.trim();
1935 if (Constants.DEFAULT_JOB_TARGET.equalsIgnoreCase(name) || StringUtil.isNotBlank(myName) && myName.equalsIgnoreCase(name)) {
1936 return true;
1937 }
1938 }
1939 return false;
1940 }
1941
1942 String getApiGsaResponseHeaders();
1943
1944 default List<Pair<String, String>> getApiGsaResponseHeaderList() {
1945 @SuppressWarnings("unchecked")
1946 List<Pair<String, String>> list = (List<Pair<String, String>>) propMap.get(API_GSA_RESPONSE_HEADER_LIST);
1947 if (list == null) {
1948 list = split(getApiGsaResponseHeaders(), "\n").get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> {
1949 final String[] values = s.split(":", 2);
1950 if (values.length == 2) {
1951 return new Pair<>(values[0], values[1]);
1952 }
1953 return new Pair<>(values[0], StringUtil.EMPTY);
1954 }).collect(Collectors.toList()));
1955 propMap.put(API_GSA_RESPONSE_HEADER_LIST, list);
1956 }
1957 return list;
1958 }
1959
1960 String getApiJsonResponseHeaders();
1961
1962 default List<Pair<String, String>> getApiJsonResponseHeaderList() {
1963 @SuppressWarnings("unchecked")
1964 List<Pair<String, String>> list = (List<Pair<String, String>>) propMap.get(API_JSON_RESPONSE_HEADER_LIST);
1965 if (list == null) {
1966 list = split(getApiJsonResponseHeaders(), "\n").get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> {
1967 final String[] values = s.split(":", 2);
1968 if (values.length == 2) {
1969 return new Pair<>(values[0], values[1]);
1970 }
1971 return new Pair<>(values[0], StringUtil.EMPTY);
1972 }).collect(Collectors.toList()));
1973 propMap.put(API_JSON_RESPONSE_HEADER_LIST, list);
1974 }
1975 return list;
1976 }
1977
1978 String getApiDashboardResponseHeaders();
1979
1980 default List<Pair<String, String>> getApiDashboardResponseHeaderList() {
1981 @SuppressWarnings("unchecked")
1982 List<Pair<String, String>> list = (List<Pair<String, String>>) propMap.get(API_DASHBOARD_RESPONSE_HEADER_LIST);
1983 if (list == null) {
1984 list = split(getApiDashboardResponseHeaders(), "\n").get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> {
1985 final String[] values = s.split(":", 2);
1986 if (values.length == 2) {
1987 return new Pair<>(values[0], values[1]);
1988 }
1989 return new Pair<>(values[0], StringUtil.EMPTY);
1990 }).collect(Collectors.toList()));
1991 propMap.put(API_DASHBOARD_RESPONSE_HEADER_LIST, list);
1992 }
1993 return list;
1994 }
1995
1996 String getApiCorsAllowOrigin();
1997
1998 default List<String> getApiCorsAllowOriginList() {
1999 @SuppressWarnings("unchecked")
2000 List<String> list = (List<String>) propMap.get(CORS_ALLOW_ORIGIN);
2001 if (list == null) {
2002 list = split(getApiCorsAllowOrigin(), "\n")
2003 .get(stream -> stream.map(String::trim).filter(StringUtil::isNotEmpty).collect(Collectors.toList()));
2004 propMap.put(CORS_ALLOW_ORIGIN, list);
2005 }
2006 return list;
2007 }
2008
2009 String getIndexerLanguageFields();
2010
2011 default String[] getIndexerLanguageFieldsAsArray() {
2012 return split(getIndexerLanguageFields(), ",").get(stream -> stream.map(String::trim).toArray(n -> new String[n]));
2013
2014 }
2015
2016 String getSessionTrackingModes();
2017
2018 default Set<String> getSessionTrackingModesAsSet() {
2019 return split(getSessionTrackingModes(), ",")
2020 .get(stream -> stream.map(s -> s.trim().toUpperCase(Locale.ENGLISH)).collect(Collectors.toSet()));
2021 }
2022
2023 String getQueryTrackTotalHits();
2024
2025 default Object getQueryTrackTotalHitsValue() {
2026 Object value = propMap.get(QUERY_TRACK_TOTAL_HITS_VALUE);
2027 if (value == null) {
2028 final String v = getQueryTrackTotalHits();
2029 if (Constants.TRUE.equalsIgnoreCase(v)) {
2030 value = Boolean.TRUE;
2031 } else if (Constants.FALSE.equalsIgnoreCase(v)) {
2032 value = Boolean.FALSE;
2033 } else {
2034 try {
2035 value = DfTypeUtil.toInteger(v);
2036 } catch (final NumberFormatException e) {
2037 value = StringUtil.EMPTY;
2038 }
2039 }
2040 propMap.put(QUERY_TRACK_TOTAL_HITS_VALUE, value);
2041 }
2042 return value;
2043 }
2044
2045 Integer getProcessorsAsInteger();
2046
2047 default int availableProcessors() {
2048 final int num = getProcessorsAsInteger();
2049 if (num > 0) {
2050 return num;
2051 }
2052 return Runtime.getRuntime().availableProcessors();
2053 }
2054
2055 String getPluginVersionFilter();
2056
2057 default boolean isTargetPluginVersion(final String version) {
2058 final Pattern pattern;
2059 if (StringUtil.isBlank(getPluginVersionFilter())) {
2060 pattern = Pattern.compile("^" + Pattern.quote(ComponentUtil.getSystemHelper().getProductVersion()) + ".*");
2061 } else {
2062 pattern = Pattern.compile(getPluginVersionFilter());
2063 }
2064 return pattern.matcher(version).matches();
2065 }
2066
2067 String getQueryHighlightBoundaryChars();
2068
2069 default char[] getQueryHighlightBoundaryCharsAsArray() {
2070 final int[] values = getCrawlerDocumentCharsAsArray(QUERY_HIGHLIGHT_BOUNDARY_CHARS, getQueryHighlightBoundaryChars());
2071 final char[] chars = new char[values.length];
2072 for (int i = 0; i < values.length; i++) {
2073 chars[i] = (char) values[i];
2074 }
2075 return chars;
2076 }
2077
2078 String getQueryHighlightTerminalChars();
2079
2080 default int[] getQueryHighlightTerminalCharsAsArray() {
2081 return getCrawlerDocumentCharsAsArray(QUERY_HIGHLIGHT_TERMINAL_CHARS, getQueryHighlightTerminalChars());
2082 }
2083
2084 String getHttpFileuploadMaxSize();
2085
2086 default Long getHttpFileuploadMaxSizeAsLong() {
2087 final String value = getHttpFileuploadMaxSize();
2088 return value != null ? DfTypeUtil.toLong(value) : null;
2089 }
2090
2091 String getHttpFileuploadThresholdSize();
2092
2093 default Long getHttpFileuploadThresholdSizeAsLong() {
2094 final String value = getHttpFileuploadThresholdSize();
2095 return value != null ? DfTypeUtil.toLong(value) : null;
2096 }
2097
2098 String getPasswordInvalidAdminPasswords();
2099
2100 default boolean isValidAdminPassword(final String password) {
2101 return !split(getPasswordInvalidAdminPasswords(), "\n")
2102 .get(stream -> stream.map(String::trim).filter(StringUtil::isNotEmpty).anyMatch(s -> s.equals(password)));
2103 }
2104
2105 String getFesenType();
2106 }