View Javadoc
1   /*
2    * Copyright 2012-2025 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.mylasta.direction.sponsor;
17  
18  import java.util.ArrayList;
19  import java.util.Collections;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.function.BiConsumer;
24  
25  import org.apache.commons.lang3.StringUtils;
26  import org.apache.logging.log4j.LogManager;
27  import org.apache.logging.log4j.Logger;
28  import org.codelibs.core.lang.StringUtil;
29  import org.codelibs.core.misc.Pair;
30  import org.codelibs.core.stream.StreamUtil;
31  import org.codelibs.fess.mylasta.direction.FessConfig;
32  import org.codelibs.fess.util.ComponentUtil;
33  import org.dbflute.util.DfTypeUtil;
34  import org.lastaflute.web.path.ActionAdjustmentProvider;
35  import org.lastaflute.web.path.FormMappingOption;
36  import org.lastaflute.web.response.ActionResponse;
37  import org.lastaflute.web.response.HtmlResponse;
38  import org.lastaflute.web.response.JsonResponse;
39  import org.lastaflute.web.response.StreamResponse;
40  import org.lastaflute.web.response.XmlResponse;
41  import org.lastaflute.web.ruts.process.ActionRuntime;
42  
43  /**
44   * The provider of action adjustment.
45   *
46   * @author jflute
47   */
48  public class FessActionAdjustmentProvider implements ActionAdjustmentProvider {
49  
50      private static final Logger logger = LogManager.getLogger(FessActionAdjustmentProvider.class);
51  
52      // _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
53      // you can adjust your actions by overriding
54      // default methods defined at the interface
55      // _/_/_/_/_/_/_/_/_/_/
56  
57      protected Map<String, List<Pair<String, String>>> responseHeaderMap = new HashMap<>();
58  
59      protected List<Pair<String, String>> defaultResponseHeaders;
60  
61      public FessActionAdjustmentProvider(final FessConfig fessConfig) {
62          parseResponseHeaderConfig(fessConfig.getResponseHeaders());
63      }
64  
65      private void parseResponseHeaderConfig(final String value) {
66          if (StringUtil.isBlank(value)) {
67              defaultResponseHeaders = Collections.emptyList();
68              return;
69          }
70  
71          StreamUtil.split(value, "\n").of(stream -> stream.filter(StringUtil::isNotBlank).forEach(s -> {
72              final String[] values = StringUtils.split(s, "=", 2);
73              List<Pair<String, String>> list = responseHeaderMap.get(values[0]);
74              if (list == null) {
75                  list = new ArrayList<>();
76                  responseHeaderMap.put(values[0], list);
77              }
78              final String[] keyValue = StringUtils.split(values[1], ":", 2);
79              if (keyValue.length == 2) {
80                  list.add(new Pair<>(keyValue[0].trim(), keyValue[1].trim()));
81              } else if (keyValue.length == 1) {
82                  list.add(new Pair<>(keyValue[0].trim(), StringUtil.EMPTY));
83              } else {
84                  logger.warn("Unexpected value: value={}", s);
85              }
86          }));
87  
88          final List<Pair<String, String>> headerList = responseHeaderMap.remove("*");
89          if (headerList != null) {
90              defaultResponseHeaders = headerList;
91          } else {
92              defaultResponseHeaders = Collections.emptyList();
93          }
94      }
95  
96      @Override
97      public FormMappingOption adjustFormMapping() {
98          return new FormMappingOption()
99                  .filterSimpleTextParameter((parameter, meta) -> parameter.trim().replace("\r\n", "\n").replace('\r', '\n'));
100     }
101 
102     @Override
103     public String customizeActionMappingRequestPath(final String requestPath) {
104         if (StringUtil.isBlank(requestPath)) {
105             return null;
106         }
107         final String virtualHostKey = ComponentUtil.getVirtualHostHelper().getVirtualHostKey();
108         if (StringUtil.isBlank(virtualHostKey)) {
109             return null;
110         }
111         final String prefix = "/" + virtualHostKey;
112         if (requestPath.startsWith(prefix)) {
113             return requestPath.substring(prefix.length());
114         }
115         return null;
116     }
117 
118     @Override
119     public String toString() {
120         return DfTypeUtil.toClassTitle(this) + ":{}";
121     }
122 
123     @Override
124     public void adjustActionResponseJustBefore(final ActionRuntime runtime, final ActionResponse response) {
125         final String mimeType;
126         if (response instanceof HtmlResponse) {
127             mimeType = "text/html";
128         } else if (response instanceof JsonResponse) {
129             mimeType = "application/json";
130         } else if (response instanceof XmlResponse) {
131             mimeType = "text/xml";
132         } else if (response instanceof StreamResponse) {
133             mimeType = "application/octet-stream";
134         } else {
135             logger.debug("Unknown response: response={}", response);
136             return;
137         }
138         adjustActionResponseHeaders(mimeType, (k, v) -> {
139             if (logger.isDebugEnabled()) {
140                 logger.debug("Apply header: key={}, value={}, mimeType={}", k, v, mimeType);
141             }
142             response.header(k, v);
143         });
144     }
145 
146     protected void adjustActionResponseHeaders(final String mimeType, final BiConsumer<String, String> callback) {
147         defaultResponseHeaders.forEach(header -> callback.accept(header.getFirst(), header.getSecond()));
148         final List<Pair<String, String>> headers = responseHeaderMap.get(mimeType);
149         if (headers != null) {
150             headers.forEach(header -> callback.accept(header.getFirst(), header.getSecond()));
151         }
152     }
153 }