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 		forward.execute(actionContext, request, response);
228 	}
229 
230 	@Test
231 	public void forwardByClassAndMethodNameWithParam() throws Exception {
232 		final Method method = action.getClass().getMethod("dummy1");
233 		final ActionContext actionContext = new MockActionContext(action,
234 				MockAction.class, method);
235 
236 		request.setAttribute(eq(CubbyConstants.ATTR_ROUTING),
237 				isA(Routing.class));
238 		expectLastCall().andAnswer(new IAnswer<Object>() {
239 
240 			public Object answer() throws Throwable {
241 				final Routing routing = Routing.class
242 						.cast(getCurrentArguments()[1]);
243 				assertNotNull(routing);
244 				assertEquals(MockAction.class, routing.getActionClass());
245 				final Method forwardMethod = action.getClass().getMethod(
246 						"dummy2");
247 				assertEquals(forwardMethod, routing.getActionMethod());
248 				return null;
249 			}
250 
251 		});
252 		expect(request.getRequestDispatcher("/mock/dummy2/123/456")).andReturn(
253 				requestDispatcher);
254 		requestDispatcher.forward(request, response);
255 		expectLastCall();
256 		replay(request, requestDispatcher, response);
257 
258 		final Forward forward = new Forward(MockAction.class, "dummy2").param(
259 				"value1", "123").param("value2", "456");
260 		forward.execute(actionContext, request, response);
261 	}
262 
263 	interface Asserter {
264 		void assertDispatchPath(String path);
265 	}
266 
267 	class RequestDispatcherAssertionWrapper extends HttpServletRequestWrapper {
268 
269 		private final Asserter asserter;
270 
271 		public RequestDispatcherAssertionWrapper(
272 				final HttpServletRequest request, final Asserter asserter) {
273 			super(request);
274 			this.asserter = asserter;
275 		}
276 
277 		@Override
278 		public RequestDispatcher getRequestDispatcher(final String path) {
279 			asserter.assertDispatchPath(path);
280 			return super.getRequestDispatcher(path);
281 		}
282 
283 	}
284 
285 }