##### Coverage Report - org.seasar.cubby.action.Json

Classes in this File | Line Coverage | Branch Coverage | Complexity
Json |
57% | 27/47
50% | 4/8
| 1.2666666666666666;1.267

1 |  |
     /*
2 |  |
      * Copyright 2004-2009 the Seasar Foundation 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.seasar.cubby.action;
17 |  |
18 |  |
     import java.io.Writer;
19 |  |
     import java.util.Collection;
20 |  |
     import java.util.Map;
21 |  |
22 |  |
     import javax.servlet.http.HttpServletRequest;
23 |  |
     import javax.servlet.http.HttpServletResponse;
24 |  |
25 |  |
     import org.seasar.cubby.internal.util.StringUtils;
26 |  |
     import org.seasar.cubby.spi.JsonProvider;
27 |  |
     import org.seasar.cubby.spi.ProviderFactory;
28 |  |
29 |  |
     /**
30 |  |
      * JSON 形式の応答を返す {@link ActionResult} です。
31 |  |
      * <p>
32 |  |
      * アクションメソッドの戻り値としてこのインスタンスを指定することで、指定された JavaBean を JSON/JSONP 形式に変換して応答を返します。
33 |  |
      * ブラウザの JavaScript から発行された要求を処理する場合等に使用してください。 JavaBean/ {@link Map}/配列/
34 |  |
      * {@link Collection}などがコンストラクタに渡すことができます。
35 |  |
      * </p>
36 |  |
      * <p>
37 |  |
      * 使用例1 : JSON 形式の応答を返す
38 |  |
      *
39 |  |
      * <pre>
40 |  |
      * MyBean bean = ...;
41 |  |
      * return new Json(bean);
42 |  |
      * </pre>
43 |  |
      *
44 |  |
      * </p>
45 |  |
      * <p>
46 |  |
      * 使用例2 : コールバック関数名を指定して JSONP 形式の応答を返す
47 |  |
      *
48 |  |
      * <pre>
49 |  |
      * MyBean bean = ...;
50 |  |
      * return new Json(bean, &quot;callback&quot;);
51 |  |
      * </pre>
52 |  |
      *
53 |  |
      * </p>
54 |  |
      * <p>
55 |  |
      * 使用例3 : MIME タイプと文字コードを指定して JSON 形式の応答を返す。<br>
56 |  |
      * 設定される MIME タイプは"text/javascript+json; charset=Shift_JIS"になります。
57 |  |
      *
58 |  |
      * <pre>
59 |  |
      * MyBean bean = ...;
60 |  |
      * return new Json(bean).contentType(&quot;text/javascript+json&quot;).encoding(&quot;Shift_JIS&quot;);
61 |  |
      * </pre>
62 |  |
      *
63 |  |
      * </p>
64 |  |
      *
65 |  |
      * @see <a
66 |  |
      *      href="http://www.json.org/">JSON(JavaScript&nbsp;Object&nbsp;Notation)</a>
67 |  |
      * @see <a
68 |  |
      *      href="http://ajaxian.com/archives/jsonp-json-with-padding">JSONP(JSON&nbsp;with&nbsp;Padding)</a>
69 |  |
      * @see JsonProvider#toJson(Object)
70 |  |
      * @author baba
71 |  |
      * @author agata
72 |  |
      */
73 |  |
     public class Json implements ActionResult {
74 |  |
75 |  |
             /** 変換対象のオブジェクト。 */
76 |  |
             private final Object bean;
77 |  |
78 |  |
             /** 変換に使用する {@link JsonProvider}。 */
79 |  |
             private final JsonProvider jsonProvider;
80 |  |
81 |  |
             /** コールバック関数名。 */
82 |  |
             private final String calllback;
83 |  |
84 |  |
             /** MIME タイプ。 */
85 | 2 |
             private String contentType = "text/javascript";
86 |  |
87 |  |
             /** エンコーディング。 */
88 | 2 |
             private String encoding = "utf-8";
89 |  |
90 |  |
             /** X-JSON 応答ヘッダを使用するか。 */
91 | 2 |
             private boolean xjson = false;
92 |  |
93 |  |
             /**
94 |  |
              * JSON 形式で応答を返すインスタンスを生成します。
95 |  |
              *
96 |  |
              * @param bean
97 |  |
              *            JSON 形式に変換するオブジェクト
98 |  |
              */
99 |  |
             public Json(final Object bean) {
100 | 2 |
                     this(bean, null, ProviderFactory.get(JsonProvider.class));
101 | 2 |
             }
102 |  |
103 |  |
             /**
104 |  |
              * JSON 形式で応答を返すインスタンスを生成します。
105 |  |
              *
106 |  |
              * @param bean
107 |  |
              *            JSON 形式に変換するオブジェクト
108 |  |
              * @param jsonProvider
109 |  |
              *            JSON のプロバイダ
110 |  |
              */
111 |  |
             public Json(final Object bean, final JsonProvider jsonProvider) {
112 | 0 |
                     this(bean, null, jsonProvider);
113 | 0 |
             }
114 |  |
115 |  |
             /**
116 |  |
              * JSONP 形式で応答を返すインスタンスを生成します。
117 |  |
              *
118 |  |
              * @param bean
119 |  |
              *            JSONP 形式に変換するオブジェクト
120 |  |
              * @param callback
121 |  |
              *            コールバック関数名
122 |  |
              */
123 |  |
             public Json(final Object bean, final String callback) {
124 | 0 |
                     this(bean, callback, ProviderFactory.get(JsonProvider.class));
125 | 0 |
             }
126 |  |
127 |  |
             /**
128 |  |
              * JSONP 形式で応答を返すインスタンスを生成します。
129 |  |
              *
130 |  |
              * @param bean
131 |  |
              *            JSONP 形式に変換するオブジェクト
132 |  |
              * @param callback
133 |  |
              *            コールバック関数名
134 |  |
              * @param jsonProvider
135 |  |
              *            JSON のプロバイダ
136 |  |
              */
137 |  |
             public Json(final Object bean, final String callback,
138 | 2 |
                             final JsonProvider jsonProvider) {
139 | 2 |
                     if (jsonProvider == null) {
140 | 0 |
                             throw new NullPointerException("jsonProvider");
141 |  |
                     }
142 | 2 |
                     this.bean = bean;
143 | 2 |
                     this.calllback = callback;
144 | 2 |
                     this.jsonProvider = jsonProvider;
145 | 2 |
             }
146 |  |
147 |  |
             /**
148 |  |
              * JSON 形式に変換する JavaBeanを取得します。
149 |  |
              *
150 |  |
              * @return JSON 形式に変換する JavaBean
151 |  |
              */
152 |  |
             public Object getBean() {
153 | 0 |
                     return this.bean;
154 |  |
             }
155 |  |
156 |  |
             /**
157 |  |
              * コールバック関数名を取得します。
158 |  |
              *
159 |  |
              * @return コールバック関数名
160 |  |
              */
161 |  |
             public String getCallback() {
162 | 0 |
                     return this.calllback;
163 |  |
             }
164 |  |
165 |  |
             /**
166 |  |
              * MIME タイプを設定します。
167 |  |
              *
168 |  |
              * @param contentType
169 |  |
              *            MIME タイプ (例："text/javascript+json")
170 |  |
              * @return {@link Json}
171 |  |
              */
172 |  |
             public Json contentType(final String contentType) {
173 | 1 |
                     this.contentType = contentType;
174 | 1 |
                     return this;
175 |  |
             }
176 |  |
177 |  |
             /**
178 |  |
              * MIME タイプを取得します。
179 |  |
              *
180 |  |
              * @return MIME タイプ
181 |  |
              */
182 |  |
             public String getContentType() {
183 | 0 |
                     return this.contentType;
184 |  |
             }
185 |  |
186 |  |
             /**
187 |  |
              * エンコーディングを設定します。
188 |  |
              * <p>
189 |  |
              * 設定されたエンコーディングは MIME タイプの charset として使用されます。
190 |  |
              * </p>
191 |  |
              *
192 |  |
              * @param encoding
193 |  |
              *            エンコーディング (例："Shift_JIS")
194 |  |
              * @return {@link Json}
195 |  |
              */
196 |  |
             public Json encoding(final String encoding) {
197 | 1 |
                     this.encoding = encoding;
198 | 1 |
                     return this;
199 |  |
             }
200 |  |
201 |  |
             /**
202 |  |
              * エンコーディングを取得します。
203 |  |
              *
204 |  |
              * @return エンコーディング
205 |  |
              */
206 |  |
             public String getEncoding() {
207 | 0 |
                     return this.encoding;
208 |  |
             }
209 |  |
210 |  |
             /**
211 |  |
              * JSON 文字列を応答ボディではなく X-JSON 応答ヘッダに設定することを指定します。
212 |  |
              * <p>
213 |  |
              * prototype.js の <code>Ajax.Request</code> を使うときに使用してください。
214 |  |
              * </p>
215 |  |
              *
216 |  |
              * @see <a
217 |  |
              *      href="http://www.prototypejs.org/api/ajax/options">www.prototypejs.org&nbsp;-&nbsp;Ajax&nbsp;Options</a>
218 |  |
              */
219 |  |
             public void xjson() {
220 | 0 |
                     this.xjson = true;
221 | 0 |
             }
222 |  |
223 |  |
             /**
224 |  |
              * JSON 文字列を X-JOSN 応答ヘッダに設定するかを示します。
225 |  |
              *
226 |  |
              * @return JSON 文字列を X-JOSN 応答ヘッダに設定する場合は <code>true</code>、そうでない場合は
227 |  |
              *         <code>false</code>
228 |  |
              */
229 |  |
             public boolean isXjson() {
230 | 0 |
                     return xjson;
231 |  |
             }
232 |  |
233 |  |
             /**
234 |  |
              * {@inheritDoc}
235 |  |
              */
236 |  |
             public void execute(final ActionContext actionContext,
237 |  |
                             final HttpServletRequest request, final HttpServletResponse response)
238 |  |
                             throws Exception {
239 | 2 |
                     response.setCharacterEncoding(this.encoding);
240 | 2 |
                     response
241 |  |
                                     .setContentType(this.contentType + "; charset=" + this.encoding);
242 | 2 |
                     response.setHeader("Cache-Control", "no-cache");
243 | 2 |
                     response.setHeader("Pragma", "no-cache");
244 |  |
245 |  |
                     final String script;
246 | 2 |
                     if (isJsonp()) {
247 | 0 |
                             script = appendCallbackFunction(jsonProvider.toJson(bean),
248 |  |
                                             calllback);
249 |  |
                     } else {
250 | 2 |
                             script = jsonProvider.toJson(bean);
251 |  |
                     }
252 |  |
253 | 2 |
                     if (xjson) {
254 | 0 |
                             response.setHeader("X-JSON", script);
255 |  |
                     } else {
256 | 2 |
                             final Writer writer = response.getWriter();
257 | 2 |
                             writer.write(script);
258 | 2 |
                             writer.flush();
259 |  |
                     }
260 | 2 |
             }
261 |  |
262 |  |
             /**
263 |  |
              * JSONP 形式に変換するかどうかを示します。
264 |  |
              *
265 |  |
              * @return JSONP 形式に変換する場合は <code>true</code>、そうでない場合は <code>false</code>
266 |  |
              */
267 |  |
             private boolean isJsonp() {
268 | 2 |
                     return !StringUtils.isEmpty(calllback);
269 |  |
             }
270 |  |
271 |  |
             /**
272 |  |
              * JSON 形式のスクリプトに指定されたコールバック関数を付加します。
273 |  |
              *
274 |  |
              * @param script
275 |  |
              *            JSON 形式のスクリプト
276 |  |
              * @param callback
277 |  |
              *            コールバック関数名
278 |  |
              * @return コールバック関数が追加された JSON 形式のスクリプト
279 |  |
              */
280 |  |
             private static String appendCallbackFunction(final String script,
281 |  |
                             final String callback) {
282 | 0 |
                     final StringBuilder builder = new StringBuilder(script.length()
283 |  |
                                     + callback.length() + 10);
284 | 0 |
                     builder.append(callback);
285 | 0 |
                     builder.append("(");
286 | 0 |
                     builder.append(script);
287 | 0 |
                     builder.append(");");
288 | 0 |
                     return builder.toString();
289 |  |
             }
290 |  |
291 |  |
     }