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.unit;
17  
18  import java.io.IOException;
19  import java.util.Arrays;
20  import java.util.Iterator;
21  
22  import javax.servlet.Filter;
23  import javax.servlet.FilterChain;
24  import javax.servlet.FilterConfig;
25  import javax.servlet.ServletContext;
26  import javax.servlet.ServletException;
27  import javax.servlet.ServletRequest;
28  import javax.servlet.ServletResponse;
29  import javax.servlet.http.HttpServletRequest;
30  import javax.servlet.http.HttpServletRequestWrapper;
31  import javax.servlet.http.HttpServletResponse;
32  
33  import org.seasar.cubby.CubbyConstants;
34  import org.seasar.cubby.action.ActionContext;
35  import org.seasar.cubby.action.ActionResult;
36  import org.seasar.cubby.internal.controller.RequestProcessor;
37  import org.seasar.cubby.internal.controller.impl.RequestProcessorImpl;
38  import org.seasar.cubby.internal.plugin.PluginManager;
39  import org.seasar.cubby.internal.routing.Router;
40  import org.seasar.cubby.internal.routing.impl.RouterImpl;
41  import org.seasar.cubby.plugin.AbstractPlugin;
42  import org.seasar.cubby.plugin.ActionResultInvocation;
43  import org.seasar.cubby.plugin.PluginRegistry;
44  import org.seasar.cubby.routing.PathInfo;
45  
46  /**
47   * アクションを実行するためのクラスです。
48   * 
49   * @author someda
50   * @author baba
51   */
52  public class CubbyRunner {
53  
54  	/** プラグインマネージャ。 */
55  	private static PluginManager pluginManager = new PluginManager(
56  			PluginRegistry.getInstance());
57  
58  	/**
59  	 * リクエストに応じたアクションを実行します。
60  	 * <p>
61  	 * <code>filters</code> が指定された場合はアクションを実行する前後に
62  	 * {@link Filter#doFilter(ServletRequest, ServletResponse, FilterChain)}
63  	 * を実行します。
64  	 * </p>
65  	 * 
66  	 * @param request
67  	 *            テスト用の要求
68  	 * @param response
69  	 *            テスト用の応答
70  	 * @param filters
71  	 *            実行するサーブレットフィルタ
72  	 * @return アクションメソッドの実行結果。アクションメソッドが見つからなかったり結果がない場合は <code>null</code>
73  	 * @throws Exception
74  	 *             アクションメソッドの実行時に例外が発生した場合
75  	 */
76  	public static ActionResult processAction(final HttpServletRequest request,
77  			final HttpServletResponse response, final Filter... filters)
78  			throws Exception {
79  		final ServletContext servletContext = new MockServletContext();
80  		return processAction(servletContext, request, response, filters);
81  	}
82  
83  	/**
84  	 * リクエストに応じたアクションを実行します。
85  	 * <p>
86  	 * <code>filters</code> が指定された場合はアクションを実行する前後に
87  	 * {@link Filter#doFilter(ServletRequest, ServletResponse, FilterChain)}
88  	 * を実行します。
89  	 * </p>
90  	 * 
91  	 * @param servletContext
92  	 *            サーブレットコンテキスト
93  	 * @param request
94  	 *            テスト用の要求
95  	 * @param response
96  	 *            テスト用の応答
97  	 * @param filters
98  	 *            実行するサーブレットフィルタ
99  	 * @return アクションメソッドの実行結果。アクションメソッドが見つからなかったり結果がない場合は <code>null</code>
100 	 * @throws Exception
101 	 *             アクションメソッドの実行時に例外が発生した場合
102 	 */
103 	public static ActionResult processAction(
104 			final ServletContext servletContext,
105 			final HttpServletRequest request,
106 			final HttpServletResponse response, final Filter... filters)
107 			throws Exception {
108 		return doProcess(false, servletContext, request, response, filters);
109 	}
110 
111 	/**
112 	 * リクエストに応じたアクションを実行し、その結果の {@link ActionResult} も実行します。
113 	 * <p>
114 	 * <code>filters</code> が指定された場合はアクションを実行する前後に
115 	 * {@link Filter#doFilter(ServletRequest, ServletResponse, FilterChain)}
116 	 * を実行します。
117 	 * </p>
118 	 * 
119 	 * @param request
120 	 *            テスト用の要求
121 	 * @param response
122 	 *            テスト用の応答
123 	 * @param filters
124 	 *            実行するサーブレットフィルタ
125 	 * @return アクションメソッドの実行結果。アクションメソッドが見つからなかったり結果がない場合は <code>null</code>
126 	 * @throws Exception
127 	 *             アクションメソッドの実行時に例外が発生した場合
128 	 * @since 2.0.2
129 	 */
130 	public static ActionResult processActionAndExecuteActionResult(
131 			final HttpServletRequest request,
132 			final HttpServletResponse response, final Filter... filters)
133 			throws Exception {
134 		final ServletContext servletContext = new MockServletContext();
135 		return processActionAndExecuteActionResult(servletContext, request,
136 				response, filters);
137 	}
138 
139 	/**
140 	 * リクエストに応じたアクションを実行し、その結果の {@link ActionResult} も実行します。
141 	 * <p>
142 	 * <code>filters</code> が指定された場合はアクションを実行する前後に
143 	 * {@link Filter#doFilter(ServletRequest, ServletResponse, FilterChain)}
144 	 * を実行します。
145 	 * </p>
146 	 * 
147 	 * @param servletContext
148 	 *            サーブレットコンテキスト
149 	 * @param request
150 	 *            テスト用の要求
151 	 * @param response
152 	 *            テスト用の応答
153 	 * @param filters
154 	 *            実行するサーブレットフィルタ
155 	 * @return アクションメソッドの実行結果。アクションメソッドが見つからなかったり結果がない場合は <code>null</code>
156 	 * @throws Exception
157 	 *             アクションメソッドの実行時に例外が発生した場合
158 	 * @since 2.0.2
159 	 */
160 	public static ActionResult processActionAndExecuteActionResult(
161 			final ServletContext servletContext,
162 			final HttpServletRequest request,
163 			final HttpServletResponse response, final Filter... filters)
164 			throws Exception {
165 		return doProcess(true, servletContext, request, response, filters);
166 	}
167 
168 	/**
169 	 * リクエストに応じたアクションを実行します。
170 	 * 
171 	 * @param executeActionResult
172 	 *            {@link ActionResult} を実行する場合は <code>true</code>、そうでない場合は
173 	 *            <code>false</code>
174 	 * @param servletContext
175 	 *            サーブレットコンテキスト
176 	 * @param request
177 	 *            テスト用の要求
178 	 * @param response
179 	 *            テスト用の応答
180 	 * @param filters
181 	 *            実行するサーブレットフィルタ
182 	 * @return アクションメソッドの実行結果。アクションメソッドが見つからなかったり結果がない場合は <code>null</code>
183 	 * @throws Exception
184 	 *             アクションメソッドの実行時に例外が発生した場合
185 	 */
186 	private static ActionResult doProcess(final boolean executeActionResult,
187 			final ServletContext servletContext,
188 			final HttpServletRequest request,
189 			final HttpServletResponse response, final Filter... filters)
190 			throws Exception {
191 		final FilterConfig filterConfig = new MockFilterConfig(servletContext);
192 		for (final Filter filter : filters) {
193 			filter.init(filterConfig);
194 		}
195 
196 		try {
197 			final CubbyRunnerPlugin cubbyRunnerPlugin = new CubbyRunnerPlugin();
198 			final PluginRegistry pluginRegistry = PluginRegistry.getInstance();
199 			pluginRegistry.register(cubbyRunnerPlugin);
200 
201 			pluginManager.init(servletContext);
202 			CubbyRunnerHttpServletRequestWrapper requestWrapper = new CubbyRunnerHttpServletRequestWrapper(
203 					request);
204 			final ActionInvokeFilterChain chain = new ActionInvokeFilterChain(
205 					filters);
206 			chain.doFilter(requestWrapper, response);
207 
208 			final ActionResult actionResult = cubbyRunnerPlugin
209 					.getActionResult();
210 			if (executeActionResult) {
211 				final ActionContext actionContext = requestWrapper
212 						.getActionContext();
213 				actionResult.execute(actionContext, requestWrapper, response);
214 			}
215 			return actionResult;
216 		} finally {
217 			pluginManager.destroy();
218 			for (final Filter filter : filters) {
219 				filter.destroy();
220 			}
221 		}
222 	}
223 
224 	static class ActionInvokeFilterChain implements FilterChain {
225 
226 		private final Iterator<Filter> iterator;
227 
228 		public ActionInvokeFilterChain(final Filter... filters) {
229 			this.iterator = Arrays.asList(filters).iterator();
230 		}
231 
232 		public void doFilter(final ServletRequest request,
233 				final ServletResponse response) throws IOException,
234 				ServletException {
235 			if (iterator.hasNext()) {
236 				final Filter filter = iterator.next();
237 				filter.doFilter(request, response, this);
238 			} else {
239 				try {
240 					invoke((HttpServletRequest) request,
241 							(HttpServletResponse) response);
242 				} catch (final Exception e) {
243 					throw new ServletException(e);
244 				}
245 			}
246 		}
247 
248 		private void invoke(final HttpServletRequest request,
249 				final HttpServletResponse response) throws Exception {
250 			final Router router = new RouterImpl();
251 			final PathInfo pathInfo = router.routing(request, response);
252 			if (pathInfo == null) {
253 				return;
254 			}
255 
256 			final RequestProcessor requestProcessor = new RequestProcessorImpl();
257 			requestProcessor.process(request, response, pathInfo);
258 		}
259 
260 	}
261 
262 	static class CubbyRunnerPlugin extends AbstractPlugin {
263 
264 		private ActionResult actionResult;
265 
266 		@Override
267 		public void invokeActionResult(ActionResultInvocation invocation)
268 				throws Exception {
269 			this.actionResult = invocation.getActionResult();
270 		}
271 
272 		public ActionResult getActionResult() {
273 			return actionResult;
274 		}
275 
276 	}
277 
278 	static class CubbyRunnerHttpServletRequestWrapper extends
279 			HttpServletRequestWrapper {
280 
281 		private ActionContext actionContext;
282 
283 		public CubbyRunnerHttpServletRequestWrapper(HttpServletRequest request) {
284 			super(request);
285 		}
286 
287 		@Override
288 		public void setAttribute(String name, Object o) {
289 			if (CubbyConstants.ATTR_ACTION_CONTEXT.equals(name)) {
290 				this.actionContext = (ActionContext) o;
291 			}
292 			super.setAttribute(name, o);
293 		}
294 
295 		public ActionContext getActionContext() {
296 			return actionContext;
297 		}
298 
299 	}
300 
301 }