View Javadoc

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.internal.controller.impl;
17  
18  import static org.seasar.cubby.CubbyConstants.ATTR_ACTION;
19  import static org.seasar.cubby.CubbyConstants.ATTR_CONTEXT_PATH;
20  import static org.seasar.cubby.CubbyConstants.ATTR_FORM_WRAPPER_FACTORY;
21  import static org.seasar.cubby.CubbyConstants.ATTR_MESSAGES;
22  
23  import java.util.ArrayList;
24  import java.util.Enumeration;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  import java.util.Map.Entry;
31  
32  import javax.servlet.http.HttpServletRequest;
33  import javax.servlet.http.HttpServletRequestWrapper;
34  
35  import org.seasar.cubby.CubbyConstants;
36  import org.seasar.cubby.controller.FormWrapperFactory;
37  import org.seasar.cubby.internal.controller.ThreadContext;
38  import org.seasar.cubby.internal.util.IteratorEnumeration;
39  import org.seasar.cubby.spi.beans.Attribute;
40  import org.seasar.cubby.spi.beans.BeanDesc;
41  import org.seasar.cubby.spi.beans.BeanDescFactory;
42  
43  /**
44   * 特別な属性を取得するためにサーブレットへの要求をラップします。
45   * <p>
46   * <ul>
47   * <li>{@link #getAttribute(String)}</li>
48   * <li>{@link #getAttributeNames()}</li>
49   * </ul>
50   * 上記メソッドでは、ラップされた要求の属性に加えて以下のような属性を使用することができます。
51   * <table>
52   * <thead>
53   * <tr>
54   * <th>属性名</th>
55   * <th>値</th>
56   * <th>型</th>
57   * </tr>
58   * </thead><tbody>
59   * <tr>
60   * <td>{@link CubbyConstants#ATTR_CONTEXT_PATH}</td>
61   * <td>コンテキストパス</td>
62   * <td>{@link String}</td>
63   * </tr>
64   * <tr>
65   * <td>{@link CubbyConstants#ATTR_ACTION}</td>
66   * <td>アクション</td>
67   * <td>{@link org.seasar.cubby.action.Action}</td>
68   * </tr>
69   * <tr>
70   * <td>{@link CubbyConstants#ATTR_MESSAGES}</td>
71   * <td>メッセージリソース</td>
72   * <td>{@link java.util.Map}</td>
73   * </tr>
74   * <tr>
75   * <td>{@link CubbyConstants#ATTR_FORM_WRAPPER_FACTORY}</td>
76   * <td>フォームオブジェクトのラッパーファクトリ</td>
77   * <td>{@link FormWrapperFactory}</td>
78   * </tr>
79   * <tr>
80   * <td>アクションのプロパティ名</td>
81   * <td>アクションのプロパティ値</td>
82   * <td>任意</td>
83   * </tr>
84   * </table>
85   * これらの属性は通常の属性よりも優先されるのでご注意ください。
86   * </p>
87   * <p>
88   * また、以下の要求パラメータに関するメソッドは、通常の要求パラメータに加え、URI パラメータも対象として処理します。
89   * <ul>
90   * <li>{@link #getParameter(String)}</li>
91   * <li>{@link #getParameterMap()}</li>
92   * <li>{@link #getParameterNames()}</li>
93   * <li>{@link #getParameterValues(String)}</li>
94   * </ul>
95   * </p>
96   * 
97   * @author baba
98   */
99  class CubbyHttpServletRequestWrapper extends HttpServletRequestWrapper {
100 
101 	/** URI パラメータの {@link Map} です。 */
102 	private final Map<String, String[]> uriParameters;
103 
104 	/** フォームオブジェクトのラッパーファクトリです。 */
105 	private FormWrapperFactory formWrapperFactory;
106 
107 	/**
108 	 * 指定された要求をラップした要求オブジェクトを構築します。
109 	 * 
110 	 * @param request
111 	 *            要求
112 	 * @param uriParameters
113 	 *            URI パラメータの {@link Map}
114 	 */
115 	public CubbyHttpServletRequestWrapper(final HttpServletRequest request,
116 			final Map<String, String[]> uriParameters) {
117 		super(request);
118 		this.uriParameters = uriParameters;
119 	}
120 
121 	/**
122 	 * 指定された属性の値を <code>Object</code> として返します。指定された名前の属性が存在しない場合は、
123 	 * <code>null</code> を返します。
124 	 * 
125 	 * @param name
126 	 *            属性の名前を指定する <code>String</code>
127 	 * @return 属性の値を含む <code>Object</code>。属性が存在しない場合は <code>null</code>
128 	 */
129 	@Override
130 	public Object getAttribute(final String name) {
131 		final Object value;
132 		if (ATTR_CONTEXT_PATH.equals(name)) {
133 			value = this.getContextPath();
134 		} else if (ATTR_MESSAGES.equals(name)) {
135 			value = ThreadContext.getMessagesMap();
136 		} else if (ATTR_FORM_WRAPPER_FACTORY.equals(name)) {
137 			if (this.formWrapperFactory == null) {
138 				this.formWrapperFactory = new FormWrapperFactoryImpl();
139 			}
140 			value = this.formWrapperFactory;
141 		} else {
142 			final Object action = super.getAttribute(ATTR_ACTION);
143 			if (action != null) {
144 				final BeanDesc beanDesc = BeanDescFactory.getBeanDesc(action
145 						.getClass());
146 				if (beanDesc.hasPropertyAttribute(name)) {
147 					final Attribute attribute = beanDesc
148 							.getPropertyAttribute(name);
149 					if (attribute.isReadable()) {
150 						value = attribute.getValue(action);
151 					} else {
152 						value = super.getAttribute(name);
153 					}
154 				} else {
155 					value = super.getAttribute(name);
156 				}
157 			} else {
158 				value = super.getAttribute(name);
159 			}
160 		}
161 		return value;
162 	}
163 
164 	/**
165 	 * この要求で利用できる属性の名前が格納された <code>Enumeration</code> を返します。利用できる属性が要求にない場合は、空の
166 	 * <code>Enumeration</code> を返します。
167 	 * 
168 	 * @return 要求に付随する属性の名前が格納された文字列の <code>Enumeration</code>
169 	 */
170 	@SuppressWarnings("unchecked")
171 	@Override
172 	public Enumeration getAttributeNames() {
173 		final Set attributeNames = new HashSet();
174 
175 		attributeNames.add(ATTR_CONTEXT_PATH);
176 		attributeNames.add(ATTR_ACTION);
177 		attributeNames.add(ATTR_MESSAGES);
178 		attributeNames.add(ATTR_FORM_WRAPPER_FACTORY);
179 
180 		final Object action = super.getAttribute(ATTR_ACTION);
181 		if (action != null) {
182 			final BeanDesc beanDesc = BeanDescFactory.getBeanDesc(action
183 					.getClass());
184 			for (final Attribute attribute : beanDesc.findtPropertyAttributes()) {
185 				if (attribute.isReadable()) {
186 					attributeNames.add(attribute.getName());
187 				}
188 			}
189 		}
190 
191 		final Enumeration defaultAttributeNames = super.getAttributeNames();
192 		while (defaultAttributeNames.hasMoreElements()) {
193 			attributeNames.add(defaultAttributeNames.nextElement());
194 		}
195 		return new IteratorEnumeration(attributeNames.iterator());
196 	}
197 
198 	/**
199 	 * 要求パラメータの値を <code>String</code> として返します。
200 	 * <p>
201 	 * パラメータが存在しない場合は、<code>null</code> を返します。
202 	 * </p>
203 	 * 
204 	 * @param name
205 	 *            パラメータの名前を指定する <code>String</code>
206 	 * @return パラメータの単一の値を表す <code>String</code>
207 	 */
208 	@Override
209 	public String getParameter(final String name) {
210 		final String[] parameters = this.getParameterValues(name);
211 		if (parameters == null) {
212 			return null;
213 		} else {
214 			return parameters[0];
215 		}
216 	}
217 
218 	/**
219 	 * この要求に含まれるパラメータの名前を格納した、<code>String</code> オブジェクトの
220 	 * <code>Enumeration</code> を返します。
221 	 * <p>
222 	 * パラメータが要求にない場合、このメソッドは空の <code>Enumeration</code> を返します。
223 	 * </p>
224 	 */
225 	@SuppressWarnings("unchecked")
226 	@Override
227 	public Enumeration getParameterNames() {
228 		return new IteratorEnumeration(this.getParameterMap().keySet()
229 				.iterator());
230 	}
231 
232 	/**
233 	 * 指定された要求パラメータのすべての値が格納された <code>String</code> オブジェクトの配列を返します。
234 	 * <p>
235 	 * パラメータが存在しない場合は、<code>null</code> を返します。
236 	 * </p>
237 	 * 
238 	 * @param name
239 	 *            取得したいパラメータの名前を表す <code>String</code>
240 	 * @return パラメータの値が格納された <code>String</code> オブジェクトの配列
241 	 */
242 	@SuppressWarnings("unchecked")
243 	@Override
244 	public String[] getParameterValues(final String name) {
245 		final Map<String, String[]> parameterMap = this.getParameterMap();
246 		return parameterMap.get(name);
247 	}
248 
249 	/**
250 	 * この要求から取得できるパラメータを <code>java.util.Map</code> で返します。
251 	 * 
252 	 * @return キーとしてパラメータ名、マップ値としてパラメータ値が格納された不変の <code>java.util.Map</code>。
253 	 *         <p>
254 	 *         パラメータマップ内のキーは <code>String</code> 型。パラメータマップ内の値は
255 	 *         <code>String</code> の配列型
256 	 *         </p>
257 	 */
258 	@SuppressWarnings("unchecked")
259 	@Override
260 	public Map getParameterMap() {
261 		final Map<String, String[]> parameterMap = buildParameterMap(
262 				(HttpServletRequest) getRequest(), uriParameters);
263 		return parameterMap;
264 	}
265 
266 	/**
267 	 * 要求パラメータを構築します。
268 	 * 
269 	 * @param request
270 	 *            要求
271 	 * @param uriParameters
272 	 *            URI パラメータの {@link Map}
273 	 * @return URI パラメータを含む要求パラメータの {@link Map}
274 	 */
275 	private Map<String, String[]> buildParameterMap(
276 			final HttpServletRequest request,
277 			final Map<String, String[]> uriParameters) {
278 		final Map<String, List<String>> extendedParameterMap = new HashMap<String, List<String>>();
279 
280 		final Map<?, ?> originalParameterMap = request.getParameterMap();
281 		for (final Entry<?, ?> entry : originalParameterMap.entrySet()) {
282 			final String name = (String) entry.getKey();
283 			final List<String> values = new ArrayList<String>();
284 			for (final String value : (String[]) entry.getValue()) {
285 				values.add(value);
286 			}
287 			extendedParameterMap.put(name, values);
288 		}
289 		for (final Entry<String, String[]> entry : uriParameters.entrySet()) {
290 			final String name = entry.getKey();
291 			if (extendedParameterMap.containsKey(name)) {
292 				final List<String> values = extendedParameterMap.get(name);
293 				for (final String value : entry.getValue()) {
294 					values.add(value);
295 				}
296 			} else {
297 				final List<String> values = new ArrayList<String>();
298 				for (final String value : entry.getValue()) {
299 					values.add(value);
300 				}
301 				extendedParameterMap.put(name, values);
302 			}
303 		}
304 
305 		final Map<String, String[]> parameterMap = new HashMap<String, String[]>();
306 		for (final Entry<String, List<String>> entry : extendedParameterMap
307 				.entrySet()) {
308 			parameterMap.put(entry.getKey(), entry.getValue().toArray(
309 					new String[0]));
310 		}
311 		return parameterMap;
312 	}
313 
314 }