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