View Javadoc
1   /*
2    * Copyright 2012-2017 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.taglib;
17  
18  import java.io.File;
19  import java.math.RoundingMode;
20  import java.nio.file.Files;
21  import java.nio.file.Path;
22  import java.nio.file.Paths;
23  import java.text.DecimalFormat;
24  import java.text.ParseException;
25  import java.text.SimpleDateFormat;
26  import java.time.LocalDateTime;
27  import java.time.format.DateTimeFormatter;
28  import java.util.Base64;
29  import java.util.Date;
30  import java.util.Enumeration;
31  import java.util.List;
32  import java.util.Locale;
33  import java.util.Map;
34  import java.util.concurrent.ExecutionException;
35  import java.util.concurrent.TimeUnit;
36  import java.util.stream.Collectors;
37  
38  import javax.servlet.http.HttpServletRequest;
39  
40  import org.apache.commons.text.StringEscapeUtils;
41  import org.codelibs.core.lang.StringUtil;
42  import org.codelibs.fess.Constants;
43  import org.codelibs.fess.entity.FacetQueryView;
44  import org.codelibs.fess.helper.ViewHelper;
45  import org.codelibs.fess.util.ComponentUtil;
46  import org.lastaflute.di.util.LdiURLUtil;
47  import org.lastaflute.web.util.LaRequestUtil;
48  import org.lastaflute.web.util.LaResponseUtil;
49  import org.lastaflute.web.util.LaServletContextUtil;
50  import org.slf4j.Logger;
51  import org.slf4j.LoggerFactory;
52  
53  import com.google.common.cache.CacheBuilder;
54  import com.google.common.cache.CacheLoader;
55  import com.google.common.cache.LoadingCache;
56  
57  public class FessFunctions {
58      private static final Logger logger = LoggerFactory.getLogger(FessFunctions.class);
59  
60      private static final String GEO_PREFIX = "geo.";
61  
62      private static final String FACET_PREFIX = "facet.";
63  
64      private static LoadingCache<String, Long> resourceHashCache = CacheBuilder.newBuilder().maximumSize(1000)
65              .expireAfterWrite(10, TimeUnit.MINUTES).build(new CacheLoader<String, Long>() {
66                  @Override
67                  public Long load(final String key) throws Exception {
68                      try {
69                          final Path path = Paths.get(LaServletContextUtil.getServletContext().getRealPath(key));
70                          if (Files.isRegularFile(path)) {
71                              return Files.getLastModifiedTime(path).toMillis();
72                          }
73                      } catch (final Exception e) {
74                          logger.debug("Failed to access " + key, e);
75                      }
76                      return 0L;
77                  }
78              });
79  
80      protected FessFunctions() {
81          // nothing
82      }
83  
84      public static Boolean labelExists(final String value) {
85          @SuppressWarnings("unchecked")
86          final Map<String, String> labelValueMap = (Map<String, String>) LaRequestUtil.getRequest().getAttribute(Constants.LABEL_VALUE_MAP);
87          if (labelValueMap != null) {
88              return labelValueMap.get(value) != null;
89          }
90          return false;
91      }
92  
93      public static String label(final String value) {
94          @SuppressWarnings("unchecked")
95          final Map<String, String> labelValueMap = (Map<String, String>) LaRequestUtil.getRequest().getAttribute(Constants.LABEL_VALUE_MAP);
96          if (labelValueMap != null) {
97              final String name = labelValueMap.get(value);
98              if (name != null) {
99                  return name;
100             }
101         }
102         return value;
103     }
104 
105     public static Date date(final Long value) {
106         if (value == null) {
107             return null;
108         }
109         return new Date(value.longValue());
110     }
111 
112     public static Date parseDate(final String value) {
113         return parseDate(value, Constants.ISO_DATETIME_FORMAT);
114     }
115 
116     public static Date parseDate(final String value, final String format) {
117         if (value == null) {
118             return null;
119         }
120         try {
121             final SimpleDateFormat sdf = new SimpleDateFormat(format);
122             sdf.setTimeZone(Constants.TIMEZONE_UTC);
123             return sdf.parse(value);
124         } catch (final ParseException e) {
125             return null;
126         }
127     }
128 
129     public static String formatDate(final Date date) {
130         final SimpleDateFormat sdf = new SimpleDateFormat(Constants.ISO_DATETIME_FORMAT);
131         sdf.setTimeZone(Constants.TIMEZONE_UTC);
132         return sdf.format(date);
133     }
134 
135     public static String formatDate(final LocalDateTime date) {
136         return date.format(DateTimeFormatter.ofPattern(Constants.ISO_DATETIME_FORMAT, Locale.ROOT));
137     }
138 
139     public static String formatNumber(final long value) {
140         int ratio = 1;
141         String unit = "";
142         String format = "0.#";
143         if (value < 1024) {
144             format = "0";
145         } else if (value < (1024 * 1024)) {
146             ratio = 1024;
147             unit = "K";
148         } else if (value < (1024 * 1024 * 1024)) {
149             ratio = 1024 * 1024;
150             unit = "M";
151         } else {
152             ratio = 1024 * 1024 * 1024;
153             unit = "G";
154         }
155         final DecimalFormat df = new DecimalFormat(format + unit);
156         df.setRoundingMode(RoundingMode.HALF_UP);
157         return df.format((double) value / ratio);
158     }
159 
160     public static String pagingQuery(final String query) {
161         final HttpServletRequest request = LaRequestUtil.getRequest();
162         @SuppressWarnings("unchecked")
163         final List<String> pagingQueryList = (List<String>) request.getAttribute(Constants.PAGING_QUERY_LIST);
164         if (pagingQueryList != null) {
165             final String prefix;
166             if (query != null) {
167                 prefix = "ex_q=" + query.split(":")[0] + "%3A";
168             } else {
169                 prefix = null;
170             }
171             return pagingQueryList.stream().filter(s -> prefix == null || !s.startsWith(prefix))
172                     .collect(Collectors.joining("&", "&", StringUtil.EMPTY));
173         }
174         return StringUtil.EMPTY;
175     }
176 
177     public static String facetQuery() {
178         return createQuery(Constants.FACET_QUERY, FACET_PREFIX);
179     }
180 
181     public static String geoQuery() {
182         return createQuery(Constants.GEO_QUERY, GEO_PREFIX);
183     }
184 
185     public static String facetForm() {
186         return createForm(Constants.FACET_FORM, FACET_PREFIX);
187     }
188 
189     public static String geoForm() {
190         return createForm(Constants.GEO_FORM, GEO_PREFIX);
191     }
192 
193     public static List<FacetQueryView> facetQueryViewList() {
194         final ViewHelper viewHelper = ComponentUtil.getViewHelper();
195         return viewHelper.getFacetQueryViewList();
196     }
197 
198     private static String createQuery(final String key, final String prefix) {
199         final HttpServletRequest request = LaRequestUtil.getRequest();
200         String query = (String) request.getAttribute(key);
201         if (query == null) {
202             final StringBuilder buf = new StringBuilder(100);
203             final Enumeration<String> names = request.getParameterNames();
204             while (names.hasMoreElements()) {
205                 final String name = names.nextElement();
206                 if (name.startsWith(prefix)) {
207                     final String[] values = request.getParameterValues(name);
208                     if (values != null) {
209                         for (final String value : values) {
210                             buf.append('&');
211                             buf.append(LdiURLUtil.encode(name, Constants.UTF_8));
212                             buf.append('=');
213                             buf.append(LdiURLUtil.encode(value, Constants.UTF_8));
214                         }
215                     }
216                 }
217             }
218             query = buf.toString();
219             request.setAttribute(key, query);
220         }
221         return query;
222     }
223 
224     private static String createForm(final String key, final String prefix) {
225         final HttpServletRequest request = LaRequestUtil.getRequest();
226         String query = (String) request.getAttribute(key);
227         if (query == null) {
228             final StringBuilder buf = new StringBuilder(100);
229             final Enumeration<String> names = request.getParameterNames();
230             while (names.hasMoreElements()) {
231                 final String name = names.nextElement();
232                 if (name.startsWith(prefix)) {
233                     final String[] values = request.getParameterValues(name);
234                     if (values != null) {
235                         for (final String value : values) {
236                             buf.append("<input type=\"hidden\" name=\"");
237                             buf.append(StringEscapeUtils.escapeHtml4(name));
238                             buf.append("\" value=\"");
239                             buf.append(StringEscapeUtils.escapeHtml4(value));
240                             buf.append("\"/>");
241                         }
242                     }
243                 }
244             }
245             query = buf.toString();
246             request.setAttribute(key, query);
247         }
248         return query;
249     }
250 
251     public static String base64(final String value) {
252         if (value == null) {
253             return StringUtil.EMPTY;
254         }
255         return Base64.getUrlEncoder().encodeToString(value.getBytes(Constants.CHARSET_UTF_8));
256     }
257 
258     public static boolean fileExists(final String path) {
259         final File file = new File(LaServletContextUtil.getServletContext().getRealPath(path));
260         return file.exists();
261     }
262 
263     public static String url(final String input) {
264         if (input == null) {
265             final String msg = "The argument 'input' should not be null.";
266             throw new IllegalArgumentException(msg);
267         }
268         if (!input.startsWith("/")) {
269             final String msg = "The argument 'input' should start with slash '/': " + input;
270             throw new IllegalArgumentException(msg);
271         }
272         final String contextPath = LaRequestUtil.getRequest().getContextPath();
273         final StringBuilder sb = new StringBuilder();
274         if (contextPath.length() > 1) {
275             sb.append(contextPath);
276         }
277         sb.append(input);
278         if (input.indexOf('?') == -1) {
279             try {
280                 final Long value = resourceHashCache.get(input);
281                 if (value.longValue() > 0) {
282                     sb.append("?t=").append(value.toString());
283                 }
284             } catch (final ExecutionException e) {
285                 logger.debug("Failed to access " + input, e);
286             }
287         }
288         return LaResponseUtil.getResponse().encodeURL(sb.toString());
289     }
290 
291     public static String sdh(final String input) {
292         if (StringUtil.isBlank(input)) {
293             return input;
294         }
295         return ComponentUtil.getDocumentHelper().encodeSimilarDocHash(input);
296     }
297 }