View Javadoc
1   /*
2    * Copyright 2012-2021 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.PrintWriter;
20  import java.io.StringWriter;
21  import java.text.SimpleDateFormat;
22  import java.util.Date;
23  import java.util.List;
24  import java.util.Locale;
25  import java.util.Map;
26  
27  import javax.servlet.http.HttpServletResponse;
28  
29  import org.apache.commons.text.StringEscapeUtils;
30  import org.codelibs.core.CoreLibConstants;
31  import org.codelibs.core.lang.StringUtil;
32  import org.codelibs.fess.Constants;
33  import org.codelibs.fess.exception.InvalidAccessTokenException;
34  import org.codelibs.fess.util.ComponentUtil;
35  import org.lastaflute.web.util.LaRequestUtil;
36  import org.lastaflute.web.util.LaResponseUtil;
37  
38  public abstract class BaseJsonApiManager extends BaseApiManager {
39  
40      protected String mimeType = "application/json";
41  
42      protected void writeJsonResponse(final int status, final String body, final Throwable t) {
43          if (t == null) {
44              writeJsonResponse(status, body, (String) null);
45              return;
46          }
47  
48          if (t instanceof InvalidAccessTokenException) {
49              final InvalidAccessTokenException e = (InvalidAccessTokenException) t;
50              final HttpServletResponse response = LaResponseUtil.getResponse();
51              response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
52              response.setHeader("WWW-Authenticate", "Bearer error=\"" + e.getType() + "\"");
53          }
54  
55          final StringBuilder sb = new StringBuilder();
56          if (StringUtil.isBlank(t.getMessage())) {
57              sb.append(t.getClass().getName());
58          } else {
59              sb.append(t.getMessage());
60          }
61          final StringWriter sw = new StringWriter();
62          t.printStackTrace(new PrintWriter(sw));
63          sb.append(" [ ").append(sw.toString()).append(" ]");
64          try {
65              sw.close();
66          } catch (final IOException ignore) {}
67          writeJsonResponse(status, body, sb.toString());
68      }
69  
70      protected void writeJsonResponse(final int status, final String body, final String errMsg) {
71          String content = null;
72          if (status == 0) {
73              if (StringUtil.isNotBlank(body)) {
74                  content = body;
75              }
76          } else {
77              content = "\"message\":" + escapeJson(errMsg);
78          }
79          writeJsonResponse(status, content);
80      }
81  
82      protected void writeJsonResponse(final int status, final String body) {
83          final String callback = LaRequestUtil.getRequest().getParameter("callback");
84          final boolean isJsonp = ComponentUtil.getFessConfig().isApiJsonpEnabled() && StringUtil.isNotBlank(callback);
85  
86          final StringBuilder buf = new StringBuilder(1000);
87          if (isJsonp) {
88              buf.append(escapeCallbackName(callback));
89              buf.append('(');
90          }
91          buf.append("{\"response\":");
92          buf.append("{\"version\":\"");
93          buf.append(ComponentUtil.getSystemHelper().getProductVersion());
94          buf.append("\",");
95          buf.append("\"status\":");
96          buf.append(status);
97          if (StringUtil.isNotBlank(body)) {
98              buf.append(',');
99              buf.append(body);
100         }
101         buf.append('}');
102         buf.append('}');
103         if (isJsonp) {
104             buf.append(')');
105         }
106         write(buf.toString(), mimeType, Constants.UTF_8);
107 
108     }
109 
110     protected String escapeCallbackName(final String callbackName) {
111         return "/**/" + callbackName.replaceAll("[^0-9a-zA-Z_\\$\\.]", StringUtil.EMPTY);
112     }
113 
114     protected String escapeJson(final Object obj) {
115         if (obj == null) {
116             return "null";
117         }
118 
119         final StringBuilder buf = new StringBuilder(255);
120         if (obj instanceof String[]) {
121             buf.append('[');
122             boolean first = true;
123             for (final Object child : (String[]) obj) {
124                 if (first) {
125                     first = false;
126                 } else {
127                     buf.append(',');
128                 }
129                 buf.append(escapeJson(child));
130             }
131             buf.append(']');
132         } else if (obj instanceof List<?>) {
133             buf.append('[');
134             boolean first = true;
135             for (final Object child : (List<?>) obj) {
136                 if (first) {
137                     first = false;
138                 } else {
139                     buf.append(',');
140                 }
141                 buf.append(escapeJson(child));
142             }
143             buf.append(']');
144         } else if (obj instanceof Map<?, ?>) {
145             buf.append('{');
146             boolean first = true;
147             for (final Map.Entry<?, ?> entry : ((Map<?, ?>) obj).entrySet()) {
148                 if (first) {
149                     first = false;
150                 } else {
151                     buf.append(',');
152                 }
153                 buf.append(escapeJson(entry.getKey())).append(':').append(escapeJson(entry.getValue()));
154             }
155             buf.append('}');
156         } else if ((obj instanceof Integer) || (obj instanceof Long) || (obj instanceof Float) || (obj instanceof Double)) {
157             buf.append((obj));
158         } else if (obj instanceof Boolean) {
159             buf.append(obj.toString());
160         } else if (obj instanceof Date) {
161             final SimpleDateFormat sdf = new SimpleDateFormat(CoreLibConstants.DATE_FORMAT_ISO_8601_EXTEND, Locale.ROOT);
162             buf.append('\"').append(StringEscapeUtils.escapeJson(sdf.format(obj))).append('\"');
163         } else {
164             buf.append('\"').append(StringEscapeUtils.escapeJson(obj.toString())).append('\"');
165         }
166         return buf.toString();
167     }
168 
169     public void setMimeType(final String mimeType) {
170         this.mimeType = mimeType;
171     }
172 
173 }