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.io.BufferedInputStream;
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.UnsupportedEncodingException;
23 import java.net.URLDecoder;
24 import java.net.URLEncoder;
25 import java.util.ArrayList;
26 import java.util.Date;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Locale;
31 import java.util.Map;
32 import java.util.Set;
33 import java.util.concurrent.ConcurrentHashMap;
34 import java.util.function.Consumer;
35 import java.util.function.Function;
36 import java.util.regex.Matcher;
37 import java.util.regex.Pattern;
38
39 import javax.annotation.PostConstruct;
40 import javax.annotation.Resource;
41 import javax.servlet.http.HttpServletRequest;
42
43 import org.apache.catalina.connector.ClientAbortException;
44 import org.apache.commons.io.IOUtils;
45 import org.apache.commons.lang3.StringUtils;
46 import org.apache.commons.text.StringEscapeUtils;
47 import org.codelibs.core.CoreLibConstants;
48 import org.codelibs.core.lang.StringUtil;
49 import org.codelibs.core.misc.Base64Util;
50 import org.codelibs.core.misc.DynamicProperties;
51 import org.codelibs.fess.Constants;
52 import org.codelibs.fess.crawler.builder.RequestDataBuilder;
53 import org.codelibs.fess.crawler.client.CrawlerClient;
54 import org.codelibs.fess.crawler.client.CrawlerClientFactory;
55 import org.codelibs.fess.crawler.entity.ResponseData;
56 import org.codelibs.fess.crawler.util.CharUtil;
57 import org.codelibs.fess.entity.FacetQueryView;
58 import org.codelibs.fess.es.config.exentity.CrawlingConfig;
59 import org.codelibs.fess.exception.FessSystemException;
60 import org.codelibs.fess.helper.UserAgentHelper.UserAgentType;
61 import org.codelibs.fess.mylasta.direction.FessConfig;
62 import org.codelibs.fess.util.ComponentUtil;
63 import org.codelibs.fess.util.DocumentUtil;
64 import org.codelibs.fess.util.ResourceUtil;
65 import org.lastaflute.taglib.function.LaFunctions;
66 import org.lastaflute.web.response.ActionResponse;
67 import org.lastaflute.web.response.StreamResponse;
68 import org.lastaflute.web.ruts.process.ActionRuntime;
69 import org.lastaflute.web.util.LaRequestUtil;
70 import org.lastaflute.web.util.LaResponseUtil;
71 import org.lastaflute.web.util.LaServletContextUtil;
72 import org.slf4j.Logger;
73 import org.slf4j.LoggerFactory;
74
75 import com.github.jknack.handlebars.Context;
76 import com.github.jknack.handlebars.Handlebars;
77 import com.github.jknack.handlebars.Template;
78 import com.github.jknack.handlebars.io.FileTemplateLoader;
79 import com.ibm.icu.text.SimpleDateFormat;
80
81 public class ViewHelper {
82
83 private static final String CONTENT_DISPOSITION = "Content-Disposition";
84
85 private static final String HL_CACHE = "hl_cache";
86
87 private static final String QUERIES = "queries";
88
89 private static final String CACHE_MSG = "cache_msg";
90
91 private static final Pattern LOCAL_PATH_PATTERN = Pattern.compile("^file:/+[a-zA-Z]:");
92
93 private static final Pattern SHARED_FOLDER_PATTERN = Pattern.compile("^file:/+[^/]\\.");
94
95 private static final Logger logger = LoggerFactory.getLogger(ViewHelper.class);
96
97 @Resource
98 protected DynamicProperties systemProperties;
99
100 @Resource
101 protected PathMappingHelper pathMappingHelper;
102
103 @Resource
104 protected UserAgentHelper userAgentHelper;
105
106 public int titleLength = 50;
107
108 public int sitePathLength = 50;
109
110 public boolean encodeUrlLink = false;
111
112 public String urlLinkEncoding = Constants.UTF_8;
113
114 public String[] highlightedFields = new String[] { "hl_content", "digest" };
115
116 public String originalHighlightTagPre = "<em>";
117
118 public String originalHighlightTagPost = "</em>";
119
120 public String highlightTagPre = "<strong>";
121
122 public String highlightTagPost = "</strong>";
123
124 protected boolean useSession = true;
125
126 private final Map<String, String> pageCacheMap = new ConcurrentHashMap<>();
127
128 private final Map<String, String> initFacetParamMap = new HashMap<>();
129
130 private final Map<String, String> initGeoParamMap = new HashMap<>();
131
132 private final List<FacetQueryView> facetQueryViewList = new ArrayList<>();
133
134 public String cacheTemplateName = "cache";
135
136 private String escapedHighlightPre = null;
137
138 private String escapedHighlightPost = null;
139
140 protected ActionHook actionHook = new ActionHook();
141
142 private final Set<String> inlineMimeTypeSet = new HashSet<>();
143
144 @PostConstruct
145 public void init() {
146 escapedHighlightPre = LaFunctions.h(originalHighlightTagPre);
147 escapedHighlightPost = LaFunctions.h(originalHighlightTagPost);
148 }
149
150 public String getContentTitle(final Map<String, Object> document) {
151 final int size = titleLength;
152 final FessConfig fessConfig = ComponentUtil.getFessConfig();
153 String title = DocumentUtil.getValue(document, fessConfig.getIndexFieldTitle(), String.class);
154 if (StringUtil.isBlank(title)) {
155 title = DocumentUtil.getValue(document, fessConfig.getIndexFieldFilename(), String.class);
156 if (StringUtil.isBlank(title)) {
157 title = DocumentUtil.getValue(document, fessConfig.getIndexFieldUrl(), String.class);
158 }
159 }
160 return StringUtils.abbreviate(title, size);
161 }
162
163 public String getContentDescription(final Map<String, Object> document) {
164 for (final String field : highlightedFields) {
165 final String text = DocumentUtil.getValue(document, field, String.class);
166 if (StringUtil.isNotBlank(text)) {
167 return escapeHighlight(text);
168 }
169 }
170
171 return StringUtil.EMPTY;
172 }
173
174 protected String escapeHighlight(final String text) {
175 return LaFunctions.h(text).replaceAll(escapedHighlightPre, highlightTagPre).replaceAll(escapedHighlightPost, highlightTagPost);
176 }
177
178 protected String removeHighlightTag(final String str) {
179 return str.replaceAll(originalHighlightTagPre, StringUtil.EMPTY).replaceAll(originalHighlightTagPost, StringUtil.EMPTY);
180 }
181
182 public String getUrlLink(final Map<String, Object> document) {
183 final FessConfig fessConfig = ComponentUtil.getFessConfig();
184 String url = DocumentUtil.getValue(document, fessConfig.getIndexFieldUrl(), String.class);
185
186 if (StringUtil.isBlank(url)) {
187 return "#not-found-" + DocumentUtil.getValue(document, fessConfig.getIndexFieldDocId(), String.class);
188 }
189
190 final boolean isSmbUrl = url.startsWith("smb:");
191 final boolean isFtpUrl = url.startsWith("ftp:");
192 final boolean isSmbOrFtpUrl = isSmbUrl || isFtpUrl;
193
194
195 if (pathMappingHelper != null) {
196 url = pathMappingHelper.replaceUrl(url);
197 }
198
199 final boolean isHttpUrl = url.startsWith("http:") || url.startsWith("https:");
200
201 if (isSmbUrl) {
202 url = url.replace("smb:", "file:");
203 }
204
205 if (isHttpUrl && isSmbOrFtpUrl) {
206
207
208 final StringBuilder buf = new StringBuilder(url.length() + 100);
209 for (final char c : url.toCharArray()) {
210 if (CharUtil.isUrlChar(c)) {
211 buf.append(c);
212 } else {
213 try {
214 buf.append(URLEncoder.encode(String.valueOf(c), urlLinkEncoding));
215 } catch (final UnsupportedEncodingException e) {
216 buf.append(c);
217 }
218 }
219 }
220 url = buf.toString();
221 } else if (url.startsWith("file:")) {
222
223 url = updateFileProtocol(url);
224
225 if (encodeUrlLink) {
226 return appendQueryParameter(document, url);
227 }
228
229
230 if (!isSmbOrFtpUrl) {
231
232 try {
233 url = URLDecoder.decode(url.replace("+", "%2B"), urlLinkEncoding);
234 } catch (Exception e) {
235 if (logger.isDebugEnabled()) {
236 logger.warn("Failed to decode " + url, e);
237 }
238 }
239 }
240 }
241
242
243
244 return appendQueryParameter(document, url);
245 }
246
247 protected String updateFileProtocol(String url) {
248 final int pos = url.indexOf(':', 5);
249 final boolean isLocalFile = pos > 0 && pos < 12;
250
251 final UserAgentType ua = userAgentHelper.getUserAgentType();
252 switch (ua) {
253 case IE:
254 if (isLocalFile) {
255 url = url.replaceFirst("file:/+", systemProperties.getProperty("file.protocol.winlocal.ie", "file://"));
256 } else {
257 url = url.replaceFirst("file:/+", systemProperties.getProperty("file.protocol.ie", "file://"));
258 }
259 break;
260 case FIREFOX:
261 if (isLocalFile) {
262 url = url.replaceFirst("file:/+", systemProperties.getProperty("file.protocol.winlocal.firefox", "file://"));
263 } else {
264 url = url.replaceFirst("file:/+", systemProperties.getProperty("file.protocol.firefox", "file://///"));
265 }
266 break;
267 case CHROME:
268 if (isLocalFile) {
269 url = url.replaceFirst("file:/+", systemProperties.getProperty("file.protocol.winlocal.chrome", "file://"));
270 } else {
271 url = url.replaceFirst("file:/+", systemProperties.getProperty("file.protocol.chrome", "file://"));
272 }
273 break;
274 case SAFARI:
275 if (isLocalFile) {
276 url = url.replaceFirst("file:/+", systemProperties.getProperty("file.protocol.winlocal.safari", "file://"));
277 } else {
278 url = url.replaceFirst("file:/+", systemProperties.getProperty("file.protocol.safari", "file:////"));
279 }
280 break;
281 case OPERA:
282 if (isLocalFile) {
283 url = url.replaceFirst("file:/+", systemProperties.getProperty("file.protocol.winlocal.opera", "file://"));
284 } else {
285 url = url.replaceFirst("file:/+", systemProperties.getProperty("file.protocol.opera", "file://"));
286 }
287 break;
288 default:
289 if (isLocalFile) {
290 url = url.replaceFirst("file:/+", systemProperties.getProperty("file.protocol.winlocal.other", "file://"));
291 } else {
292 url = url.replaceFirst("file:/+", systemProperties.getProperty("file.protocol.other", "file://"));
293 }
294 break;
295 }
296 return url;
297 }
298
299 protected String appendQueryParameter(final Map<String, Object> document, final String url) {
300 final FessConfig fessConfig = ComponentUtil.getFessConfig();
301 if (fessConfig.isAppendQueryParameter()) {
302 if (url.indexOf('#') >= 0) {
303 return url;
304 }
305
306 final String mimetype = DocumentUtil.getValue(document, fessConfig.getIndexFieldMimetype(), String.class);
307 if (StringUtil.isNotBlank(mimetype)) {
308 if ("application/pdf".equals(mimetype)) {
309 return appendPDFSearchWord(url);
310 } else {
311
312 return url;
313 }
314 }
315 }
316 return url;
317 }
318
319 protected String appendPDFSearchWord(final String url) {
320 final String queries = (String) LaRequestUtil.getRequest().getAttribute(Constants.REQUEST_QUERIES);
321 if (queries != null) {
322 try {
323 final StringBuilder buf = new StringBuilder(url.length() + 100);
324 buf.append(url).append("#search=%22");
325 buf.append(URLEncoder.encode(queries.trim(), Constants.UTF_8));
326 buf.append("%22");
327 return buf.toString();
328 } catch (final UnsupportedEncodingException e) {
329 logger.warn("Unsupported encoding.", e);
330 }
331 }
332 return url;
333 }
334
335 public String getPagePath(final String page) {
336 final Locale locale = ComponentUtil.getRequestManager().getUserLocale();
337 final String lang = locale.getLanguage();
338 final String country = locale.getCountry();
339
340 final String pathLC = getLocalizedPagePath(page, lang, country);
341 final String pLC = pageCacheMap.get(pathLC);
342 if (pLC != null) {
343 return pLC;
344 }
345 if (existsPage(pathLC)) {
346 pageCacheMap.put(pathLC, pathLC);
347 return pathLC;
348 }
349
350 final String pathL = getLocalizedPagePath(page, lang, null);
351 final String pL = pageCacheMap.get(pathL);
352 if (pL != null) {
353 return pL;
354 }
355 if (existsPage(pathL)) {
356 pageCacheMap.put(pathLC, pathL);
357 return pathL;
358 }
359
360 final String path = getLocalizedPagePath(page, null, null);
361 final String p = pageCacheMap.get(path);
362 if (p != null) {
363 return p;
364 }
365 if (existsPage(path)) {
366 pageCacheMap.put(pathLC, path);
367 return path;
368 }
369
370 return "index.jsp";
371 }
372
373 private String getLocalizedPagePath(final String page, final String lang, final String country) {
374 final StringBuilder buf = new StringBuilder(100);
375 buf.append("/WEB-INF/view/").append(page);
376 if (StringUtil.isNotBlank(lang)) {
377 buf.append('_').append(lang);
378 if (StringUtil.isNotBlank(country)) {
379 buf.append('_').append(country);
380 }
381 }
382 buf.append(".jsp");
383 return buf.toString();
384 }
385
386 private boolean existsPage(final String path) {
387 final String realPath = LaServletContextUtil.getServletContext().getRealPath(path);
388 final File file = new File(realPath);
389 return file.isFile();
390 }
391
392 public String createCacheContent(final Map<String, Object> doc, final String[] queries) {
393 final FessConfig fessConfig = ComponentUtil.getFessConfig();
394 final FileTemplateLoader loader = new FileTemplateLoader(ResourceUtil.getViewTemplatePath().toFile());
395 final Handlebars handlebars = new Handlebars(loader);
396
397 Locale locale = ComponentUtil.getRequestManager().getUserLocale();
398 if (locale == null) {
399 locale = Locale.ENGLISH;
400 }
401 String url = DocumentUtil.getValue(doc, fessConfig.getIndexFieldUrl(), String.class);
402 if (url == null) {
403 url = ComponentUtil.getMessageManager().getMessage(locale, "labels.search_unknown");
404 }
405 doc.put(fessConfig.getResponseFieldUrlLink(), getUrlLink(doc));
406 String createdStr;
407 final Date created = DocumentUtil.getValue(doc, fessConfig.getIndexFieldCreated(), Date.class);
408 if (created != null) {
409 final SimpleDateFormat sdf = new SimpleDateFormat(CoreLibConstants.DATE_FORMAT_ISO_8601_EXTEND);
410 createdStr = sdf.format(created);
411 } else {
412 createdStr = ComponentUtil.getMessageManager().getMessage(locale, "labels.search_unknown");
413 }
414 doc.put(CACHE_MSG, ComponentUtil.getMessageManager()
415 .getMessage(locale, "labels.search_cache_msg", new Object[] { url, createdStr }));
416
417 doc.put(QUERIES, queries);
418
419 String cache = DocumentUtil.getValue(doc, fessConfig.getIndexFieldCache(), String.class);
420 if (cache != null) {
421 final String mimetype = DocumentUtil.getValue(doc, fessConfig.getIndexFieldMimetype(), String.class);
422 if (!ComponentUtil.getFessConfig().isHtmlMimetypeForCache(mimetype)) {
423 cache = StringEscapeUtils.escapeHtml4(cache);
424 }
425 cache = pathMappingHelper.replaceUrls(cache);
426 if (queries != null && queries.length > 0) {
427 doc.put(HL_CACHE, replaceHighlightQueries(cache, queries));
428 } else {
429 doc.put(HL_CACHE, cache);
430 }
431 } else {
432 doc.put(fessConfig.getIndexFieldCache(), StringUtil.EMPTY);
433 doc.put(HL_CACHE, StringUtil.EMPTY);
434 }
435
436 try {
437 final Template template = handlebars.compile(cacheTemplateName);
438 final Context hbsContext = Context.newContext(doc);
439 return template.apply(hbsContext);
440 } catch (final Exception e) {
441 logger.warn("Failed to create a cache response.", e);
442 }
443
444 return null;
445 }
446
447 protected String replaceHighlightQueries(final String cache, final String[] queries) {
448 final StringBuffer buf = new StringBuffer(cache.length() + 100);
449 final StringBuffer segBuf = new StringBuffer(1000);
450 final Pattern p = Pattern.compile("<[^>]+>");
451 final Matcher m = p.matcher(cache);
452 final String[] regexQueries = new String[queries.length];
453 final String[] hlQueries = new String[queries.length];
454 for (int i = 0; i < queries.length; i++) {
455 regexQueries[i] = Pattern.quote(queries[i]);
456 hlQueries[i] = highlightTagPre + queries[i] + highlightTagPost;
457 }
458 while (m.find()) {
459 segBuf.setLength(0);
460 m.appendReplacement(segBuf, StringUtil.EMPTY);
461 String segment = segBuf.toString();
462 for (int i = 0; i < queries.length; i++) {
463 segment = Pattern.compile(regexQueries[i], Pattern.CASE_INSENSITIVE).matcher(segment).replaceAll(hlQueries[i]);
464 }
465 buf.append(segment);
466 buf.append(m.group(0));
467 }
468 segBuf.setLength(0);
469 m.appendTail(segBuf);
470 String segment = segBuf.toString();
471 for (int i = 0; i < queries.length; i++) {
472 segment = Pattern.compile(regexQueries[i], Pattern.CASE_INSENSITIVE).matcher(segment).replaceAll(hlQueries[i]);
473 }
474 buf.append(segment);
475 return buf.toString();
476 }
477
478 public Object getSitePath(final Map<String, Object> docMap) {
479 final FessConfig fessConfig = ComponentUtil.getFessConfig();
480 final Object urlLink = docMap.get(fessConfig.getResponseFieldUrlLink());
481 if (urlLink != null) {
482 final String returnUrl;
483 final String url = urlLink.toString();
484 if (LOCAL_PATH_PATTERN.matcher(url).find() || SHARED_FOLDER_PATTERN.matcher(url).find()) {
485 returnUrl = url.replaceFirst("^file:/+", "");
486 } else if (url.startsWith("file:")) {
487 returnUrl = url.replaceFirst("^file:/+", "/");
488 } else {
489 returnUrl = url.replaceFirst("^[a-zA-Z0-9]*:/+", "");
490 }
491 return StringUtils.abbreviate(returnUrl, sitePathLength);
492 }
493 return null;
494 }
495
496 public StreamResponse asContentResponse(final Map<String, Object> doc) {
497 if (logger.isDebugEnabled()) {
498 logger.debug("writing the content of: " + doc);
499 }
500 final FessConfig fessConfig = ComponentUtil.getFessConfig();
501 final CrawlingConfigHelper crawlingConfigHelper = ComponentUtil.getCrawlingConfigHelper();
502 final String configId = DocumentUtil.getValue(doc, fessConfig.getIndexFieldConfigId(), String.class);
503 if (configId == null) {
504 throw new FessSystemException("configId is null.");
505 }
506 if (configId.length() < 2) {
507 throw new FessSystemException("Invalid configId: " + configId);
508 }
509 final CrawlingConfig config = crawlingConfigHelper.getCrawlingConfig(configId);
510 if (config == null) {
511 throw new FessSystemException("No crawlingConfig: " + configId);
512 }
513 final String url = DocumentUtil.getValue(doc, fessConfig.getIndexFieldUrl(), String.class);
514 final CrawlerClientFactory crawlerClientFactory = ComponentUtil.getComponent(CrawlerClientFactory.class);
515 config.initializeClientFactory(crawlerClientFactory);
516 final CrawlerClient client = crawlerClientFactory.getClient(url);
517 if (client == null) {
518 throw new FessSystemException("No CrawlerClient: " + configId + ", url: " + url);
519 }
520 return writeContent(configId, url, client);
521 }
522
523 protected StreamResponse writeContent(final String configId, final String url, final CrawlerClient client) {
524 final StreamResponse response = new StreamResponse(StringUtil.EMPTY);
525 final ResponseData responseData = client.execute(RequestDataBuilder.newRequestData().get().url(url).build());
526 if (responseData.getHttpStatusCode() == 404) {
527 response.httpStatus(responseData.getHttpStatusCode());
528 IOUtils.closeQuietly(responseData);
529 return response;
530 }
531 writeFileName(response, responseData);
532 writeContentType(response, responseData);
533 writeNoCache(response, responseData);
534 response.stream(out -> {
535 try (final InputStream is = new BufferedInputStream(responseData.getResponseBody())) {
536 out.write(is);
537 } catch (final IOException e) {
538 if (!(e.getCause() instanceof ClientAbortException)) {
539 throw new FessSystemException("Failed to write a content. configId: " + configId + ", url: " + url, e);
540 }
541 } finally {
542 IOUtils.closeQuietly(responseData);
543 }
544 if (logger.isDebugEnabled()) {
545 logger.debug("Finished to write " + url);
546 }
547 });
548 return response;
549 }
550
551 protected void writeNoCache(final StreamResponse response, final ResponseData responseData) {
552 response.header("Pragma", "no-cache");
553 response.header("Cache-Control", "no-cache");
554 response.header("Expires", "Thu, 01 Dec 1994 16:00:00 GMT");
555 }
556
557 protected void writeFileName(final StreamResponse response, final ResponseData responseData) {
558 final UserAgentHelper userAgentHelper = ComponentUtil.getUserAgentHelper();
559 final UserAgentType userAgentType = userAgentHelper.getUserAgentType();
560 String charset = responseData.getCharSet();
561 if (charset == null) {
562 charset = Constants.UTF_8;
563 }
564 final String name;
565 final String url = responseData.getUrl();
566 final int pos = url.lastIndexOf('/');
567 try {
568 if (pos >= 0 && pos + 1 < url.length()) {
569 name = URLDecoder.decode(url.substring(pos + 1), charset);
570 } else {
571 name = URLDecoder.decode(url, charset);
572 }
573
574 if (logger.isDebugEnabled()) {
575 logger.debug("userAgentType: " + userAgentType + ", charset: " + charset + ", name: " + name);
576 }
577
578 final String contentDispositionType;
579 if (inlineMimeTypeSet.contains(responseData.getMimeType())) {
580 contentDispositionType = "inline";
581 } else {
582 contentDispositionType = "attachment";
583 }
584
585 switch (userAgentType) {
586 case IE:
587 response.header(CONTENT_DISPOSITION, contentDispositionType + "; filename=\"" + URLEncoder.encode(name, Constants.UTF_8)
588 + "\"");
589 break;
590 case OPERA:
591 response.header(CONTENT_DISPOSITION,
592 contentDispositionType + "; filename*=utf-8'ja'" + URLEncoder.encode(name, Constants.UTF_8));
593 break;
594 case SAFARI:
595 response.header(CONTENT_DISPOSITION, contentDispositionType + "; filename=\"" + name + "\"");
596 break;
597 case CHROME:
598 case FIREFOX:
599 case OTHER:
600 default:
601 response.header(CONTENT_DISPOSITION,
602 contentDispositionType + "; filename=\"=?utf-8?B?" + Base64Util.encode(name.getBytes(Constants.UTF_8)) + "?=\"");
603 break;
604 }
605 } catch (final Exception e) {
606 logger.warn("Failed to write a filename: " + responseData, e);
607 }
608 }
609
610 protected void writeContentType(final StreamResponse response, final ResponseData responseData) {
611 final String mimeType = responseData.getMimeType();
612 if (logger.isDebugEnabled()) {
613 logger.debug("mimeType: " + mimeType);
614 }
615 if (mimeType == null) {
616 response.contentTypeOctetStream();
617 return;
618 }
619 if (mimeType.startsWith("text/")) {
620 final String charset = LaResponseUtil.getResponse().getCharacterEncoding();
621 if (charset != null) {
622 response.contentType(mimeType + "; charset=" + charset);
623 return;
624 }
625 }
626 response.contentType(mimeType);
627 }
628
629 public String getClientIp(final HttpServletRequest request) {
630 final String value = request.getHeader("x-forwarded-for");
631 if (StringUtil.isNotBlank(value)) {
632 return value;
633 } else {
634 return request.getRemoteAddr();
635 }
636 }
637
638 public boolean isUseSession() {
639 return useSession;
640 }
641
642 public void setUseSession(final boolean useSession) {
643 this.useSession = useSession;
644 }
645
646 public void addInitFacetParam(final String key, final String value) {
647 initFacetParamMap.put(value, key);
648 }
649
650 public Map<String, String> getInitFacetParamMap() {
651 return initFacetParamMap;
652 }
653
654 public void addInitGeoParam(final String key, final String value) {
655 initGeoParamMap.put(value, key);
656 }
657
658 public Map<String, String> getInitGeoParamMap() {
659 return initGeoParamMap;
660 }
661
662 public void addFacetQueryView(final FacetQueryView facetQueryView) {
663 facetQueryViewList.add(facetQueryView);
664 }
665
666 public List<FacetQueryView> getFacetQueryViewList() {
667 return facetQueryViewList;
668 }
669
670 public void addInlineMimeType(final String mimeType) {
671 inlineMimeTypeSet.add(mimeType);
672 }
673
674 public ActionHook getActionHook() {
675 return actionHook;
676 }
677
678 public void setActionHook(final ActionHook actionHook) {
679 this.actionHook = actionHook;
680 }
681
682 public static class ActionHook {
683
684 public ActionResponse godHandPrologue(final ActionRuntime runtime, final Function<ActionRuntime, ActionResponse> func) {
685 return func.apply(runtime);
686 }
687
688 public ActionResponse godHandMonologue(final ActionRuntime runtime, final Function<ActionRuntime, ActionResponse> func) {
689 return func.apply(runtime);
690 }
691
692 public void godHandEpilogue(final ActionRuntime runtime, final Consumer<ActionRuntime> consumer) {
693 consumer.accept(runtime);
694 }
695
696 public ActionResponse hookBefore(final ActionRuntime runtime, final Function<ActionRuntime, ActionResponse> func) {
697 return func.apply(runtime);
698 }
699
700 public void hookFinally(final ActionRuntime runtime, final Consumer<ActionRuntime> consumer) {
701 consumer.accept(runtime);
702 }
703 }
704 }