View Javadoc
1   /*
2    * Copyright 2012-2021 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
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 javax.annotation.PostConstruct;
32  
33  import org.apache.logging.log4j.LogManager;
34  import org.apache.logging.log4j.Logger;
35  import org.codelibs.core.lang.StringUtil;
36  import org.codelibs.fess.Constants;
37  import org.codelibs.fess.app.service.LabelTypeService;
38  import org.codelibs.fess.entity.SearchRequestParams.SearchRequestType;
39  import org.codelibs.fess.es.config.exentity.LabelType;
40  import org.codelibs.fess.util.ComponentUtil;
41  
42  public class LabelTypeHelper extends AbstractConfigHelper {
43      private static final Logger logger = LogManager.getLogger(LabelTypeHelper.class);
44  
45      protected volatile List<LabelTypeItem> labelTypeItemList;
46  
47      protected volatile List<LabelTypePattern> labelTypePatternList;
48  
49      @PostConstruct
50      public void init() {
51          if (logger.isDebugEnabled()) {
52              logger.debug("Initialize {}", this.getClass().getSimpleName());
53          }
54          load();
55      }
56  
57      @Override
58      public int load() {
59          final List<LabelType> labelTypeList = ComponentUtil.getComponent(LabelTypeService.class).getLabelTypeList();
60          buildLabelTypeItems(labelTypeList);
61          buildLabelTypePatternList(labelTypeList);
62          return labelTypeList.size();
63      }
64  
65      public void refresh(final List<LabelType> labelTypeList) {
66          buildLabelTypeItems(labelTypeList);
67          buildLabelTypePatternList(labelTypeList);
68      }
69  
70      protected void buildLabelTypeItems(final List<LabelType> labelTypeList) {
71          final List<LabelTypeItem> itemList = new ArrayList<>();
72          for (final LabelType labelType : labelTypeList) {
73              final LabelTypeItem item = new LabelTypeItem();
74              item.setLabel(labelType.getName());
75              item.setValue(labelType.getValue());
76              item.setPermissions(labelType.getPermissions());
77              item.setVirtualHost(labelType.getVirtualHost());
78              item.setLocale(labelType.getLocale());
79              itemList.add(item);
80          }
81          labelTypeItemList = itemList;
82      }
83  
84      public List<Map<String, String>> getLabelTypeItemList(final SearchRequestType searchRequestType) {
85          return getLabelTypeItemList(searchRequestType, Locale.ROOT);
86      }
87  
88      public List<Map<String, String>> getLabelTypeItemList(final SearchRequestType searchRequestType, final Locale requestLocale) {
89          if (labelTypeItemList == null) {
90              init();
91          }
92  
93          final String virtualHostKey = ComponentUtil.getVirtualHostHelper().getVirtualHostKey();
94          final List<LabelTypeItem> labelList;
95          if (StringUtil.isBlank(virtualHostKey)) {
96              labelList =
97                      labelTypeItemList.stream().filter(item -> matchLocale(requestLocale, item.getLocale())).collect(Collectors.toList());
98          } else {
99              labelList = labelTypeItemList.stream()
100                     .filter(item -> matchLocale(requestLocale, item.getLocale()) && virtualHostKey.equals(item.getVirtualHost()))
101                     .collect(Collectors.toList());
102         }
103 
104         final List<Map<String, String>> itemList = new ArrayList<>();
105         final Set<String> roleSet = ComponentUtil.getRoleQueryHelper().build(searchRequestType);
106         if (roleSet.isEmpty()) {
107             for (final LabelTypeItem item : labelList) {
108                 if (item.getPermissions().length == 0) {
109                     final Map<String, String> map = new HashMap<>(2);
110                     map.put(Constants.ITEM_LABEL, item.getLabel());
111                     map.put(Constants.ITEM_VALUE, item.getValue());
112                     itemList.add(map);
113                 }
114             }
115         } else {
116             for (final LabelTypeItem item : labelList) {
117                 final Set<String> permissions = stream(item.getPermissions()).get(stream -> stream.collect(Collectors.toSet()));
118                 for (final String roleValue : roleSet) {
119                     if (permissions.contains(roleValue)) {
120                         final Map<String, String> map = new HashMap<>(2);
121                         map.put(Constants.ITEM_LABEL, item.getLabel());
122                         map.put(Constants.ITEM_VALUE, item.getValue());
123                         itemList.add(map);
124                         break;
125                     }
126                 }
127             }
128         }
129 
130         return itemList;
131     }
132 
133     protected boolean matchLocale(final Locale requestLocale, final Locale targetLocale) {
134         if (targetLocale.equals(requestLocale) || targetLocale.equals(Locale.ROOT)) {
135             return true;
136         }
137         if (requestLocale == null) {
138             return false;
139         }
140         if (!requestLocale.getLanguage().equals(targetLocale.getLanguage())) {
141             return false;
142         }
143         if (targetLocale.getCountry().length() > 0 && !requestLocale.getCountry().equals(targetLocale.getCountry())) {
144             return false;
145         }
146         return true;
147     }
148 
149     public Set<String> getMatchedLabelValueSet(final String path) {
150         if (labelTypePatternList == null) {
151             synchronized (this) {
152                 if (labelTypePatternList == null) {
153                     buildLabelTypePatternList(ComponentUtil.getComponent(LabelTypeService.class).getLabelTypeList());
154                 }
155             }
156         }
157 
158         if (labelTypePatternList.isEmpty()) {
159             return Collections.emptySet();
160         }
161 
162         final Set<String> valueSet = new HashSet<>();
163         for (final LabelTypePattern pattern : labelTypePatternList) {
164             if (pattern.match(path)) {
165                 valueSet.add(pattern.getValue());
166             }
167         }
168         return valueSet;
169     }
170 
171     protected void buildLabelTypePatternList(final List<LabelType> labelTypeList) {
172         final List<LabelTypePattern> list = new ArrayList<>();
173         for (final LabelType labelType : labelTypeList) {
174             final String includedPaths = labelType.getIncludedPaths();
175             final String excludedPaths = labelType.getExcludedPaths();
176             if (StringUtil.isNotBlank(includedPaths) || StringUtil.isNotBlank(excludedPaths)) {
177                 try {
178                     list.add(new LabelTypePattern(labelType.getValue(), includedPaths, excludedPaths));
179                 } catch (final Exception e) {
180                     logger.warn("Failed to create a matching pattern of a label: {}, includedPaths:{}, excludedPaths:{}",
181                             labelType.getValue(), includedPaths, excludedPaths, e);
182                 }
183             }
184         }
185         labelTypePatternList = list;
186     }
187 
188     protected static class LabelTypeItem {
189         private String label;
190 
191         private String value;
192 
193         private String[] permissions;
194 
195         private String virtualHost;
196 
197         private Locale locale;
198 
199         public String getLabel() {
200             return label;
201         }
202 
203         public void setLabel(final String label) {
204             this.label = label;
205         }
206 
207         public String getValue() {
208             return value;
209         }
210 
211         public void setValue(final String value) {
212             this.value = value;
213         }
214 
215         public String[] getPermissions() {
216             return permissions;
217         }
218 
219         public void setPermissions(final String[] permissions) {
220             this.permissions = permissions;
221         }
222 
223         public String getVirtualHost() {
224             return virtualHost;
225         }
226 
227         public void setVirtualHost(final String virtualHost) {
228             this.virtualHost = virtualHost;
229         }
230 
231         public Locale getLocale() {
232             return locale;
233         }
234 
235         public void setLocale(Locale locale) {
236             this.locale = locale;
237         }
238     }
239 
240     public static class LabelTypePattern {
241 
242         private final String value;
243 
244         private Pattern includedPaths;
245 
246         private Pattern excludedPaths;
247 
248         public LabelTypePattern(final String value, final String includedPaths, final String excludedPaths) {
249             this.value = value;
250 
251             final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
252             if (StringUtil.isNotBlank(includedPaths)) {
253                 final StringBuilder buf = new StringBuilder(100);
254                 char split = 0;
255                 for (final String path : includedPaths.split("\n")) {
256                     if (split == 0) {
257                         split = '|';
258                     } else {
259                         buf.append(split);
260                     }
261                     final String normalizePath = systemHelper.normalizeConfigPath(path);
262                     if (StringUtil.isNotBlank(normalizePath)) {
263                         buf.append(normalizePath);
264                     }
265                 }
266                 this.includedPaths = Pattern.compile(buf.toString());
267             }
268 
269             if (StringUtil.isNotBlank(excludedPaths)) {
270                 final StringBuilder buf = new StringBuilder(100);
271                 char split = 0;
272                 for (final String path : excludedPaths.split("\n")) {
273                     if (split == 0) {
274                         split = '|';
275                     } else {
276                         buf.append(split);
277                     }
278                     final String normalizePath = systemHelper.normalizeConfigPath(path);
279                     if (StringUtil.isNotBlank(normalizePath)) {
280                         buf.append(normalizePath);
281                     }
282                 }
283                 this.excludedPaths = Pattern.compile(buf.toString());
284             }
285         }
286 
287         public String getValue() {
288             return value;
289         }
290 
291         public boolean match(final String path) {
292             if (includedPaths == null) {
293                 if (excludedPaths != null && excludedPaths.matcher(path).matches()) {
294                     if (logger.isDebugEnabled()) {
295                         logger.debug("Path {} matches the exclude path expression {} on {} of label.", path, excludedPaths, value);
296                     }
297                     return false;
298                 }
299                 if (logger.isDebugEnabled()) {
300                     logger.debug("Path {} does not match the exclude path expression {} on {} of label.", path, excludedPaths, value);
301                 }
302                 return true;
303             }
304             if (includedPaths.matcher(path).matches()) {
305                 if (excludedPaths != null && excludedPaths.matcher(path).matches()) {
306                     if (logger.isDebugEnabled()) {
307                         logger.debug("Path {} matches the include/exclude path expression {} on {} of label.", path, excludedPaths, value);
308                     }
309                     return false;
310                 }
311                 if (logger.isDebugEnabled()) {
312                     logger.debug("Path {} matches the include path expression {} on {} of label.", path, excludedPaths, value);
313                 }
314                 return true;
315             }
316             if (logger.isDebugEnabled()) {
317                 logger.debug("Path {} does not match the include path expression {} on {} of label.", path, excludedPaths, value);
318             }
319             return false;
320         }
321 
322     }
323 }