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