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.io.File;
21 import java.io.IOException;
22 import java.io.UnsupportedEncodingException;
23 import java.net.InetAddress;
24 import java.net.URLEncoder;
25 import java.net.UnknownHostException;
26 import java.nio.file.Files;
27 import java.security.SecureRandom;
28 import java.time.LocalDateTime;
29 import java.util.ArrayList;
30 import java.util.Date;
31 import java.util.HashMap;
32 import java.util.LinkedHashMap;
33 import java.util.List;
34 import java.util.Locale;
35 import java.util.Map;
36 import java.util.Random;
37 import java.util.UUID;
38 import java.util.concurrent.ExecutionException;
39 import java.util.concurrent.TimeUnit;
40 import java.util.concurrent.atomic.AtomicBoolean;
41 import java.util.concurrent.atomic.AtomicInteger;
42
43 import javax.annotation.PostConstruct;
44 import javax.annotation.PreDestroy;
45 import javax.servlet.ServletContext;
46
47 import org.apache.commons.lang3.LocaleUtils;
48 import org.apache.commons.lang3.RandomStringUtils;
49 import org.apache.commons.lang3.StringUtils;
50 import org.codelibs.core.lang.StringUtil;
51 import org.codelibs.core.misc.Pair;
52 import org.codelibs.fess.Constants;
53 import org.codelibs.fess.crawler.util.CharUtil;
54 import org.codelibs.fess.mylasta.action.FessMessages;
55 import org.codelibs.fess.mylasta.action.FessUserBean;
56 import org.codelibs.fess.mylasta.direction.FessConfig;
57 import org.codelibs.fess.util.ComponentUtil;
58 import org.codelibs.fess.validation.FessActionValidator;
59 import org.lastaflute.core.message.supplier.UserMessagesCreator;
60 import org.lastaflute.web.TypicalAction;
61 import org.lastaflute.web.ruts.process.ActionRuntime;
62 import org.lastaflute.web.servlet.request.RequestManager;
63 import org.lastaflute.web.util.LaServletContextUtil;
64 import org.lastaflute.web.validation.ActionValidator;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67
68 import com.google.common.cache.CacheBuilder;
69 import com.google.common.cache.CacheLoader;
70 import com.google.common.cache.LoadingCache;
71 import com.ibm.icu.util.ULocale;
72
73 public class SystemHelper {
74 private static final Logger logger = LoggerFactory.getLogger(SystemHelper.class);
75
76 protected final Map<String, String> designJspFileNameMap = new LinkedHashMap<>();
77
78 protected final AtomicBoolean forceStop = new AtomicBoolean(false);
79
80 protected LoadingCache<String, List<Map<String, String>>> langItemsCache;
81
82 protected String filterPathEncoding;
83
84 protected String[] supportedLanguages;
85
86 protected List<Runnable> shutdownHookList = new ArrayList<>();
87
88 protected Random random = new SecureRandom();
89
90 protected AtomicInteger previousClusterState = new AtomicInteger(0);
91
92 @PostConstruct
93 public void init() {
94 final FessConfig fessConfig = ComponentUtil.getFessConfig();
95 filterPathEncoding = fessConfig.getPathEncoding();
96 supportedLanguages = fessConfig.getSupportedLanguagesAsArray();
97 langItemsCache =
98 CacheBuilder.newBuilder().maximumSize(20).expireAfterAccess(1, TimeUnit.HOURS)
99 .build(new CacheLoader<String, List<Map<String, String>>>() {
100 @Override
101 public List<Map<String, String>> load(final String key) throws Exception {
102 final ULocale uLocale = new ULocale(key);
103 final Locale displayLocale = uLocale.toLocale();
104 final List<Map<String, String>> langItems = new ArrayList<>(supportedLanguages.length);
105 final String msg = ComponentUtil.getMessageManager().getMessage(displayLocale, "labels.allLanguages");
106 final Map<String, String> defaultMap = new HashMap<>(2);
107 defaultMap.put(Constants.ITEM_LABEL, msg);
108 defaultMap.put(Constants.ITEM_VALUE, "all");
109 langItems.add(defaultMap);
110
111 for (final String lang : supportedLanguages) {
112 final Locale locale = LocaleUtils.toLocale(lang);
113 final String label = locale.getDisplayName(displayLocale);
114 final Map<String, String> map = new HashMap<>(2);
115 map.put(Constants.ITEM_LABEL, label);
116 map.put(Constants.ITEM_VALUE, lang);
117 langItems.add(map);
118 }
119 return langItems;
120 }
121 });
122
123 ComponentUtil.doInitProcesses(p -> p.run());
124 }
125
126 @PreDestroy
127 public void destroy() {
128 shutdownHookList.forEach(action -> {
129 try {
130 action.run();
131 } catch (final Exception e) {
132 logger.warn("Failed to process shutdown task.", e);
133 }
134 });
135 }
136
137 public String getUsername() {
138 final RequestManager requestManager = ComponentUtil.getRequestManager();
139 return requestManager.findUserBean(FessUserBean.class).map(user -> {
140 return user.getUserId();
141 }).orElse(Constants.GUEST_USER);
142 }
143
144 public Date getCurrentTime() {
145 return new Date();
146 }
147
148 public long getCurrentTimeAsLong() {
149 return System.currentTimeMillis();
150 }
151
152 public LocalDateTime getCurrentTimeAsLocalDateTime() {
153 return LocalDateTime.now();
154 }
155
156 public String getLogFilePath() {
157 final String value = System.getProperty("fess.log.path");
158 if (value != null) {
159 return value;
160 } else {
161 final String userDir = System.getProperty("user.dir");
162 final File targetDir = new File(userDir, "target");
163 return new File(targetDir, "logs").getAbsolutePath();
164 }
165 }
166
167 public String encodeUrlFilter(final String path) {
168 if (filterPathEncoding == null || path == null) {
169 return path;
170 }
171
172 try {
173 final StringBuilder buf = new StringBuilder(path.length() + 100);
174 for (int i = 0; i < path.length(); i++) {
175 final char c = path.charAt(i);
176 if (CharUtil.isUrlChar(c) || c == '^' || c == '{' || c == '}' || c == '|' || c == '\\') {
177 buf.append(c);
178 } else {
179 buf.append(URLEncoder.encode(String.valueOf(c), filterPathEncoding));
180 }
181 }
182 return buf.toString();
183 } catch (final UnsupportedEncodingException e) {
184 return path;
185 }
186 }
187
188 public String getHelpLink(final String name) {
189 final String url = ComponentUtil.getFessConfig().getOnlineHelpBaseLink() + name + "-guide.html";
190 return getHelpUrl(url);
191 }
192
193 protected String getHelpUrl(final String url) {
194 final Locale locale = ComponentUtil.getRequestManager().getUserLocale();
195 if (locale != null) {
196 final String lang = locale.getLanguage();
197 if (ComponentUtil.getFessConfig().isOnlineHelpSupportedLang(lang)) {
198 return url.replaceFirst("\\{lang\\}", lang).replaceFirst("\\{version\\}",
199 Constants.MAJOR_VERSION + "." + Constants.MINOR_VERSION);
200 }
201 }
202 return getDefaultHelpLink(url);
203 }
204
205 protected String getDefaultHelpLink(final String url) {
206 return url.replaceFirst("/\\{lang\\}/", "/").replaceFirst("\\{version\\}", Constants.MAJOR_VERSION + "." + Constants.MINOR_VERSION);
207 }
208
209 public void addDesignJspFileName(final String key, final String value) {
210 designJspFileNameMap.put(key, value);
211 }
212
213 public String getDesignJspFileName(final String fileName) {
214 return designJspFileNameMap.get(fileName);
215 }
216
217 @SuppressWarnings("unchecked")
218 public Pair<String, String>[] getDesignJspFileNames() {
219 return designJspFileNameMap.entrySet().stream().map(e -> new Pair<>(e.getKey(), e.getValue())).toArray(n -> new Pair[n]);
220 }
221
222 public void refreshDesignJspFiles() {
223 final ServletContext servletContext = LaServletContextUtil.getServletContext();
224 stream(ComponentUtil.getFessConfig().getVirtualHostPaths()).of(
225 stream -> stream.filter(s -> s != null && !s.equals("/")).forEach(
226 key -> {
227 designJspFileNameMap
228 .entrySet()
229 .stream()
230 .forEach(
231 e -> {
232 final File jspFile =
233 new File(servletContext.getRealPath("/WEB-INF/view" + key + "/" + e.getValue()));
234 if (!jspFile.exists()) {
235 jspFile.getParentFile().mkdirs();
236 final File baseJspFile =
237 new File(servletContext.getRealPath("/WEB-INF/view/" + e.getValue()));
238 try {
239 Files.copy(baseJspFile.toPath(), jspFile.toPath());
240 } catch (final IOException ex) {
241 logger.warn("Could not copy from " + baseJspFile.getAbsolutePath() + " to "
242 + jspFile.getAbsolutePath(), ex);
243 }
244 }
245 });
246 }));
247 }
248
249 public boolean isForceStop() {
250 return forceStop.get();
251 }
252
253 public void setForceStop(final boolean b) {
254 forceStop.set(true);
255 }
256
257 public String generateDocId(final Map<String, Object> map) {
258 return UUID.randomUUID().toString().replace("-", StringUtil.EMPTY);
259 }
260
261 public String abbreviateLongText(final String str) {
262 return StringUtils.abbreviate(str, ComponentUtil.getFessConfig().getMaxLogOutputLengthAsInteger().intValue());
263 }
264
265 public String normalizeLang(final String value) {
266 if (StringUtil.isBlank(value)) {
267 return null;
268 }
269
270 final String localeName = value.trim().toLowerCase(Locale.ENGLISH).replace("-", "_");
271
272 for (final String supportedLang : supportedLanguages) {
273 if (localeName.startsWith(supportedLang.toLowerCase(Locale.ENGLISH))) {
274 return supportedLang;
275 }
276 }
277 return null;
278 }
279
280 public List<Map<String, String>> getLanguageItems(final Locale locale) {
281 try {
282 final String localeStr = locale.toString();
283 return langItemsCache.get(localeStr);
284 } catch (final ExecutionException e) {
285 final List<Map<String, String>> langItems = new ArrayList<>(supportedLanguages.length);
286 final String msg = ComponentUtil.getMessageManager().getMessage(locale, "labels.allLanguages");
287 final Map<String, String> defaultMap = new HashMap<>(2);
288 defaultMap.put(Constants.ITEM_LABEL, msg);
289 defaultMap.put(Constants.ITEM_VALUE, "all");
290 langItems.add(defaultMap);
291 return langItems;
292 }
293 }
294
295 public void sleep(final int sec) {
296 try {
297 Thread.sleep(sec * 1000L);
298 } catch (final InterruptedException e) {
299 if (logger.isDebugEnabled()) {
300 logger.debug("Interrupted.", e);
301 }
302 }
303 }
304
305 public void addShutdownHook(final Runnable hook) {
306 shutdownHookList.add(hook);
307 }
308
309 public String getHostname() {
310 final Map<String, String> env = System.getenv();
311 if (env.containsKey("COMPUTERNAME")) {
312 return env.get("COMPUTERNAME");
313 } else if (env.containsKey("HOSTNAME")) {
314 return env.get("HOSTNAME");
315 }
316 try {
317 return InetAddress.getLocalHost().getHostAddress();
318 } catch (final UnknownHostException e) {
319 logger.debug("Unknown hostname.", e);
320 }
321 return "Unknown";
322 }
323
324 public void setupAdminHtmlData(final TypicalAction action, final ActionRuntime runtime) {
325 runtime.registerData("developmentMode", ComponentUtil.getFessEsClient().isEmbedded());
326 final String url = ComponentUtil.getFessConfig().getOnlineHelpInstallation();
327 runtime.registerData("installationLink", getHelpUrl(url));
328 }
329
330 public String getSearchRoleByUser(final String name) {
331 return createSearchRole(ComponentUtil.getFessConfig().getRoleSearchUserPrefix(), name);
332 }
333
334 public String getSearchRoleByGroup(final String name) {
335 return createSearchRole(ComponentUtil.getFessConfig().getRoleSearchGroupPrefix(), name);
336 }
337
338 public String getSearchRoleByRole(final String name) {
339 return createSearchRole(ComponentUtil.getFessConfig().getRoleSearchRolePrefix(), name);
340 }
341
342 protected String createSearchRole(final String type, final String name) {
343 return type + name;
344 }
345
346 public void reloadConfiguration() {
347 ComponentUtil.getFessEsClient().refresh();
348 ComponentUtil.getLabelTypeHelper().init();
349 ComponentUtil.getPathMappingHelper().init();
350 ComponentUtil.getSuggestHelper().init();
351 ComponentUtil.getPopularWordHelper().init();
352 ComponentUtil.getJobManager().reboot();
353 ComponentUtil.getLdapManager().updateConfig();
354 ComponentUtil.getRelatedContentHelper().update();
355 ComponentUtil.getRelatedQueryHelper().update();
356 }
357
358 public String generateAccessToken() {
359 return RandomStringUtils.random(ComponentUtil.getFessConfig().getApiAccessTokenLengthAsInteger().intValue(), 0, 0, true, true,
360 null, random);
361 }
362
363 public void setRandom(final Random random) {
364 this.random = random;
365 }
366
367 public boolean isChangedClusterState(final int status) {
368 return previousClusterState.getAndSet(status) != status;
369 }
370
371 public ActionValidator<FessMessages> createValidator(final RequestManager requestManager,
372 final UserMessagesCreator<FessMessages> messagesCreator, final Class<?>[] runtimeGroups) {
373 return new FessActionValidator<>(requestManager, messagesCreator, runtimeGroups);
374 }
375
376 }