1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.helper;
17
18 import static org.codelibs.core.stream.StreamUtil.stream;
19
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Locale;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.regex.Pattern;
29 import java.util.stream.Collectors;
30
31 import org.apache.logging.log4j.LogManager;
32 import org.apache.logging.log4j.Logger;
33 import org.codelibs.core.lang.StringUtil;
34 import org.codelibs.fess.Constants;
35 import org.codelibs.fess.app.service.LabelTypeService;
36 import org.codelibs.fess.entity.SearchRequestParams.SearchRequestType;
37 import org.codelibs.fess.opensearch.config.exentity.LabelType;
38 import org.codelibs.fess.util.ComponentUtil;
39
40 import jakarta.annotation.PostConstruct;
41
42
43
44
45 public class LabelTypeHelper extends AbstractConfigHelper {
46 private static final Logger logger = LogManager.getLogger(LabelTypeHelper.class);
47
48
49 protected volatile List<LabelTypeItem> labelTypeItemList;
50
51
52 protected volatile List<LabelTypePattern> labelTypePatternList;
53
54
55
56
57 public LabelTypeHelper() {
58 super();
59 }
60
61
62
63
64 @PostConstruct
65 public void init() {
66 if (logger.isDebugEnabled()) {
67 logger.debug("Initializing {}", this.getClass().getSimpleName());
68 }
69 load();
70 }
71
72 @Override
73 public int load() {
74 final List<LabelType> labelTypeList = ComponentUtil.getComponent(LabelTypeService.class).getLabelTypeList();
75 buildLabelTypeItems(labelTypeList);
76 buildLabelTypePatternList(labelTypeList);
77 return labelTypeList.size();
78 }
79
80
81
82
83
84
85 public void refresh(final List<LabelType> labelTypeList) {
86 buildLabelTypeItems(labelTypeList);
87 buildLabelTypePatternList(labelTypeList);
88 }
89
90
91
92
93
94
95 protected void buildLabelTypeItems(final List<LabelType> labelTypeList) {
96 final List<LabelTypeItem> itemList = new ArrayList<>();
97 for (final LabelType labelType : labelTypeList) {
98 final LabelTypeItem item = new LabelTypeItem();
99 item.setLabel(labelType.getName());
100 item.setValue(labelType.getValue());
101 item.setPermissions(labelType.getPermissions());
102 item.setVirtualHost(labelType.getVirtualHost());
103 item.setLocale(labelType.getLocale());
104 itemList.add(item);
105 }
106 labelTypeItemList = itemList;
107 }
108
109
110
111
112
113
114
115 public List<Map<String, String>> getLabelTypeItemList(final SearchRequestType searchRequestType) {
116 return getLabelTypeItemList(searchRequestType, Locale.ROOT);
117 }
118
119
120
121
122
123
124
125
126 public List<Map<String, String>> getLabelTypeItemList(final SearchRequestType searchRequestType, final Locale requestLocale) {
127 if (labelTypeItemList == null) {
128 init();
129 }
130
131 final String virtualHostKey = ComponentUtil.getVirtualHostHelper().getVirtualHostKey();
132 final List<LabelTypeItem> labelList;
133 if (StringUtil.isBlank(virtualHostKey)) {
134 labelList =
135 labelTypeItemList.stream().filter(item -> matchLocale(requestLocale, item.getLocale())).collect(Collectors.toList());
136 } else {
137 labelList = labelTypeItemList.stream()
138 .filter(item -> matchLocale(requestLocale, item.getLocale()) && virtualHostKey.equals(item.getVirtualHost()))
139 .collect(Collectors.toList());
140 }
141
142 final List<Map<String, String>> itemList = new ArrayList<>();
143 final Set<String> roleSet = ComponentUtil.getRoleQueryHelper().build(searchRequestType);
144 if (roleSet.isEmpty()) {
145 for (final LabelTypeItem item : labelList) {
146 if (item.getPermissions().length == 0) {
147 final Map<String, String> map = new HashMap<>(2);
148 map.put(Constants.ITEM_LABEL, item.getLabel());
149 map.put(Constants.ITEM_VALUE, item.getValue());
150 itemList.add(map);
151 }
152 }
153 } else {
154 for (final LabelTypeItem item : labelList) {
155 final Set<String> permissions = stream(item.getPermissions()).get(stream -> stream.collect(Collectors.toSet()));
156 for (final String roleValue : roleSet) {
157 if (permissions.contains(roleValue)) {
158 final Map<String, String> map = new HashMap<>(2);
159 map.put(Constants.ITEM_LABEL, item.getLabel());
160 map.put(Constants.ITEM_VALUE, item.getValue());
161 itemList.add(map);
162 break;
163 }
164 }
165 }
166 }
167
168 return itemList;
169 }
170
171
172
173
174
175
176
177
178 protected boolean matchLocale(final Locale requestLocale, final Locale targetLocale) {
179 if (targetLocale.equals(requestLocale) || targetLocale.equals(Locale.ROOT)) {
180 return true;
181 }
182 if (requestLocale == null || !requestLocale.getLanguage().equals(targetLocale.getLanguage())
183 || targetLocale.getCountry().length() > 0 && !requestLocale.getCountry().equals(targetLocale.getCountry())) {
184 return false;
185 }
186 return true;
187 }
188
189
190
191
192
193
194
195 public Set<String> getMatchedLabelValueSet(final String path) {
196 if (labelTypePatternList == null) {
197 synchronized (this) {
198 if (labelTypePatternList == null) {
199 buildLabelTypePatternList(ComponentUtil.getComponent(LabelTypeService.class).getLabelTypeList());
200 }
201 }
202 }
203
204 if (labelTypePatternList.isEmpty()) {
205 return Collections.emptySet();
206 }
207
208 final Set<String> valueSet = new HashSet<>();
209 for (final LabelTypePattern pattern : labelTypePatternList) {
210 if (pattern.match(path)) {
211 valueSet.add(pattern.getValue());
212 }
213 }
214 return valueSet;
215 }
216
217
218
219
220
221
222 protected void buildLabelTypePatternList(final List<LabelType> labelTypeList) {
223 final List<LabelTypePattern> list = new ArrayList<>();
224 for (final LabelType labelType : labelTypeList) {
225 final String includedPaths = labelType.getIncludedPaths();
226 final String excludedPaths = labelType.getExcludedPaths();
227 if (StringUtil.isNotBlank(includedPaths) || StringUtil.isNotBlank(excludedPaths)) {
228 try {
229 list.add(new LabelTypePattern(labelType.getValue(), includedPaths, excludedPaths));
230 } catch (final Exception e) {
231 logger.warn("Failed to create label pattern: label={}, includedPaths={}, excludedPaths={}", labelType.getValue(),
232 includedPaths, excludedPaths, e);
233 }
234 }
235 }
236 labelTypePatternList = list;
237 }
238
239
240
241
242 protected static class LabelTypeItem {
243
244
245
246 public LabelTypeItem() {
247
248 }
249
250 private String label;
251
252 private String value;
253
254 private String[] permissions;
255
256 private String virtualHost;
257
258 private Locale locale;
259
260
261
262
263
264
265 public String getLabel() {
266 return label;
267 }
268
269
270
271
272
273
274 public void setLabel(final String label) {
275 this.label = label;
276 }
277
278
279
280
281
282
283 public String getValue() {
284 return value;
285 }
286
287
288
289
290
291
292 public void setValue(final String value) {
293 this.value = value;
294 }
295
296
297
298
299
300
301 public String[] getPermissions() {
302 return permissions;
303 }
304
305
306
307
308
309
310 public void setPermissions(final String[] permissions) {
311 this.permissions = permissions;
312 }
313
314
315
316
317
318
319 public String getVirtualHost() {
320 return virtualHost;
321 }
322
323
324
325
326
327
328 public void setVirtualHost(final String virtualHost) {
329 this.virtualHost = virtualHost;
330 }
331
332
333
334
335
336
337 public Locale getLocale() {
338 return locale;
339 }
340
341
342
343
344
345
346 public void setLocale(final Locale locale) {
347 this.locale = locale;
348 }
349 }
350
351
352
353
354 public static class LabelTypePattern {
355
356 private final String value;
357
358 private Pattern includedPaths;
359
360 private Pattern excludedPaths;
361
362
363
364
365
366
367
368
369 public LabelTypePattern(final String value, final String includedPaths, final String excludedPaths) {
370 this.value = value;
371
372 final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
373 if (StringUtil.isNotBlank(includedPaths)) {
374 final StringBuilder buf = new StringBuilder(100);
375 char split = 0;
376 for (final String path : includedPaths.split("\n")) {
377 if (split == 0) {
378 split = '|';
379 } else {
380 buf.append(split);
381 }
382 final String normalizePath = systemHelper.normalizeConfigPath(path);
383 if (StringUtil.isNotBlank(normalizePath)) {
384 buf.append(normalizePath);
385 }
386 }
387 this.includedPaths = Pattern.compile(buf.toString());
388 }
389
390 if (StringUtil.isNotBlank(excludedPaths)) {
391 final StringBuilder buf = new StringBuilder(100);
392 char split = 0;
393 for (final String path : excludedPaths.split("\n")) {
394 if (split == 0) {
395 split = '|';
396 } else {
397 buf.append(split);
398 }
399 final String normalizePath = systemHelper.normalizeConfigPath(path);
400 if (StringUtil.isNotBlank(normalizePath)) {
401 buf.append(normalizePath);
402 }
403 }
404 this.excludedPaths = Pattern.compile(buf.toString());
405 }
406 }
407
408
409
410
411
412
413 public String getValue() {
414 return value;
415 }
416
417
418
419
420
421
422
423 public boolean match(final String path) {
424 if (includedPaths == null) {
425 if (excludedPaths != null && excludedPaths.matcher(path).matches()) {
426 if (logger.isDebugEnabled()) {
427 logger.debug("Path {} matches the exclude path expression {} on {} of label.", path, excludedPaths, value);
428 }
429 return false;
430 }
431 if (logger.isDebugEnabled()) {
432 logger.debug("Path {} does not match the exclude path expression {} on {} of label.", path, excludedPaths, value);
433 }
434 return true;
435 }
436 if (includedPaths.matcher(path).matches()) {
437 if (excludedPaths != null && excludedPaths.matcher(path).matches()) {
438 if (logger.isDebugEnabled()) {
439 logger.debug("Path {} matches the include/exclude path expression {} on {} of label.", path, excludedPaths, value);
440 }
441 return false;
442 }
443 if (logger.isDebugEnabled()) {
444 logger.debug("Path {} matches the include path expression {} on {} of label.", path, excludedPaths, value);
445 }
446 return true;
447 }
448 if (logger.isDebugEnabled()) {
449 logger.debug("Path {} does not match the include path expression {} on {} of label.", path, excludedPaths, value);
450 }
451 return false;
452 }
453
454 }
455 }