1   /*
2    * Copyright 2004-2010 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  
17  package org.seasar.cubby.action;
18  
19  import static org.easymock.EasyMock.createMock;
20  import static org.easymock.EasyMock.eq;
21  import static org.easymock.EasyMock.expect;
22  import static org.easymock.EasyMock.expectLastCall;
23  import static org.easymock.EasyMock.getCurrentArguments;
24  import static org.easymock.EasyMock.isA;
25  import static org.easymock.EasyMock.replay;
26  import static org.easymock.EasyMock.verify;
27  import static org.junit.Assert.assertEquals;
28  import static org.junit.Assert.assertNotNull;
29  import static org.junit.Assert.assertTrue;
30  
31  import java.lang.reflect.Method;
32  import java.util.ArrayList;
33  import java.util.List;
34  
35  import javax.servlet.RequestDispatcher;
36  import javax.servlet.http.HttpServletRequest;
37  import javax.servlet.http.HttpServletRequestWrapper;
38  import javax.servlet.http.HttpServletResponse;
39  
40  import org.easymock.IAnswer;
41  import org.junit.After;
42  import org.junit.Before;
43  import org.junit.Test;
44  import org.seasar.cubby.CubbyConstants;
45  import org.seasar.cubby.mock.MockActionContext;
46  import org.seasar.cubby.mock.MockPathResolverProvider;
47  import org.seasar.cubby.plugin.PluginRegistry;
48  import org.seasar.cubby.plugins.BinderPlugin;
49  import org.seasar.cubby.routing.PathResolver;
50  import org.seasar.cubby.routing.Routing;
51  import org.seasar.cubby.routing.impl.PathResolverImpl;
52  import org.seasar.cubby.routing.impl.PathTemplateParserImpl;
53  import org.seasar.cubby.spi.PathResolverProvider;
54  
55  public class ForwardTest {
56  
57  	private final PluginRegistry pluginRegistry = PluginRegistry.getInstance();
58  
59  	private final MockAction action = new MockAction();
60  
61  	private HttpServletRequest request;
62  
63  	private RequestDispatcher requestDispatcher;
64  
65  	private HttpServletResponse response;
66  
67  	@Before
68  	public void setupProvider() {
69  		final List<Class<?>> actionClasses = new ArrayList<Class<?>>();
70  		actionClasses.add(MockAction.class);
71  		final PathResolver pathResolver = new PathResolverImpl(
72  				new PathTemplateParserImpl());
73  		pathResolver.addAll(actionClasses);
74  		final BinderPlugin binderPlugin = new BinderPlugin();
75  		binderPlugin.bind(PathResolverProvider.class).toInstance(
76  				new MockPathResolverProvider(pathResolver));
77  		pluginRegistry.register(binderPlugin);
78  	}
79  
80  	@After
81  	public void tearDownProvider() {
82  		pluginRegistry.clear();
83  	}
84  
85  	@Before
86  	public void setupRequest() {
87  		request = createMock(HttpServletRequest.class);
88  		expect(request.getCharacterEncoding()).andReturn("UTF-8").anyTimes();
89  		requestDispatcher = createMock(RequestDispatcher.class);
90  		response = createMock(HttpServletResponse.class);
91  	}
92  
93  	@Test
94  	public void basicSequence() throws Exception {
95  		final Method method = action.getClass().getMethod("dummy1");
96  		final MockActionContext actionContext = new MockActionContext(action,
97  				MockAction.class, method);
98  
99  		expect(request.getRequestDispatcher("/mock/path.jsp")).andStubAnswer(
100 				new IAnswer<RequestDispatcher>() {
101 
102 					public RequestDispatcher answer() throws Throwable {
103 						assertTrue(actionContext.isPrerendered());
104 						return requestDispatcher;
105 					}
106 
107 				});
108 		requestDispatcher.forward(request, response);
109 		expectLastCall();
110 		replay(request, requestDispatcher, response);
111 
112 		final Forward forward = new Forward("path.jsp");
113 		forward.execute(actionContext, request, response);
114 		assertTrue(actionContext.isPostrendered());
115 		verify(request, requestDispatcher, response);
116 	}
117 
118 	@Test
119 	public void relativePath() throws Exception {
120 		final Method method = action.getClass().getMethod("dummy1");
121 		final MockActionContext actionContext = new MockActionContext(action,
122 				MockAction.class, method);
123 
124 		expect(request.getRequestDispatcher("/mock/page.jsp")).andReturn(
125 				requestDispatcher);
126 		requestDispatcher.forward(request, response);
127 		expectLastCall();
128 		replay(request, requestDispatcher, response);
129 
130 		final Forward forward = new Forward("page.jsp");
131 		forward.execute(actionContext, request, response);
132 		verify(request, requestDispatcher, response);
133 	}
134 
135 	@Test
136 	public void absolutePath() throws Exception {
137 		final Method method = action.getClass().getMethod("dummy1");
138 		final ActionContext actionContext = new MockActionContext(action,
139 				MockAction.class, method);
140 
141 		expect(request.getRequestDispatcher("/absolute/path.jsp")).andReturn(
142 				requestDispatcher);
143 		requestDispatcher.forward(request, response);
144 		expectLastCall();
145 		replay(request, requestDispatcher, response);
146 
147 		final Forward forward = new Forward("/absolute/path.jsp");
148 		forward.execute(actionContext, request, response);
149 		verify(request, requestDispatcher, response);
150 	}
151 
152 	@Test
153 	public void getPath() throws Exception {
154 		final Forward forward = new Forward("/absolute/path.jsp");
155 		assertEquals("/absolute/path.jsp", forward.getPath("UTF-8"));
156 	}
157 
158 	@Test
159 	public void param() throws Exception {
160 		final Forward forward = new Forward("/absolute/path.jsp").param(
161 				"value1", "123").param("value2", "456");
162 		assertEquals("/absolute/path.jsp?value1=123&value2=456", forward
163 				.getPath("UTF-8"));
164 	}
165 
166 	@Test
167 	public void forwardByClassAndMethodName() throws Exception {
168 		final Method method = action.getClass().getMethod("dummy1");
169 		final ActionContext actionContext = new MockActionContext(action,
170 				MockAction.class, method);
171 
172 		request.setAttribute(eq(CubbyConstants.ATTR_ROUTING),
173 				isA(Routing.class));
174 		expectLastCall().andAnswer(new IAnswer<Object>() {
175 
176 			public Object answer() throws Throwable {
177 				final Routing routing = Routing.class
178 						.cast(getCurrentArguments()[1]);
179 				assertNotNull(routing);
180 				assertEquals(MockAction.class, routing.getActionClass());
181 				final Method forwardMethod = action.getClass().getMethod(
182 						"dummy2");
183 				assertEquals(forwardMethod, routing.getActionMethod());
184 				return null;
185 			}
186 
187 		});
188 		expect(request.getRequestDispatcher("/mock/dummy2/5/abc")).andReturn(
189 				requestDispatcher);
190 		requestDispatcher.forward(request, response);
191 		expectLastCall();
192 		replay(request, requestDispatcher, response);
193 
194 		final Forward forward = new Forward(MockAction.class, "dummy2").param(
195 				"value1", "5").param("value2", "abc");
196 		forward.execute(actionContext, request, response);
197 	}
198 
199 	@Test
200 	public void forwardByClassAndIndex() throws Exception {
201 		final Method method = action.getClass().getMethod("dummy1");
202 		final ActionContext actionContext = new MockActionContext(action,
203 				MockAction.class, method);
204 
205 		request.setAttribute(eq(CubbyConstants.ATTR_ROUTING),
206 				isA(Routing.class));
207 		expectLastCall().andAnswer(new IAnswer<Object>() {
208 
209 			public Object answer() throws Throwable {
210 				final Routing routing = Routing.class
211 						.cast(getCurrentArguments()[1]);
212 				assertNotNull(routing);
213 				assertEquals(MockAction.class, routing.getActionClass());
214 				final Method forwardMethod = action.getClass().getMethod(
215 						"index");
216 				assertEquals(forwardMethod, routing.getActionMethod());
217 				return null;
218 			}
219 
220 		});
221 		expect(request.getRequestDispatcher("/mock/")).andReturn(
222 				requestDispatcher);
223 		requestDispatcher.forward(request, response);
224 		expectLastCall();
225 		replay(request, requestDispatcher, response);
226 
227 		final Forward forward = new Forward(MockAction.class);
228 		PluginRegistry.getInstance().clear();
229 
230 		assertEquals("/mock/", forward.getPath("UTF-8"));
231 		forward.execute(actionContext, request, response);
232 	}
233 
234 	@Test
235 	public void forwardByClassAndMethodNameWithParam() throws Exception {
236 		final Method method = action.getClass().getMethod("dummy1");
237 		final ActionContext actionContext = new MockActionContext(action,
238 				MockAction.class, method);
239 
240 		request.setAttribute(eq(CubbyConstants.ATTR_ROUTING),
241 				isA(Routing.class));
242 		expectLastCall().andAnswer(new IAnswer<Object>() {
243 
244 			public Object answer() throws Throwable {
245 				final Routing routing = Routing.class
246 						.cast(getCurrentArguments()[1]);
247 				assertNotNull(routing);
248 				assertEquals(MockAction.class, routing.getActionClass());
249 				final Method forwardMethod = action.getClass().getMethod(
250 						"dummy2");
251 				assertEquals(forwardMethod, routing.getActionMethod());
252 				return null;
253 			}
254 
255 		});
256 		expect(request.getRequestDispatcher("/mock/dummy2/123/456")).andReturn(
257 				requestDispatcher);
258 		requestDispatcher.forward(request, response);
259 		expectLastCall();
260 		replay(request, requestDispatcher, response);
261 
262 		final Forward forward = new Forward(MockAction.class, "dummy2").param(
263 				"value1", "123").param("value2", "456");
264 		PluginRegistry.getInstance().clear();
265 
266 		assertEquals("/mock/dummy2/123/456", forward.getPath("UTF-8"));
267 		forward.execute(actionContext, request, response);
268 	}
269 
270 	interface Asserter {
271 		void assertDispatchPath(String path);
272 	}
273 
274 	static class RequestDispatcherAssertionWrapper extends
275 			HttpServletRequestWrapper {
276 
277 		private final Asserter asserter;
278 
279 		public RequestDispatcherAssertionWrapper(
280 				final HttpServletRequest request, final Asserter asserter) {
281 			super(request);
282 			this.asserter = asserter;
283 		}
284 
285 		@Override
286 		public RequestDispatcher getRequestDispatcher(final String path) {
287 			asserter.assertDispatchPath(path);
288 			return super.getRequestDispatcher(path);
289 		}
290 
291 	}
292 
293 }