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.api;
17  
18  import java.io.IOException;
19  import java.io.OutputStreamWriter;
20  import java.io.PrintWriter;
21  import java.util.Locale;
22  
23  import org.codelibs.core.exception.IORuntimeException;
24  import org.codelibs.fess.Constants;
25  import org.lastaflute.web.util.LaRequestUtil;
26  import org.lastaflute.web.util.LaResponseUtil;
27  
28  import jakarta.servlet.http.HttpServletRequest;
29  import jakarta.servlet.http.HttpServletResponse;
30  
31  /**
32   * Base implementation for API managers providing common functionality.
33   * Abstract class that provides format detection and response handling for web APIs.
34   */
35  public abstract class BaseApiManager implements WebApiManager {
36  
37      private static final String API_FORMAT_TYPE = "apiFormatType";
38  
39      /** Path prefix for API endpoints. */
40      protected String pathPrefix;
41  
42      /**
43       * Enumeration of supported API format types.
44       */
45      protected enum FormatType {
46          /** Search API format. */
47          SEARCH,
48          /** Label API format. */
49          LABEL,
50          /** Popular word API format. */
51          POPULARWORD,
52          /** Favorite API format. */
53          FAVORITE,
54          /** Favorites API format. */
55          FAVORITES,
56          /** Ping API format. */
57          PING,
58          /** Scroll API format. */
59          SCROLL,
60          /** Suggest API format. */
61          SUGGEST,
62          /** Other API format. */
63          OTHER;
64      }
65  
66      /**
67       * Default constructor for BaseApiManager.
68       */
69      public BaseApiManager() {
70          // Default constructor
71      }
72  
73      /**
74       * Gets the path prefix for API endpoints.
75       * @return The path prefix.
76       */
77      public String getPathPrefix() {
78          return pathPrefix;
79      }
80  
81      /**
82       * Sets the path prefix for API endpoints.
83       * @param pathPrefix The path prefix to set.
84       */
85      public void setPathPrefix(final String pathPrefix) {
86          this.pathPrefix = pathPrefix;
87      }
88  
89      /**
90       * Gets the format type for the request.
91       * @param request The HTTP servlet request.
92       * @return The format type.
93       */
94      protected FormatType getFormatType(final HttpServletRequest request) {
95          FormatType formatType = (FormatType) request.getAttribute(API_FORMAT_TYPE);
96          if (formatType != null) {
97              return formatType;
98          }
99  
100         formatType = detectFormatType(request);
101         request.setAttribute(API_FORMAT_TYPE, formatType);
102         return formatType;
103     }
104 
105     /**
106      * Detects the format type from the request parameters.
107      * @param request The HTTP servlet request.
108      * @return The detected format type.
109      */
110     protected FormatType detectFormatType(final HttpServletRequest request) {
111         String value = request.getParameter("type");
112         if (value == null) {
113             final String servletPath = request.getServletPath();
114             final String[] values = servletPath.replaceAll("/+", "/").split("/");
115             if (values.length > 2) {
116                 value = values[2];
117             }
118         }
119         if (value == null) {
120             return FormatType.SEARCH;
121         }
122         final String type = value.toUpperCase(Locale.ROOT);
123         if (FormatType.SEARCH.name().equals(type)) {
124             return FormatType.SEARCH;
125         }
126         if (FormatType.LABEL.name().equals(type)) {
127             return FormatType.LABEL;
128         }
129         if (FormatType.POPULARWORD.name().equals(type)) {
130             return FormatType.POPULARWORD;
131         }
132         if (FormatType.FAVORITE.name().equals(type)) {
133             return FormatType.FAVORITE;
134         }
135         if (FormatType.FAVORITES.name().equals(type)) {
136             return FormatType.FAVORITES;
137         }
138         if (FormatType.PING.name().equals(type)) {
139             return FormatType.PING;
140         }
141         if (FormatType.SCROLL.name().equals(type)) {
142             return FormatType.SCROLL;
143         }
144         if (FormatType.SUGGEST.name().equals(type)) {
145             return FormatType.SUGGEST;
146         }
147 
148         // default
149         return FormatType.OTHER;
150     }
151 
152     /**
153      * Writes text content to the HTTP response with specified content type and encoding.
154      * @param text The text content to write.
155      * @param contentType The content type for the response.
156      * @param encoding The character encoding for the response.
157      */
158     protected void write(final String text, final String contentType, final String encoding) {
159         final StringBuilder buf = new StringBuilder(50);
160         if (contentType == null) {
161             buf.append("text/plain");
162         } else {
163             buf.append(contentType);
164         }
165         buf.append("; charset=");
166         final String enc;
167         if (encoding == null) {
168             enc = LaRequestUtil.getOptionalRequest().map(HttpServletRequest::getCharacterEncoding).orElse(Constants.UTF_8);
169         } else {
170             enc = encoding;
171         }
172         buf.append(enc);
173         final HttpServletResponse response = LaResponseUtil.getResponse();
174         response.setContentType(buf.toString());
175         writeHeaders(response);
176         try (PrintWriter out = new PrintWriter(new OutputStreamWriter(response.getOutputStream(), enc))) {
177             out.print(text);
178         } catch (final IOException e) {
179             throw new IORuntimeException(e);
180         }
181     }
182 
183     /**
184      * Writes custom headers to the HTTP response.
185      * @param response The HTTP servlet response.
186      */
187     protected abstract void writeHeaders(final HttpServletResponse response);
188 }