1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.helper;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.function.BiFunction;
23 import java.util.regex.Matcher;
24
25 import javax.annotation.PostConstruct;
26
27 import org.apache.logging.log4j.LogManager;
28 import org.apache.logging.log4j.Logger;
29 import org.codelibs.core.lang.StringUtil;
30 import org.codelibs.fess.Constants;
31 import org.codelibs.fess.es.config.exbhv.PathMappingBhv;
32 import org.codelibs.fess.es.config.exentity.PathMapping;
33 import org.codelibs.fess.util.ComponentUtil;
34 import org.codelibs.fess.util.DocumentUtil;
35 import org.lastaflute.di.core.exception.ComponentNotFoundException;
36 import org.lastaflute.di.core.factory.SingletonLaContainerFactory;
37 import org.lastaflute.web.util.LaRequestUtil;
38
39 public class PathMappingHelper extends AbstractConfigHelper {
40
41 private static final Logger logger = LogManager.getLogger(PathMappingHelper.class);
42
43 protected static final String FUNCTION_ENCODEURL_MATCHER = "function:encodeUrl";
44
45 protected static final String GROOVY_MATCHER = "groovy:";
46
47 protected final Map<String, List<PathMapping>> pathMappingMap = new HashMap<>();
48
49 protected volatile List<PathMapping> cachedPathMappingList = null;
50
51 @PostConstruct
52 public void init() {
53 if (logger.isDebugEnabled()) {
54 logger.debug("Initialize {}", this.getClass().getSimpleName());
55 }
56 load();
57 }
58
59 @Override
60 public int load() {
61 final List<String> ptList = getProcessTypeList();
62
63 try {
64 final PathMappingBhv pathMappingBhv = ComponentUtil.getComponent(PathMappingBhv.class);
65 cachedPathMappingList = pathMappingBhv.selectList(cb -> {
66 cb.query().addOrderBy_SortOrder_Asc();
67 cb.query().setProcessType_InScope(ptList);
68 cb.fetchFirst(ComponentUtil.getFessConfig().getPagePathMappingMaxFetchSizeAsInteger());
69 });
70 return cachedPathMappingList.size();
71 } catch (final ComponentNotFoundException e) {
72 if (logger.isDebugEnabled()) {
73 logger.debug("Failed to load path mappings.", e);
74 }
75 cachedPathMappingList = new ArrayList<>();
76 } catch (final Exception e) {
77 logger.warn("Failed to load path mappings.", e);
78 }
79 return 0;
80 }
81
82 protected List<String> getProcessTypeList() {
83 final List<String> ptList = new ArrayList<>();
84 final String executeType = System.getProperty("lasta.env");
85 if (Constants.EXECUTE_TYPE_CRAWLER.equalsIgnoreCase(executeType)) {
86 ptList.add(Constants.PROCESS_TYPE_REPLACE);
87 } else {
88 ptList.add(Constants.PROCESS_TYPE_DISPLAYING);
89 ptList.add(Constants.PROCESS_TYPE_BOTH);
90 }
91 return ptList;
92 }
93
94 public void setPathMappingList(final String sessionId, final List<PathMapping> pathMappingList) {
95 if (sessionId != null) {
96 if (pathMappingList != null) {
97 pathMappingMap.put(sessionId, pathMappingList);
98 } else {
99 removePathMappingList(sessionId);
100 }
101 }
102 }
103
104 public void removePathMappingList(final String sessionId) {
105 pathMappingMap.remove(sessionId);
106 }
107
108 public List<PathMapping> getPathMappingList(final String sessionId) {
109 if (sessionId == null) {
110 return null;
111 }
112 return pathMappingMap.get(sessionId);
113 }
114
115 public String replaceUrl(final String sessionId, final String url) {
116 final List<PathMapping> pathMappingList = getPathMappingList(sessionId);
117 if (pathMappingList == null) {
118 return url;
119 }
120 return replaceUrl(pathMappingList, url);
121 }
122
123 public String replaceUrls(final String text) {
124 if (cachedPathMappingList == null) {
125 synchronized (this) {
126 if (cachedPathMappingList == null) {
127 init();
128 }
129 }
130 }
131 String result = text;
132 for (final PathMapping pathMapping : cachedPathMappingList) {
133 if (matchUserAgent(pathMapping)) {
134 String replacement = pathMapping.getReplacement();
135 if (replacement == null) {
136 replacement = StringUtil.EMPTY;
137 }
138 result = result.replaceAll("(\"[^\"]*)" + pathMapping.getRegex() + "([^\"]*\")", "$1" + replacement + "$2");
139 }
140 }
141 return result;
142 }
143
144 public String replaceUrl(final String url) {
145 if (cachedPathMappingList == null) {
146 synchronized (this) {
147 if (cachedPathMappingList == null) {
148 init();
149 }
150 }
151 }
152 return replaceUrl(cachedPathMappingList, url);
153 }
154
155 public BiFunction<String, Matcher, String> createPathMatcher(final Matcher matcher, final String replacement) {
156 if (FUNCTION_ENCODEURL_MATCHER.equals(replacement)) {
157 return (u, m) -> DocumentUtil.encodeUrl(u);
158 }
159 if (!replacement.startsWith(GROOVY_MATCHER)) {
160 return (u, m) -> m.replaceAll(replacement);
161 }
162 final String template = replacement.substring(GROOVY_MATCHER.length());
163 return (u, m) -> {
164 final Map<String, Object> paramMap = new HashMap<>();
165 paramMap.put("url", u);
166 paramMap.put("matcher", m);
167 final Object value =
168 ComponentUtil.getScriptEngineFactory().getScriptEngine(Constants.DEFAULT_SCRIPT).evaluate(template, paramMap);
169 if (value == null) {
170 return u;
171 }
172 return value.toString();
173 };
174 }
175
176 protected String replaceUrl(final List<PathMapping> pathMappingList, final String url) {
177 String newUrl = url;
178 for (final PathMapping pathMapping : pathMappingList) {
179 if (matchUserAgent(pathMapping)) {
180 newUrl = pathMapping.process(this, newUrl);
181 }
182 }
183 return newUrl;
184 }
185
186 protected boolean matchUserAgent(final PathMapping pathMapping) {
187 if (!pathMapping.hasUAMathcer()) {
188 return true;
189 }
190
191 if (SingletonLaContainerFactory.getExternalContext().getRequest() != null) {
192 return LaRequestUtil.getOptionalRequest().map(request -> {
193 final String userAgent = request.getHeader("user-agent");
194 if (StringUtil.isBlank(userAgent)) {
195 return false;
196 }
197
198 return pathMapping.getUAMatcher(userAgent).find();
199 }).orElse(false);
200 }
201 return false;
202 }
203 }