diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/bind/EscapedErrorsTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/bind/EscapedErrorsTests.java new file mode 100644 index 00000000000..a279ceab4b2 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/bind/EscapedErrorsTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.bind; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.validation.BindException; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; + +/** + * @author Juergen Hoeller + * @since 02.05.2003 + */ +public class EscapedErrorsTests extends TestCase { + + public void testEscapedErrors() { + TestBean tb = new TestBean(); + tb.setName("empty &"); + + Errors errors = new EscapedErrors(new BindException(tb, "tb")); + errors.rejectValue("name", "NAME_EMPTY &", null, "message: &"); + errors.rejectValue("age", "AGE_NOT_SET ", null, "message: "); + errors.rejectValue("age", "AGE_NOT_32 ", null, "message: "); + errors.reject("GENERAL_ERROR \" '", null, "message: \" '"); + + assertTrue("Correct errors flag", errors.hasErrors()); + assertTrue("Correct number of errors", errors.getErrorCount() == 4); + assertTrue("Correct object name", "tb".equals(errors.getObjectName())); + + assertTrue("Correct global errors flag", errors.hasGlobalErrors()); + assertTrue("Correct number of global errors", errors.getGlobalErrorCount() == 1); + ObjectError globalError = errors.getGlobalError(); + assertTrue("Global error message escaped", "message: " '".equals(globalError.getDefaultMessage())); + assertTrue("Global error code not escaped", "GENERAL_ERROR \" '".equals(globalError.getCode())); + ObjectError globalErrorInList = (ObjectError) errors.getGlobalErrors().get(0); + assertTrue("Same global error in list", globalError.getDefaultMessage().equals(globalErrorInList.getDefaultMessage())); + ObjectError globalErrorInAllList = (ObjectError) errors.getAllErrors().get(3); + assertTrue("Same global error in list", globalError.getDefaultMessage().equals(globalErrorInAllList.getDefaultMessage())); + + assertTrue("Correct field errors flag", errors.hasFieldErrors()); + assertTrue("Correct number of field errors", errors.getFieldErrorCount() == 3); + assertTrue("Correct number of field errors in list", errors.getFieldErrors().size() == 3); + FieldError fieldError = errors.getFieldError(); + assertTrue("Field error code not escaped", "NAME_EMPTY &".equals(fieldError.getCode())); + assertTrue("Field value escaped", "empty &".equals(errors.getFieldValue("name"))); + FieldError fieldErrorInList = (FieldError) errors.getFieldErrors().get(0); + assertTrue("Same field error in list", fieldError.getDefaultMessage().equals(fieldErrorInList.getDefaultMessage())); + + assertTrue("Correct name errors flag", errors.hasFieldErrors("name")); + assertTrue("Correct number of name errors", errors.getFieldErrorCount("name") == 1); + assertTrue("Correct number of name errors in list", errors.getFieldErrors("name").size() == 1); + FieldError nameError = errors.getFieldError("name"); + assertTrue("Name error message escaped", "message: &".equals(nameError.getDefaultMessage())); + assertTrue("Name error code not escaped", "NAME_EMPTY &".equals(nameError.getCode())); + assertTrue("Name value escaped", "empty &".equals(errors.getFieldValue("name"))); + FieldError nameErrorInList = (FieldError) errors.getFieldErrors("name").get(0); + assertTrue("Same name error in list", nameError.getDefaultMessage().equals(nameErrorInList.getDefaultMessage())); + + assertTrue("Correct age errors flag", errors.hasFieldErrors("age")); + assertTrue("Correct number of age errors", errors.getFieldErrorCount("age") == 2); + assertTrue("Correct number of age errors in list", errors.getFieldErrors("age").size() == 2); + FieldError ageError = errors.getFieldError("age"); + assertTrue("Age error message escaped", "message: <tag>".equals(ageError.getDefaultMessage())); + assertTrue("Age error code not escaped", "AGE_NOT_SET ".equals(ageError.getCode())); + assertTrue("Age value not escaped", (new Integer(0)).equals(errors.getFieldValue("age"))); + FieldError ageErrorInList = (FieldError) errors.getFieldErrors("age").get(0); + assertTrue("Same name error in list", ageError.getDefaultMessage().equals(ageErrorInList.getDefaultMessage())); + FieldError ageError2 = (FieldError) errors.getFieldErrors("age").get(1); + assertTrue("Age error 2 message escaped", "message: <tag>".equals(ageError2.getDefaultMessage())); + assertTrue("Age error 2 code not escaped", "AGE_NOT_32 ".equals(ageError2.getCode())); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/context/ServletConfigAwareBean.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/context/ServletConfigAwareBean.java new file mode 100644 index 00000000000..c3dc6275e1b --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/context/ServletConfigAwareBean.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context; + +import javax.servlet.ServletConfig; + +/** + * @author Juergen Hoeller + */ +public class ServletConfigAwareBean implements ServletConfigAware { + + private ServletConfig servletConfig; + + public void setServletConfig(ServletConfig servletConfig) { + this.servletConfig = servletConfig; + } + + public ServletConfig getServletConfig() { + return servletConfig; + } +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/context/ServletContextAwareBean.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/context/ServletContextAwareBean.java new file mode 100644 index 00000000000..a868f2f30d9 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/context/ServletContextAwareBean.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context; + +import javax.servlet.ServletContext; + +/** + * @author Juergen Hoeller + */ +public class ServletContextAwareBean implements ServletContextAware { + + private ServletContext servletContext; + + public void setServletContext(ServletContext servletContext) { + this.servletContext = servletContext; + } + + public ServletContext getServletContext() { + return servletContext; + } +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/multipart/support/ByteArrayMultipartFileEditorTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/multipart/support/ByteArrayMultipartFileEditorTests.java new file mode 100644 index 00000000000..169f2477e01 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/multipart/support/ByteArrayMultipartFileEditorTests.java @@ -0,0 +1,92 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.multipart.support; + +import java.io.IOException; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.web.multipart.MultipartFile; + +/** + * @author Rick Evans + */ +public final class ByteArrayMultipartFileEditorTests extends TestCase { + + public void testSetValueAsByteArray() throws Exception { + ByteArrayMultipartFileEditor editor = new ByteArrayMultipartFileEditor(); + String expectedValue = "Shumwere, shumhow, a shuck ish washing you. - Drunken Far Side"; + editor.setValue(expectedValue.getBytes()); + assertEquals(expectedValue, editor.getAsText()); + } + + public void testSetValueAsString() throws Exception { + ByteArrayMultipartFileEditor editor = new ByteArrayMultipartFileEditor(); + String expectedValue = "'Green Wing' - classic British comedy"; + editor.setValue(expectedValue); + assertEquals(expectedValue, editor.getAsText()); + } + + public void testSetValueAsCustomObjectInvokesToString() throws Exception { + ByteArrayMultipartFileEditor editor = new ByteArrayMultipartFileEditor(); + final String expectedValue = "'Green Wing' - classic British comedy"; + Object object = new Object() { + public String toString() { + return expectedValue; + } + }; + editor.setValue(object); + assertEquals(expectedValue, editor.getAsText()); + } + + public void testSetValueAsNullGetsBackEmptyString() throws Exception { + ByteArrayMultipartFileEditor editor = new ByteArrayMultipartFileEditor(); + editor.setValue(null); + assertEquals("", editor.getAsText()); + } + + public void testSetValueAsMultipartFile() throws Exception { + String expectedValue = "That is comforting to know"; + ByteArrayMultipartFileEditor editor = new ByteArrayMultipartFileEditor(); + MockControl mock = MockControl.createControl(MultipartFile.class); + MultipartFile file = (MultipartFile) mock.getMock(); + file.getBytes(); + mock.setReturnValue(expectedValue.getBytes()); + mock.replay(); + editor.setValue(file); + assertEquals(expectedValue, editor.getAsText()); + mock.verify(); + } + + public void testSetValueAsMultipartFileWithBadBytes() throws Exception { + ByteArrayMultipartFileEditor editor = new ByteArrayMultipartFileEditor(); + MockControl mock = MockControl.createControl(MultipartFile.class); + MultipartFile file = (MultipartFile) mock.getMock(); + file.getBytes(); + mock.setThrowable(new IOException()); + mock.replay(); + try { + editor.setValue(file); + fail("Must have thrown an IllegalArgumentException: IOException thrown when reading MultipartFile bytes"); + } + catch (IllegalArgumentException expected) { + } + mock.verify(); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/ComplexWebApplicationContext.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/ComplexWebApplicationContext.java new file mode 100644 index 00000000000..1721868b219 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/ComplexWebApplicationContext.java @@ -0,0 +1,461 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.context.support.ApplicationObjectSupport; +import org.springframework.core.Ordered; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.ServletRequestBindingException; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.context.request.WebRequestInterceptor; +import org.springframework.web.context.support.RequestHandledEvent; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.multipart.MaxUploadSizeExceededException; +import org.springframework.web.multipart.MultipartException; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.multipart.MultipartResolver; +import org.springframework.web.multipart.support.AbstractMultipartHttpServletRequest; +import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver; +import org.springframework.web.servlet.handler.SimpleServletHandlerAdapter; +import org.springframework.web.servlet.handler.SimpleServletPostProcessor; +import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; +import org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; +import org.springframework.web.servlet.i18n.SessionLocaleResolver; +import org.springframework.web.servlet.mvc.Controller; +import org.springframework.web.servlet.mvc.ParameterizableViewController; +import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; +import org.springframework.web.servlet.mvc.SimpleFormController; +import org.springframework.web.servlet.support.RequestContextUtils; +import org.springframework.web.servlet.theme.SessionThemeResolver; +import org.springframework.web.servlet.theme.ThemeChangeInterceptor; +import org.springframework.web.servlet.view.InternalResourceViewResolver; +import org.springframework.web.servlet.view.ResourceBundleViewResolver; + +/** + * @author Juergen Hoeller + * @since 21.05.2003 + */ +public class ComplexWebApplicationContext extends StaticWebApplicationContext { + + public void refresh() throws BeansException { + registerSingleton(DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME, SessionLocaleResolver.class); + registerSingleton(DispatcherServlet.THEME_RESOLVER_BEAN_NAME, SessionThemeResolver.class); + + LocaleChangeInterceptor interceptor1 = new LocaleChangeInterceptor(); + LocaleChangeInterceptor interceptor2 = new LocaleChangeInterceptor(); + interceptor2.setParamName("locale2"); + ThemeChangeInterceptor interceptor3 = new ThemeChangeInterceptor(); + ThemeChangeInterceptor interceptor4 = new ThemeChangeInterceptor(); + interceptor4.setParamName("theme2"); + UserRoleAuthorizationInterceptor interceptor5 = new UserRoleAuthorizationInterceptor(); + interceptor5.setAuthorizedRoles(new String[] {"role1", "role2"}); + + List interceptors = new ArrayList(); + interceptors.add(interceptor5); + interceptors.add(interceptor1); + interceptors.add(interceptor2); + interceptors.add(interceptor3); + interceptors.add(interceptor4); + interceptors.add(new MyHandlerInterceptor1()); + interceptors.add(new MyHandlerInterceptor2()); + interceptors.add(new MyWebRequestInterceptor()); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue( + "mappings", "/view.do=viewHandler\n/locale.do=localeHandler\nloc.do=anotherLocaleHandler"); + pvs.addPropertyValue("interceptors", interceptors); + registerSingleton("myUrlMapping1", SimpleUrlHandlerMapping.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue( + "mappings", "/form.do=localeHandler\n/unknown.do=unknownHandler\nservlet.do=myServlet"); + pvs.addPropertyValue("order", "2"); + registerSingleton("myUrlMapping2", SimpleUrlHandlerMapping.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue( + "mappings", "/form.do=formHandler\n/head.do=headController\n" + + "body.do=bodyController\n/noview*=noviewController\n/noview/simple*=noviewController"); + pvs.addPropertyValue("order", "1"); + registerSingleton("handlerMapping", SimpleUrlHandlerMapping.class, pvs); + + registerSingleton("myDummyAdapter", MyDummyAdapter.class); + registerSingleton("myHandlerAdapter", MyHandlerAdapter.class); + registerSingleton("standardHandlerAdapter", SimpleControllerHandlerAdapter.class); + registerSingleton("noviewController", NoViewController.class); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("order", new Integer(0)); + pvs.addPropertyValue("basename", "org.springframework.web.servlet.complexviews"); + registerSingleton("viewResolver", ResourceBundleViewResolver.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("suffix", ".jsp"); + registerSingleton("viewResolver2", InternalResourceViewResolver.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("commandClass", "org.springframework.beans.TestBean"); + pvs.addPropertyValue("formView", "form"); + registerSingleton("formHandler", SimpleFormController.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("viewName", "form"); + registerSingleton("viewHandler", ParameterizableViewController.class, pvs); + + registerSingleton("localeHandler", ComplexLocaleChecker.class); + registerSingleton("anotherLocaleHandler", ComplexLocaleChecker.class); + registerSingleton("unknownHandler", Object.class); + + registerSingleton("headController", HeadController.class); + registerSingleton("bodyController", BodyController.class); + + registerSingleton("servletPostProcessor", SimpleServletPostProcessor.class); + registerSingleton("handlerAdapter", SimpleServletHandlerAdapter.class); + registerSingleton("myServlet", MyServlet.class); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("order", "1"); + pvs.addPropertyValue("exceptionMappings", + "java.lang.IllegalAccessException=failed2\n" + + "ServletRequestBindingException=failed3"); + pvs.addPropertyValue("defaultErrorView", "failed0"); + registerSingleton("exceptionResolver1", SimpleMappingExceptionResolver.class, pvs); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("order", "0"); + pvs.addPropertyValue("exceptionMappings", "java.lang.Exception=failed1"); + List mappedHandlers = new ManagedList(); + mappedHandlers.add(new RuntimeBeanReference("anotherLocaleHandler")); + pvs.addPropertyValue("mappedHandlers", mappedHandlers); + pvs.addPropertyValue("defaultStatusCode", "500"); + pvs.addPropertyValue("defaultErrorView", "failed2"); + registerSingleton("handlerExceptionResolver", SimpleMappingExceptionResolver.class, pvs); + + registerSingleton("multipartResolver", MockMultipartResolver.class); + registerSingleton("testListener", TestApplicationListener.class); + + addMessage("test", Locale.ENGLISH, "test message"); + addMessage("test", Locale.CANADA, "Canadian & test message"); + + super.refresh(); + } + + + public static class HeadController implements Controller { + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + if ("HEAD".equals(request.getMethod())) { + response.setContentLength(5); + } + return null; + } + } + + + public static class BodyController implements Controller { + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + response.getOutputStream().write("body".getBytes()); + return null; + } + } + + + public static class NoViewController implements Controller { + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + return new ModelAndView(); + } + } + + + public static class MyServlet implements Servlet { + + private ServletConfig servletConfig; + + public void init(ServletConfig servletConfig) throws ServletException { + this.servletConfig = servletConfig; + } + + public ServletConfig getServletConfig() { + return servletConfig; + } + + public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException { + servletResponse.getOutputStream().write("body".getBytes()); + } + + public String getServletInfo() { + return null; + } + + public void destroy() { + this.servletConfig = null; + } + } + + + public static interface MyHandler { + + public void doSomething(HttpServletRequest request) throws ServletException, IllegalAccessException; + + public long lastModified(); + } + + + public static class MyHandlerAdapter extends ApplicationObjectSupport implements HandlerAdapter, Ordered { + + public int getOrder() { + return 99; + } + + public boolean supports(Object handler) { + return handler != null && MyHandler.class.isAssignableFrom(handler.getClass()); + } + + public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object delegate) + throws ServletException, IllegalAccessException { + ((MyHandler) delegate).doSomething(request); + return null; + } + + public long getLastModified(HttpServletRequest request, Object delegate) { + return ((MyHandler) delegate).lastModified(); + } + } + + + public static class MyDummyAdapter extends ApplicationObjectSupport implements HandlerAdapter { + + public boolean supports(Object handler) { + return handler != null && MyHandler.class.isAssignableFrom(handler.getClass()); + } + + public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object delegate) + throws IOException, ServletException { + throw new ServletException("dummy"); + } + + public long getLastModified(HttpServletRequest request, Object delegate) { + return -1; + } + } + + + public static class MyHandlerInterceptor1 implements HandlerInterceptor { + + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws ServletException { + if (request.getAttribute("test2") != null) { + throw new ServletException("Wrong interceptor order"); + } + request.setAttribute("test1", "test1"); + request.setAttribute("test1x", "test1x"); + request.setAttribute("test1y", "test1y"); + return true; + } + + public void postHandle( + HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) + throws ServletException { + if (request.getAttribute("test2x") != null) { + throw new ServletException("Wrong interceptor order"); + } + if (!"test1x".equals(request.getAttribute("test1x"))) { + throw new ServletException("Incorrect request attribute"); + } + request.removeAttribute("test1x"); + } + + public void afterCompletion( + HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) + throws ServletException { + if (request.getAttribute("test2y") != null) { + throw new ServletException("Wrong interceptor order"); + } + request.removeAttribute("test1y"); + } + } + + + public static class MyHandlerInterceptor2 implements HandlerInterceptor { + + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws ServletException { + if (request.getAttribute("test1x") == null) { + throw new ServletException("Wrong interceptor order"); + } + if (request.getParameter("abort") != null) { + return false; + } + request.setAttribute("test2", "test2"); + request.setAttribute("test2x", "test2x"); + request.setAttribute("test2y", "test2y"); + return true; + } + + public void postHandle( + HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) + throws ServletException { + if (request.getParameter("noView") != null) { + modelAndView.clear(); + } + if (request.getAttribute("test1x") == null) { + throw new ServletException("Wrong interceptor order"); + } + if (!"test2x".equals(request.getAttribute("test2x"))) { + throw new ServletException("Incorrect request attribute"); + } + request.removeAttribute("test2x"); + } + + public void afterCompletion( + HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) + throws Exception { + if (request.getAttribute("test1y") == null) { + throw new ServletException("Wrong interceptor order"); + } + request.removeAttribute("test2y"); + } + } + + + public static class MyWebRequestInterceptor implements WebRequestInterceptor { + + public void preHandle(WebRequest request) throws Exception { + request.setAttribute("test3", "test3", WebRequest.SCOPE_REQUEST); + } + + public void postHandle(WebRequest request, ModelMap model) throws Exception { + request.setAttribute("test3x", "test3x", WebRequest.SCOPE_REQUEST); + } + + public void afterCompletion(WebRequest request, Exception ex) throws Exception { + request.setAttribute("test3y", "test3y", WebRequest.SCOPE_REQUEST); + } + } + + + public static class ComplexLocaleChecker implements MyHandler { + + public void doSomething(HttpServletRequest request) throws ServletException, IllegalAccessException { + WebApplicationContext wac = RequestContextUtils.getWebApplicationContext(request); + if (!(wac instanceof ComplexWebApplicationContext)) { + throw new ServletException("Incorrect WebApplicationContext"); + } + if (!(request instanceof MultipartHttpServletRequest)) { + throw new ServletException("Not in a MultipartHttpServletRequest"); + } + if (!(RequestContextUtils.getLocaleResolver(request) instanceof SessionLocaleResolver)) { + throw new ServletException("Incorrect LocaleResolver"); + } + if (!Locale.CANADA.equals(RequestContextUtils.getLocale(request))) { + throw new ServletException("Incorrect Locale"); + } + if (!Locale.CANADA.equals(LocaleContextHolder.getLocale())) { + throw new ServletException("Incorrect Locale"); + } + if (!(RequestContextUtils.getThemeResolver(request) instanceof SessionThemeResolver)) { + throw new ServletException("Incorrect ThemeResolver"); + } + if (!"theme".equals(RequestContextUtils.getThemeResolver(request).resolveThemeName(request))) { + throw new ServletException("Incorrect theme name"); + } + if (request.getParameter("fail") != null) { + throw new ModelAndViewDefiningException(new ModelAndView("failed1")); + } + if (request.getParameter("access") != null) { + throw new IllegalAccessException("illegal access"); + } + if (request.getParameter("servlet") != null) { + throw new ServletRequestBindingException("servlet"); + } + if (request.getParameter("exception") != null) { + throw new RuntimeException("servlet"); + } + } + + public long lastModified() { + return 99; + } + } + + + public static class MockMultipartResolver implements MultipartResolver { + + public boolean isMultipart(HttpServletRequest request) { + return true; + } + + public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException { + if (request.getAttribute("fail") != null) { + throw new MaxUploadSizeExceededException(1000); + } + if (request instanceof MultipartHttpServletRequest) { + throw new IllegalStateException("Already a multipart request"); + } + if (request.getAttribute("resolved") != null) { + throw new IllegalStateException("Already resolved"); + } + request.setAttribute("resolved", Boolean.TRUE); + return new AbstractMultipartHttpServletRequest(request) { + }; + } + + public void cleanupMultipart(MultipartHttpServletRequest request) { + if (request.getAttribute("cleanedUp") != null) { + throw new IllegalStateException("Already cleaned up"); + } + request.setAttribute("cleanedUp", Boolean.TRUE); + } + } + + + public static class TestApplicationListener implements ApplicationListener { + + public int counter = 0; + + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof RequestHandledEvent) { + this.counter++; + } + } + } + +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java new file mode 100644 index 00000000000..0364bc6abb4 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java @@ -0,0 +1,871 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet; + +import java.io.IOException; +import java.util.Locale; +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.TestBean; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletConfig; +import org.springframework.mock.web.MockServletContext; +import org.springframework.validation.BindException; +import org.springframework.web.bind.EscapedErrors; +import org.springframework.web.context.ServletConfigAwareBean; +import org.springframework.web.context.ServletContextAwareBean; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.multipart.MaxUploadSizeExceededException; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.multipart.MultipartResolver; +import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver; +import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; +import org.springframework.web.servlet.mvc.BaseCommandController; +import org.springframework.web.servlet.mvc.Controller; +import org.springframework.web.servlet.support.RequestContext; +import org.springframework.web.servlet.support.RequestContextUtils; +import org.springframework.web.servlet.theme.AbstractThemeResolver; +import org.springframework.web.servlet.view.InternalResourceViewResolver; +import org.springframework.web.util.WebUtils; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rob Harrop + */ +public class DispatcherServletTests extends TestCase { + + private static final String URL_KNOWN_ONLY_PARENT = "/knownOnlyToParent.do"; + + private MockServletConfig servletConfig; + + private DispatcherServlet simpleDispatcherServlet; + + private DispatcherServlet complexDispatcherServlet; + + protected void setUp() throws ServletException { + servletConfig = new MockServletConfig(new MockServletContext(), "simple"); + MockServletConfig complexConfig = new MockServletConfig(servletConfig.getServletContext(), "complex"); + complexConfig.addInitParameter("publishContext", "false"); + complexConfig.addInitParameter("class", "notWritable"); + complexConfig.addInitParameter("unknownParam", "someValue"); + + simpleDispatcherServlet = new DispatcherServlet(); + simpleDispatcherServlet.setContextClass(SimpleWebApplicationContext.class); + simpleDispatcherServlet.init(servletConfig); + + complexDispatcherServlet = new DispatcherServlet(); + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + complexDispatcherServlet.addRequiredProperty("publishContext"); + complexDispatcherServlet.init(complexConfig); + } + + private ServletContext getServletContext() { + return servletConfig.getServletContext(); + } + + public void testDispatcherServletGetServletNameDoesNotFailWithoutConfig() { + DispatcherServlet ds = new DispatcherServlet(); + assertNull(ds.getServletConfig()); + assertNull(ds.getServletName()); + assertNull(ds.getServletContext()); + } + + public void testConfiguredDispatcherServlets() { + assertTrue("Correct namespace", + ("simple" + FrameworkServlet.DEFAULT_NAMESPACE_SUFFIX).equals(simpleDispatcherServlet.getNamespace())); + assertTrue("Correct attribute", (FrameworkServlet.SERVLET_CONTEXT_PREFIX + "simple").equals( + simpleDispatcherServlet.getServletContextAttributeName())); + assertTrue("Context published", simpleDispatcherServlet.getWebApplicationContext() == + getServletContext().getAttribute(FrameworkServlet.SERVLET_CONTEXT_PREFIX + "simple")); + + assertTrue("Correct namespace", "test".equals(complexDispatcherServlet.getNamespace())); + assertTrue("Correct attribute", (FrameworkServlet.SERVLET_CONTEXT_PREFIX + "complex").equals( + complexDispatcherServlet.getServletContextAttributeName())); + assertTrue("Context not published", + getServletContext().getAttribute(FrameworkServlet.SERVLET_CONTEXT_PREFIX + "complex") == null); + + simpleDispatcherServlet.destroy(); + complexDispatcherServlet.destroy(); + } + + public void testInvalidRequest() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/invalid.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + simpleDispatcherServlet.service(request, response); + assertTrue("Not forwarded", response.getForwardedUrl() == null); + assertTrue("correct error code", response.getStatus() == HttpServletResponse.SC_NOT_FOUND); + } + + public void testRequestHandledEvent() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + ComplexWebApplicationContext.TestApplicationListener listener = + (ComplexWebApplicationContext.TestApplicationListener) complexDispatcherServlet + .getWebApplicationContext().getBean("testListener"); + Assert.assertEquals(1, listener.counter); + } + + public void testPublishEventsOff() throws Exception { + complexDispatcherServlet.setPublishEvents(false); + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + ComplexWebApplicationContext.TestApplicationListener listener = + (ComplexWebApplicationContext.TestApplicationListener) complexDispatcherServlet + .getWebApplicationContext().getBean("testListener"); + Assert.assertEquals(0, listener.counter); + } + + public void testFormRequest() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/form.do"); + request.addPreferredLocale(Locale.CANADA); + MockHttpServletResponse response = new MockHttpServletResponse(); + + simpleDispatcherServlet.service(request, response); + assertTrue("forwarded to form", "form".equals(response.getForwardedUrl())); + DefaultMessageSourceResolvable resolvable = new DefaultMessageSourceResolvable(new String[]{"test"}); + RequestContext rc = new RequestContext(request); + + assertTrue("hasn't RequestContext attribute", request.getAttribute("rc") == null); + assertTrue("Correct WebApplicationContext", + RequestContextUtils.getWebApplicationContext(request) instanceof SimpleWebApplicationContext); + assertTrue("Correct context path", rc.getContextPath().equals(request.getContextPath())); + assertTrue("Correct locale", Locale.CANADA.equals(RequestContextUtils.getLocale(request))); + assertTrue("Correct theme", AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME.equals( + RequestContextUtils.getTheme(request).getName())); + assertTrue("Correct message", "Canadian & test message".equals(rc.getMessage("test"))); + + assertTrue("Correct WebApplicationContext", + rc.getWebApplicationContext() == simpleDispatcherServlet.getWebApplicationContext()); + assertTrue("Correct Errors", + !(rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME) instanceof EscapedErrors)); + assertTrue("Correct Errors", + !(rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME, false) instanceof EscapedErrors)); + assertTrue("Correct Errors", + rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME, true) instanceof EscapedErrors); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test")); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test", null, false)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test", null, true)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable, false)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable, true)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test", "default")); + assertEquals("Correct message", "default", rc.getMessage("testa", "default")); + assertEquals("Correct message", "default &", rc.getMessage("testa", null, "default &", true)); + } + + public void testParameterizableViewController() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/view.do"); + request.addUserRole("role1"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertTrue("forwarded to form", "myform.jsp".equals(response.getForwardedUrl())); + } + + public void testHandlerInterceptorSuppressesView() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/view.do"); + request.addUserRole("role1"); + request.addParameter("noView", "true"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertTrue("Not forwarded", response.getForwardedUrl() == null); + } + + public void testLocaleRequest() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + MockHttpServletResponse response = new MockHttpServletResponse(); + assertEquals(98, simpleDispatcherServlet.getLastModified(request)); + simpleDispatcherServlet.service(request, response); + assertTrue("Not forwarded", response.getForwardedUrl() == null); + } + + public void testUnknownRequest() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/unknown.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals("forwarded to failed", "failed0.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception").getClass().equals(ServletException.class)); + } + + public void testAnotherFormRequest() throws Exception { + MockHttpServletRequest request = + new MockHttpServletRequest(getServletContext(), "GET", "/form.do;jsessionid=xxx"); + request.addPreferredLocale(Locale.CANADA); + MockHttpServletResponse response = new MockHttpServletResponse(); + + complexDispatcherServlet.service(request, response); + assertTrue("forwarded to form", "myform.jsp".equals(response.getForwardedUrl())); + assertTrue("has RequestContext attribute", request.getAttribute("rc") != null); + DefaultMessageSourceResolvable resolvable = new DefaultMessageSourceResolvable(new String[]{"test"}); + + RequestContext rc = (RequestContext) request.getAttribute("rc"); + assertTrue("Not in HTML escaping mode", !rc.isDefaultHtmlEscape()); + assertTrue("Correct WebApplicationContext", + rc.getWebApplicationContext() == complexDispatcherServlet.getWebApplicationContext()); + assertTrue("Correct context path", rc.getContextPath().equals(request.getContextPath())); + assertTrue("Correct locale", Locale.CANADA.equals(rc.getLocale())); + assertTrue("Correct Errors", + !(rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME) instanceof EscapedErrors)); + assertTrue("Correct Errors", + !(rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME, false) instanceof EscapedErrors)); + assertTrue("Correct Errors", + rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME, true) instanceof EscapedErrors); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test")); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test", null, false)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test", null, true)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable, false)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable, true)); + + rc.setDefaultHtmlEscape(true); + assertTrue("Is in HTML escaping mode", rc.isDefaultHtmlEscape()); + assertTrue("Correct Errors", rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME) instanceof EscapedErrors); + assertTrue("Correct Errors", + !(rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME, false) instanceof EscapedErrors)); + assertTrue("Correct Errors", + rc.getErrors(BaseCommandController.DEFAULT_COMMAND_NAME, true) instanceof EscapedErrors); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test")); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test", null, false)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage("test", null, true)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable, false)); + assertEquals("Correct message", "Canadian & test message", rc.getMessage(resolvable, true)); + } + + public void testAnotherLocaleRequest() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do;abc=def"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + MockHttpServletResponse response = new MockHttpServletResponse(); + assertEquals(99, complexDispatcherServlet.getLastModified(request)); + complexDispatcherServlet.service(request, response); + + assertTrue("Not forwarded", response.getForwardedUrl() == null); + assertTrue(request.getAttribute("test1") != null); + assertTrue(request.getAttribute("test1x") == null); + assertTrue(request.getAttribute("test1y") == null); + assertTrue(request.getAttribute("test2") != null); + assertTrue(request.getAttribute("test2x") == null); + assertTrue(request.getAttribute("test2y") == null); + assertTrue(request.getAttribute("test3") != null); + assertTrue(request.getAttribute("test3x") != null); + assertTrue(request.getAttribute("test3y") != null); + } + + public void testExistingMultipartRequest() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do;abc=def"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ComplexWebApplicationContext.MockMultipartResolver multipartResolver = + (ComplexWebApplicationContext.MockMultipartResolver) complexDispatcherServlet.getWebApplicationContext() + .getBean("multipartResolver"); + MultipartHttpServletRequest multipartRequest = multipartResolver.resolveMultipart(request); + complexDispatcherServlet.service(multipartRequest, response); + multipartResolver.cleanupMultipart(multipartRequest); + assertNotNull(request.getAttribute("cleanedUp")); + } + + public void testMultipartResolutionFailed() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do;abc=def"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.setAttribute("fail", Boolean.TRUE); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertTrue("forwarded to failed", "failed0.jsp".equals(response.getForwardedUrl())); + assertEquals(200, response.getStatus()); + assertTrue("correct exception", request.getAttribute( + SimpleMappingExceptionResolver.DEFAULT_EXCEPTION_ATTRIBUTE) instanceof MaxUploadSizeExceededException); + } + + public void testHandlerInterceptorAbort() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addParameter("abort", "true"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertTrue("Not forwarded", response.getForwardedUrl() == null); + assertTrue(request.getAttribute("test1") != null); + assertTrue(request.getAttribute("test1x") != null); + assertTrue(request.getAttribute("test1y") == null); + assertTrue(request.getAttribute("test2") == null); + assertTrue(request.getAttribute("test2x") == null); + assertTrue(request.getAttribute("test2y") == null); + } + + public void testModelAndViewDefiningException() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("fail", "yes"); + MockHttpServletResponse response = new MockHttpServletResponse(); + try { + complexDispatcherServlet.service(request, response); + assertEquals(200, response.getStatus()); + assertTrue("forwarded to failed", "failed1.jsp".equals(response.getForwardedUrl())); + } + catch (ServletException ex) { + fail("Should not have thrown ServletException: " + ex.getMessage()); + } + } + + public void testSimpleMappingExceptionResolverWithSpecificHandler1() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("access", "yes"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(200, response.getStatus()); + assertEquals("forwarded to failed", "failed2.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception") instanceof IllegalAccessException); + } + + public void testSimpleMappingExceptionResolverWithSpecificHandler2() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("servlet", "yes"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(200, response.getStatus()); + assertEquals("forwarded to failed", "failed3.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception") instanceof ServletException); + } + + public void testSimpleMappingExceptionResolverWithAllHandlers1() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/loc.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("access", "yes"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(500, response.getStatus()); + assertEquals("forwarded to failed", "failed1.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception") instanceof IllegalAccessException); + } + + public void testSimpleMappingExceptionResolverWithAllHandlers2() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/loc.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("servlet", "yes"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(500, response.getStatus()); + assertEquals("forwarded to failed", "failed1.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception") instanceof ServletException); + } + + public void testSimpleMappingExceptionResolverWithDefaultErrorView() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("exception", "yes"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(200, response.getStatus()); + assertEquals("forwarded to failed", "failed0.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception").getClass().equals(RuntimeException.class)); + } + + public void testLocaleChangeInterceptor1() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.GERMAN); + request.addUserRole("role2"); + request.addParameter("locale", "en"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(200, response.getStatus()); + assertEquals("forwarded to failed", "failed0.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception").getClass().equals(ServletException.class)); + } + + public void testLocaleChangeInterceptor2() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.GERMAN); + request.addUserRole("role2"); + request.addParameter("locale", "en"); + request.addParameter("locale2", "en_CA"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertTrue("Not forwarded", response.getForwardedUrl() == null); + } + + public void testThemeChangeInterceptor1() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("theme", "mytheme"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(200, response.getStatus()); + assertEquals("forwarded to failed", "failed0.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception").getClass().equals(ServletException.class)); + } + + public void testThemeChangeInterceptor2() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + request.addUserRole("role1"); + request.addParameter("theme", "mytheme"); + request.addParameter("theme2", "theme"); + MockHttpServletResponse response = new MockHttpServletResponse(); + try { + complexDispatcherServlet.service(request, response); + assertTrue("Not forwarded", response.getForwardedUrl() == null); + } + catch (ServletException ex) { + fail("Should not have thrown ServletException: " + ex.getMessage()); + } + } + + public void testNotAuthorized() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/locale.do"); + request.addPreferredLocale(Locale.CANADA); + MockHttpServletResponse response = new MockHttpServletResponse(); + try { + complexDispatcherServlet.service(request, response); + assertTrue("Correct response", response.getStatus() == HttpServletResponse.SC_FORBIDDEN); + } + catch (ServletException ex) { + fail("Should not have thrown ServletException: " + ex.getMessage()); + } + } + + public void testHeadMethodWithExplicitHandling() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "HEAD", "/head.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(5, response.getContentLength()); + + request = new MockHttpServletRequest(getServletContext(), "GET", "/head.do"); + response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals("", response.getContentAsString()); + } + + public void testHeadMethodWithNoBodyResponse() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "HEAD", "/body.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(4, response.getContentLength()); + + request = new MockHttpServletRequest(getServletContext(), "GET", "/body.do"); + response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals("body", response.getContentAsString()); + } + + public void testNotDetectAllHandlerMappings() throws ServletException, IOException { + DispatcherServlet complexDispatcherServlet = new DispatcherServlet(); + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + complexDispatcherServlet.setDetectAllHandlerMappings(false); + complexDispatcherServlet.init(new MockServletConfig(getServletContext(), "complex")); + + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/unknown.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertTrue(response.getStatus() == HttpServletResponse.SC_NOT_FOUND); + } + + public void testHandlerNotMappedWithAutodetect() throws ServletException, IOException { + DispatcherServlet complexDispatcherServlet = new DispatcherServlet(); + // no parent + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + complexDispatcherServlet.init(new MockServletConfig(getServletContext(), "complex")); + + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", URL_KNOWN_ONLY_PARENT); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals(HttpServletResponse.SC_NOT_FOUND, response.getStatus()); + } + + public void testDetectHandlerMappingFromParent() throws ServletException, IOException { + // create a parent context that includes a mapping + StaticWebApplicationContext parent = new StaticWebApplicationContext(); + parent.setServletContext(servletConfig.getServletContext()); + parent.registerSingleton("parentHandler", ControllerFromParent.class, new MutablePropertyValues()); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue(new PropertyValue("mappings", URL_KNOWN_ONLY_PARENT + "=parentHandler")); + + parent.registerSingleton("parentMapping", SimpleUrlHandlerMapping.class, pvs); + parent.refresh(); + + DispatcherServlet complexDispatcherServlet = new DispatcherServlet(); + // will have parent + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + + ServletConfig config = new MockServletConfig(getServletContext(), "complex"); + config.getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, parent); + complexDispatcherServlet.init(config); + + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", URL_KNOWN_ONLY_PARENT); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + + assertFalse("Matched through parent controller/handler pair: not response=" + response.getStatus(), + response.getStatus() == HttpServletResponse.SC_NOT_FOUND); + } + + public void testDetectAllHandlerAdapters() throws ServletException, IOException { + DispatcherServlet complexDispatcherServlet = new DispatcherServlet(); + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + complexDispatcherServlet.init(new MockServletConfig(getServletContext(), "complex")); + + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/servlet.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals("body", response.getContentAsString()); + + request = new MockHttpServletRequest(getServletContext(), "GET", "/form.do"); + response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertTrue("forwarded to form", "myform.jsp".equals(response.getForwardedUrl())); + } + + public void testNotDetectAllHandlerAdapters() throws ServletException, IOException { + DispatcherServlet complexDispatcherServlet = new DispatcherServlet(); + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + complexDispatcherServlet.setDetectAllHandlerAdapters(false); + complexDispatcherServlet.init(new MockServletConfig(getServletContext(), "complex")); + + // only ServletHandlerAdapter with bean name "handlerAdapter" detected + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/servlet.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals("body", response.getContentAsString()); + + // SimpleControllerHandlerAdapter not detected + request = new MockHttpServletRequest(getServletContext(), "GET", "/form.do"); + response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals("forwarded to failed", "failed0.jsp", response.getForwardedUrl()); + assertTrue("Exception exposed", request.getAttribute("exception").getClass().equals(ServletException.class)); + } + + public void testNotDetectAllHandlerExceptionResolvers() throws ServletException, IOException { + DispatcherServlet complexDispatcherServlet = new DispatcherServlet(); + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + complexDispatcherServlet.setDetectAllHandlerExceptionResolvers(false); + complexDispatcherServlet.init(new MockServletConfig(getServletContext(), "complex")); + + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/unknown.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + try { + complexDispatcherServlet.service(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + // expected + assertTrue(ex.getMessage().indexOf("No adapter for handler") != -1); + } + } + + public void testNotDetectAllViewResolvers() throws ServletException, IOException { + DispatcherServlet complexDispatcherServlet = new DispatcherServlet(); + complexDispatcherServlet.setContextClass(ComplexWebApplicationContext.class); + complexDispatcherServlet.setNamespace("test"); + complexDispatcherServlet.setDetectAllViewResolvers(false); + complexDispatcherServlet.init(new MockServletConfig(getServletContext(), "complex")); + + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/unknown.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + try { + complexDispatcherServlet.service(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + // expected + assertTrue(ex.getMessage().indexOf("failed0") != -1); + } + } + + public void testCleanupAfterIncludeWithRemove() throws ServletException, IOException { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/main.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setAttribute("test1", "value1"); + request.setAttribute("test2", "value2"); + WebApplicationContext wac = new StaticWebApplicationContext(); + request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + + request.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, "/form.do"); + simpleDispatcherServlet.service(request, response); + assertTrue("forwarded to form", "form".equals(response.getIncludedUrl())); + + assertEquals("value1", request.getAttribute("test1")); + assertEquals("value2", request.getAttribute("test2")); + assertEquals(wac, request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE)); + assertNull(request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); + assertNull(request.getAttribute("command")); + } + + public void testCleanupAfterIncludeWithRestore() throws ServletException, IOException { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/main.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setAttribute("test1", "value1"); + request.setAttribute("test2", "value2"); + WebApplicationContext wac = new StaticWebApplicationContext(); + request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + TestBean command = new TestBean(); + request.setAttribute("command", command); + + request.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, "/form.do"); + simpleDispatcherServlet.service(request, response); + assertTrue("forwarded to form", "form".equals(response.getIncludedUrl())); + + assertEquals("value1", request.getAttribute("test1")); + assertEquals("value2", request.getAttribute("test2")); + assertSame(wac, request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE)); + assertSame(command, request.getAttribute("command")); + } + + public void testNoCleanupAfterInclude() throws ServletException, IOException { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/main.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setAttribute("test1", "value1"); + request.setAttribute("test2", "value2"); + WebApplicationContext wac = new StaticWebApplicationContext(); + request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + TestBean command = new TestBean(); + request.setAttribute("command", command); + + request.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, "/form.do"); + simpleDispatcherServlet.setCleanupAfterInclude(false); + simpleDispatcherServlet.service(request, response); + assertTrue("forwarded to form", "form".equals(response.getIncludedUrl())); + + assertEquals("value1", request.getAttribute("test1")); + assertEquals("value2", request.getAttribute("test2")); + assertSame(wac, request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE)); + assertNotSame(command, request.getAttribute("command")); + } + + public void testServletHandlerAdapter() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/servlet.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + complexDispatcherServlet.service(request, response); + assertEquals("body", response.getContentAsString()); + + Servlet myServlet = (Servlet) complexDispatcherServlet.getWebApplicationContext().getBean("myServlet"); + assertEquals("complex", myServlet.getServletConfig().getServletName()); + assertEquals(getServletContext(), myServlet.getServletConfig().getServletContext()); + complexDispatcherServlet.destroy(); + assertNull(myServlet.getServletConfig()); + } + + public void testThrowawayController() throws Exception { + SimpleWebApplicationContext.TestThrowawayController.counter = 0; + + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/throwaway.do"); + request.addParameter("myInt", "5"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + simpleDispatcherServlet.service(request, response); + assertTrue("Correct response", "view5".equals(response.getForwardedUrl())); + Assert.assertEquals(1, SimpleWebApplicationContext.TestThrowawayController.counter); + + request = new MockHttpServletRequest(getServletContext(), "GET", "/throwaway.do"); + request.addParameter("myInt", "5"); + response = new MockHttpServletResponse(); + + simpleDispatcherServlet.service(request, response); + assertTrue("Correct response", "view5".equals(response.getForwardedUrl())); + Assert.assertEquals(2, SimpleWebApplicationContext.TestThrowawayController.counter); + } + + public void testThrowawayControllerWithBindingFailure() throws Exception { + SimpleWebApplicationContext.TestThrowawayController.counter = 0; + MockHttpServletRequest request = new MockHttpServletRequest(getServletContext(), "GET", "/throwaway.do"); + request.addParameter("myInt", "5x"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + try { + simpleDispatcherServlet.service(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + // expected + assertTrue(ex.getRootCause() instanceof BindException); + Assert.assertEquals(1, SimpleWebApplicationContext.TestThrowawayController.counter); + } + } + + public void testWebApplicationContextLookup() { + MockServletContext servletContext = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/invalid.do"); + + try { + RequestContextUtils.getWebApplicationContext(request); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + + try { + RequestContextUtils.getWebApplicationContext(request, servletContext); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + + servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, + new StaticWebApplicationContext()); + try { + RequestContextUtils.getWebApplicationContext(request, servletContext); + } + catch (IllegalStateException ex) { + fail("Should not have thrown IllegalStateException: " + ex.getMessage()); + } + } + + public void testWithNoView() throws Exception { + MockServletContext servletContext = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/noview.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + complexDispatcherServlet.service(request, response); + assertEquals("noview.jsp", response.getForwardedUrl()); + } + + public void testWithNoViewNested() throws Exception { + MockServletContext servletContext = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/noview/simple.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + complexDispatcherServlet.service(request, response); + assertEquals("noview/simple.jsp", response.getForwardedUrl()); + } + + public void testWithNoViewAndSamePath() throws Exception { + InternalResourceViewResolver vr = (InternalResourceViewResolver) complexDispatcherServlet + .getWebApplicationContext().getBean("viewResolver2"); + vr.setSuffix(""); + + MockServletContext servletContext = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/noview"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + try { + complexDispatcherServlet.service(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + ex.printStackTrace(); + } + } + + public void testDispatcherServletRefresh() throws ServletException { + MockServletContext servletContext = new MockServletContext("org/springframework/web/context"); + DispatcherServlet servlet = new DispatcherServlet(); + + servlet.init(new MockServletConfig(servletContext, "empty")); + ServletContextAwareBean contextBean = + (ServletContextAwareBean) servlet.getWebApplicationContext().getBean("servletContextAwareBean"); + ServletConfigAwareBean configBean = + (ServletConfigAwareBean) servlet.getWebApplicationContext().getBean("servletConfigAwareBean"); + assertSame(servletContext, contextBean.getServletContext()); + assertSame(servlet.getServletConfig(), configBean.getServletConfig()); + MultipartResolver multipartResolver = servlet.getMultipartResolver(); + assertNotNull(multipartResolver); + + servlet.refresh(); + + ServletContextAwareBean contextBean2 = + (ServletContextAwareBean) servlet.getWebApplicationContext().getBean("servletContextAwareBean"); + ServletConfigAwareBean configBean2 = + (ServletConfigAwareBean) servlet.getWebApplicationContext().getBean("servletConfigAwareBean"); + assertSame(servletContext, contextBean2.getServletContext()); + assertSame(servlet.getServletConfig(), configBean2.getServletConfig()); + assertNotSame(contextBean, contextBean2); + assertNotSame(configBean, configBean2); + MultipartResolver multipartResolver2 = servlet.getMultipartResolver(); + assertNotSame(multipartResolver, multipartResolver2); + + servlet.destroy(); + } + + public void testDispatcherServletContextRefresh() throws ServletException { + MockServletContext servletContext = new MockServletContext("org/springframework/web/context"); + DispatcherServlet servlet = new DispatcherServlet(); + + servlet.init(new MockServletConfig(servletContext, "empty")); + ServletContextAwareBean contextBean = + (ServletContextAwareBean) servlet.getWebApplicationContext().getBean("servletContextAwareBean"); + ServletConfigAwareBean configBean = + (ServletConfigAwareBean) servlet.getWebApplicationContext().getBean("servletConfigAwareBean"); + assertSame(servletContext, contextBean.getServletContext()); + assertSame(servlet.getServletConfig(), configBean.getServletConfig()); + MultipartResolver multipartResolver = servlet.getMultipartResolver(); + assertNotNull(multipartResolver); + + ((ConfigurableApplicationContext) servlet.getWebApplicationContext()).refresh(); + + ServletContextAwareBean contextBean2 = + (ServletContextAwareBean) servlet.getWebApplicationContext().getBean("servletContextAwareBean"); + ServletConfigAwareBean configBean2 = + (ServletConfigAwareBean) servlet.getWebApplicationContext().getBean("servletConfigAwareBean"); + assertSame(servletContext, contextBean2.getServletContext()); + assertSame(servlet.getServletConfig(), configBean2.getServletConfig()); + assertTrue(contextBean != contextBean2); + assertTrue(configBean != configBean2); + MultipartResolver multipartResolver2 = servlet.getMultipartResolver(); + assertTrue(multipartResolver != multipartResolver2); + + servlet.destroy(); + } + + public static class ControllerFromParent implements Controller { + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + return new ModelAndView(ControllerFromParent.class.getName()); + } + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/SimpleWebApplicationContext.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/SimpleWebApplicationContext.java new file mode 100644 index 00000000000..7851da8c297 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/SimpleWebApplicationContext.java @@ -0,0 +1,141 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet; + +import java.io.IOException; +import java.util.Locale; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.context.support.StaticMessageSource; +import org.springframework.ui.context.Theme; +import org.springframework.ui.context.ThemeSource; +import org.springframework.ui.context.support.SimpleTheme; +import org.springframework.ui.context.support.UiApplicationContextUtils; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; +import org.springframework.web.servlet.mvc.Controller; +import org.springframework.web.servlet.mvc.LastModified; +import org.springframework.web.servlet.mvc.SimpleFormController; +import org.springframework.web.servlet.mvc.throwaway.ThrowawayController; +import org.springframework.web.servlet.support.RequestContextUtils; +import org.springframework.web.servlet.theme.AbstractThemeResolver; +import org.springframework.web.servlet.view.InternalResourceViewResolver; +import org.springframework.web.servlet.view.XmlViewResolver; +import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; + +/** + * @author Juergen Hoeller + * @since 21.05.2003 + */ +public class SimpleWebApplicationContext extends StaticWebApplicationContext { + + public void refresh() throws BeansException { + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.addPropertyValue("commandClass", "org.springframework.beans.TestBean"); + pvs.addPropertyValue("formView", "form"); + registerSingleton("/form.do", SimpleFormController.class, pvs); + + registerSingleton("/locale.do", LocaleChecker.class); + + registerPrototype("/throwaway.do", TestThrowawayController.class); + + addMessage("test", Locale.ENGLISH, "test message"); + addMessage("test", Locale.CANADA, "Canadian & test message"); + addMessage("testArgs", Locale.ENGLISH, "test {0} message {1}"); + addMessage("testArgsFormat", Locale.ENGLISH, "test {0} message {1,number,#.##} X"); + + registerSingleton(UiApplicationContextUtils.THEME_SOURCE_BEAN_NAME, DummyThemeSource.class); + + registerSingleton("handlerMapping", BeanNameUrlHandlerMapping.class); + registerSingleton("viewResolver", InternalResourceViewResolver.class); + + pvs = new MutablePropertyValues(); + pvs.addPropertyValue("location", "org/springframework/web/context/WEB-INF/sessionContext.xml"); + registerSingleton("viewResolver2", XmlViewResolver.class, pvs); + + super.refresh(); + } + + + public static class LocaleChecker implements Controller, LastModified { + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + if (!(RequestContextUtils.getWebApplicationContext(request) instanceof SimpleWebApplicationContext)) { + throw new ServletException("Incorrect WebApplicationContext"); + } + if (!(RequestContextUtils.getLocaleResolver(request) instanceof AcceptHeaderLocaleResolver)) { + throw new ServletException("Incorrect LocaleResolver"); + } + if (!Locale.CANADA.equals(RequestContextUtils.getLocale(request))) { + throw new ServletException("Incorrect Locale"); + } + return null; + } + + public long getLastModified(HttpServletRequest request) { + return 98; + } + } + + + public static class DummyThemeSource implements ThemeSource { + + private StaticMessageSource messageSource; + + public DummyThemeSource() { + this.messageSource = new StaticMessageSource(); + this.messageSource.addMessage("themetest", Locale.ENGLISH, "theme test message"); + this.messageSource.addMessage("themetestArgs", Locale.ENGLISH, "theme test message {0}"); + } + + public Theme getTheme(String themeName) { + if (AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME.equals(themeName)) { + return new SimpleTheme(AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME, this.messageSource); + } + else { + return null; + } + } + } + + + public static class TestThrowawayController implements ThrowawayController { + + public static int counter = 0; + + private int myInt; + + public TestThrowawayController() { + counter++; + } + + public void setMyInt(int myInt) { + this.myInt = myInt; + } + + public ModelAndView execute() throws Exception { + return new ModelAndView("view" + this.myInt); + } + } + +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/CancellableFormControllerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/CancellableFormControllerTests.java new file mode 100644 index 00000000000..804d13489e5 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/CancellableFormControllerTests.java @@ -0,0 +1,236 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.validation.BindException; +import org.springframework.validation.Errors; +import org.springframework.validation.Validator; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class CancellableFormControllerTests extends TestCase { + + public void testFormViewRequest() throws Exception { + String formView = "theFormView"; + + TestController ctl = new TestController(); + ctl.setFormView(formView); + ctl.setBindOnNewForm(true); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + String name = "Rob Harrop"; + int age = 23; + + request.setMethod("GET"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + + ModelAndView mv = ctl.handleRequest(request, response); + + assertEquals("Incorrect view name", formView, mv.getViewName()); + + TestBean command = (TestBean) mv.getModel().get(ctl.getCommandName()); + + testCommandIsBound(command, name, age); + } + + public void testFormSubmissionRequestWithoutCancel() throws Exception { + String successView = "successView"; + + TestController ctl = new TestController(); + ctl.setSuccessView(successView); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + String name = "Rob Harrop"; + int age = 23; + + request.setMethod("POST"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + + ModelAndView mv = ctl.handleRequest(request, response); + + assertEquals("Incorrect view name", successView, mv.getViewName()); + + TestBean command = (TestBean) mv.getModel().get(ctl.getCommandName()); + + testCommandIsBound(command, name, age); + } + + public void testFormSubmissionWithErrors() throws Exception { + String successView = "successView"; + String formView = "formView"; + + TestController ctl = new TestController(); + ctl.setSuccessView(successView); + ctl.setFormView(formView); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setMethod("POST"); + request.addParameter("name", "Rob Harrop"); + request.addParameter("age", "xxx23"); + + ModelAndView mv = ctl.handleRequest(request, response); + assertEquals("Incorrect view name", formView, mv.getViewName()); + + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + ctl.getCommandName()); + assertNotNull("No errors", errors); + assertEquals(1, errors.getErrorCount()); + } + + public void testFormSubmissionWithValidationError() throws Exception { + String successView = "successView"; + String formView = "formView"; + + TestController ctl = new TestController(); + ctl.setSuccessView(successView); + ctl.setFormView(formView); + TestValidator val = new TestValidator(); + ctl.setValidator(val); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setMethod("POST"); + request.addParameter("name", "Rob Harrop"); + request.addParameter("age", "23"); + + ModelAndView mv = ctl.handleRequest(request, response); + assertEquals("Incorrect view name", formView, mv.getViewName()); + + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + ctl.getCommandName()); + assertNotNull("No errors", errors); + assertEquals(1, errors.getErrorCount()); + assertTrue(val.invoked); + } + + public void testCancelSubmission() throws Exception { + String cancelView = "cancelView"; + String cancelParameterKey = "cancelRequest"; + + TestController ctl = new TestController(); + ctl.setCancelParamKey(cancelParameterKey); + ctl.setCancelView(cancelView); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setMethod("POST"); + request.addParameter("cancelRequest", "true"); + + ModelAndView mv = ctl.handleRequest(request, response); + assertEquals("Incorrect view name", cancelView, mv.getViewName()); + } + + public void testCancelSubmissionWithValidationError() throws Exception { + String cancelView = "cancelView"; + String cancelParameterKey = "cancelRequest"; + + TestController ctl = new TestController(); + ctl.setCancelParamKey(cancelParameterKey); + ctl.setCancelView(cancelView); + TestValidator val = new TestValidator(); + ctl.setValidator(val); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setMethod("POST"); + request.addParameter("name", "Rob Harrop"); + request.addParameter("age", "23"); + request.addParameter("cancelRequest", "true"); + + ModelAndView mv = ctl.handleRequest(request, response); + assertEquals("Incorrect view name", cancelView, mv.getViewName()); + + assertFalse(val.invoked); + } + + public void testCancelSubmissionWithCustomModelParams() throws Exception { + String cancelView = "cancelView"; + String cancelParameterKey = "cancelRequest"; + final String reason = "Because I wanted to"; + + TestController ctl = new TestController() { + protected ModelAndView onCancel(HttpServletRequest request, HttpServletResponse response, Object command) { + return new ModelAndView(getCancelView(), "reason", reason); + } + }; + + ctl.setCancelParamKey(cancelParameterKey); + ctl.setCancelView(cancelView); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.setMethod("POST"); + request.addParameter("cancelRequest", "true"); + + ModelAndView mv = ctl.handleRequest(request, response); + assertEquals("Incorrect view name", cancelView, mv.getViewName()); + assertEquals("Model parameter reason not correct", reason, mv.getModel().get("reason")); + } + + private void testCommandIsBound(TestBean command, String name, int age) { + assertNotNull("Command bean should not be null", command); + assertEquals("Name not bound", name, command.getName()); + assertEquals("Age not bound", age, command.getAge()); + } + + + private static class TestController extends CancellableFormController { + + public TestController() { + setCommandClass(TestBean.class); + } + } + + + private static class TestValidator implements Validator { + + private boolean invoked = false; + + public boolean supports(Class clazz) { + return TestBean.class.isAssignableFrom(clazz); + } + public void validate(Object target, Errors errors) { + this.invoked = true; + TestBean tb = (TestBean) target; + if (tb.getAge() < 25) { + errors.rejectValue("age", "TOO_YOUNG"); + } + } + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/CommandControllerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/CommandControllerTests.java new file mode 100644 index 00000000000..1b757c9314d --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/CommandControllerTests.java @@ -0,0 +1,510 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc; + +import java.text.DateFormat; +import java.text.NumberFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.beans.propertyeditors.CustomNumberEditor; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.validation.BindException; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.ServletRequestDataBinder; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Rod Johnson + */ +public class CommandControllerTests extends TestCase { + + public void testNoArgsNoErrors() throws Exception { + TestController mc = new TestController(); + HttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name", mv.getViewName().equals(request.getServletPath())); + TestBean person = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("command and errors non null", person != null && errors != null); + assertTrue("no errors", !errors.hasErrors()); + assertTrue("Correct caching", response.getHeader("Cache-Control") == null); + assertTrue("Correct expires header", response.getHeader("Expires") == null); + } + + public void test2ArgsNoErrors() throws Exception { + TestController mc = new TestController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + String name = "Rod"; + int age = 32; + request.addParameter("name", name); + request.addParameter("age", "" + age); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name", mv.getViewName().equals(request.getServletPath())); + TestBean person = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("command and errors non null", person != null && errors != null); + assertTrue("no errors", !errors.hasErrors()); + assertTrue("command name bound ok", person.getName().equals(name)); + assertTrue("command age bound ok", person.getAge() == age); + } + + public void test2Args1Mismatch() throws Exception { + TestController mc = new TestController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + String name = "Rod"; + String age = "32x"; + request.addParameter("name", name); + request.addParameter("age", age); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name", mv.getViewName().equals(request.getServletPath())); + TestBean person = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("command and errors non null", person != null && errors != null); + assertTrue("has 1 errors", errors.getErrorCount() == 1); + assertTrue("command name bound ok", person.getName().equals(name)); + assertTrue("command age default", person.getAge() == new TestBean().getAge()); + assertTrue("has error on field age", errors.hasFieldErrors("age")); + FieldError fe = errors.getFieldError("age"); + assertTrue("Saved invalid value", fe.getRejectedValue().equals(age)); + assertTrue("Correct field", fe.getField().equals("age")); + } + + public void testSupportedMethods() throws Exception { + TestController mc = new TestController(); + mc.setSupportedMethods(new String[] {"POST"}); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + HttpServletResponse response = new MockHttpServletResponse(); + try { + mc.handleRequest(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + // expected + } + } + + public void testRequireSessionWithoutSession() throws Exception { + TestController mc = new TestController(); + mc.setRequireSession(true); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + HttpServletResponse response = new MockHttpServletResponse(); + try { + mc.handleRequest(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + // expected + } + } + + public void testRequireSessionWithSession() throws Exception { + TestController mc = new TestController(); + mc.setRequireSession(true); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + request.setSession(new MockHttpSession(null)); + HttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + } + + public void testNoCaching() throws Exception { + TestController mc = new TestController(); + mc.setCacheSeconds(0); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires").equals(new Long(1))); + List cacheControl = response.getHeaders("Cache-Control"); + assertTrue("Correct cache control", cacheControl.contains("no-cache")); + assertTrue("Correct cache control", cacheControl.contains("no-store")); + } + + public void testNoCachingWithoutExpires() throws Exception { + TestController mc = new TestController(); + mc.setCacheSeconds(0); + mc.setUseExpiresHeader(false); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("No expires header", response.getHeader("Expires") == null); + List cacheControl = response.getHeaders("Cache-Control"); + assertTrue("Correct cache control", cacheControl.contains("no-cache")); + assertTrue("Correct cache control", cacheControl.contains("no-store")); + } + + public void testNoCachingWithoutCacheControl() throws Exception { + TestController mc = new TestController(); + mc.setCacheSeconds(0); + mc.setUseCacheControlHeader(false); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires").equals(new Long(1))); + assertTrue("No cache control", response.getHeader("Cache-Control") == null); + } + + public void testCaching() throws Exception { + TestController mc = new TestController(); + mc.setCacheSeconds(10); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires") != null); + assertTrue("Correct cache control", response.getHeader("Cache-Control").equals("max-age=10")); + } + + public void testCachingWithoutExpires() throws Exception { + TestController mc = new TestController(); + mc.setCacheSeconds(10); + mc.setUseExpiresHeader(false); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("No expires header", response.getHeader("Expires") == null); + assertTrue("Correct cache control", response.getHeader("Cache-Control").equals("max-age=10")); + } + + public void testCachingWithoutCacheControl() throws Exception { + TestController mc = new TestController(); + mc.setCacheSeconds(10); + mc.setUseCacheControlHeader(false); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires") != null); + assertTrue("No cache control", response.getHeader("Cache-Control") == null); + } + + public void testCachingWithLastModified() throws Exception { + class LastModifiedTestController extends TestController implements LastModified { + public long getLastModified(HttpServletRequest request) { + return 0; + } + } + LastModifiedTestController mc = new LastModifiedTestController(); + mc.setCacheSeconds(10); + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires") != null); + assertTrue("Correct cache control", response.getHeader("Cache-Control").equals("max-age=10, must-revalidate")); + } + + public void testCachingWithCustomCacheForSecondsCall() throws Exception { + TestController mc = new TestController() { + protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) { + cacheForSeconds(response, 5); + return super.handle(request, response, command, errors); + } + }; + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires") != null); + assertTrue("Correct cache control", response.getHeader("Cache-Control").equals("max-age=5")); + } + + public void testCachingWithCustomApplyCacheSecondsCall1() throws Exception { + TestController mc = new TestController() { + protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) { + applyCacheSeconds(response, 5); + return super.handle(request, response, command, errors); + } + }; + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires") != null); + assertTrue("Correct cache control", response.getHeader("Cache-Control").equals("max-age=5")); + } + + public void testCachingWithCustomApplyCacheSecondsCall2() throws Exception { + TestController mc = new TestController() { + protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) { + applyCacheSeconds(response, 0); + return super.handle(request, response, command, errors); + } + }; + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("Correct expires header", response.getHeader("Expires").equals(new Long(1))); + List cacheControl = response.getHeaders("Cache-Control"); + assertTrue("Correct cache control", cacheControl.contains("no-cache")); + assertTrue("Correct cache control", cacheControl.contains("no-store")); + } + + public void testCachingWithCustomApplyCacheSecondsCall3() throws Exception { + TestController mc = new TestController() { + protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) { + applyCacheSeconds(response, -1); + return super.handle(request, response, command, errors); + } + }; + HttpServletRequest request = new MockHttpServletRequest("GET", "/ok.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + mc.handleRequest(request, response); + assertTrue("No expires header", response.getHeader("Expires") == null); + assertTrue("No cache control", response.getHeader("Cache-Control") == null); + } + + public void testCustomDateEditorWithAllowEmpty() throws Exception { + final DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.GERMAN); + TestController mc = new TestController() { + protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) { + binder.registerCustomEditor(Date.class, new CustomDateEditor(df, true)); + } + }; + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("date", "1.5.2003"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("No field error", !errors.hasFieldErrors("date")); + assertTrue("Correct date property", df.parse("1.5.2003").equals(tb.getDate())); + assertTrue("Correct date value", "01.05.2003".equals(errors.getFieldValue("date"))); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("date", ""); + response = new MockHttpServletResponse(); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + errors = (Errors) mv.getModel().get("errors"); + assertTrue("No field error", !errors.hasFieldErrors("date")); + assertTrue("Correct date property", tb.getDate() == null); + assertTrue("Correct date value", "".equals(errors.getFieldValue("date"))); + } + + public void testCustomDateEditorWithoutAllowEmpty() throws Exception { + final DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.GERMAN); + TestController mc = new TestController() { + protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) { + binder.registerCustomEditor(Date.class, new CustomDateEditor(df, false)); + } + }; + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("date", "1.5.2003"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("No field error", !errors.hasFieldErrors("date")); + assertTrue("Correct date property", df.parse("1.5.2003").equals(tb.getDate())); + assertTrue("Correct date value", "01.05.2003".equals(errors.getFieldValue("date"))); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("date", ""); + response = new MockHttpServletResponse(); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + errors = (Errors) mv.getModel().get("errors"); + assertTrue("Has field error", errors.hasFieldErrors("date")); + assertTrue("Correct date property", tb.getDate() != null); + assertTrue("Correct date value", errors.getFieldValue("date") != null); + } + + public void testCustomNumberEditorWithAllowEmpty() throws Exception { + final NumberFormat nf = NumberFormat.getNumberInstance(Locale.GERMAN); + + TestController mc = new TestController() { + protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) { + binder.registerCustomEditor(Float.class, new CustomNumberEditor(Float.class, nf, true)); + } + }; + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("myFloat", "5,1"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("No field error", !errors.hasFieldErrors("myFloat")); + assertTrue("Correct float property", (new Float(5.1)).equals(tb.getMyFloat())); + assertTrue("Correct float value", "5,1".equals(errors.getFieldValue("myFloat"))); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("myFloat", ""); + response = new MockHttpServletResponse(); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + errors = (Errors) mv.getModel().get("errors"); + assertTrue("No field error", !errors.hasFieldErrors("myFloat")); + assertTrue("Correct float property", tb.getMyFloat() == null); + assertTrue("Correct float value", "".equals(errors.getFieldValue("myFloat"))); + } + + public void testCustomNumberEditorWithoutAllowEmpty() throws Exception { + final NumberFormat nf = NumberFormat.getNumberInstance(Locale.GERMAN); + + TestController mc = new TestController() { + protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) { + binder.registerCustomEditor(Float.class, new CustomNumberEditor(Float.class, nf, false)); + } + }; + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("myFloat", "5,1"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("No field error", !errors.hasFieldErrors("myFloat")); + assertTrue("Correct float property", (new Float(5.1)).equals(tb.getMyFloat())); + assertTrue("Correct float value", "5,1".equals(errors.getFieldValue("myFloat"))); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("myFloat", ""); + response = new MockHttpServletResponse(); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + errors = (Errors) mv.getModel().get("errors"); + assertTrue("Has field error", errors.hasFieldErrors("myFloat")); + assertTrue("Correct float property", tb.getMyFloat() != null); + assertTrue("Correct float value", errors.getFieldValue("myFloat") != null); + } + + public void testResetEmptyStringField() throws Exception { + TestController mc = new TestController(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_name", "visible"); + request.addParameter("name", "test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("Correct name property", "test".equals(tb.getName())); + assertTrue("Correct name value", "test".equals(errors.getFieldValue("name"))); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_name", "visible"); + request.addParameter("_someNonExistingField", "visible"); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + errors = (Errors) mv.getModel().get("errors"); + assertTrue("Correct name property", tb.getName() == null); + assertTrue("Correct name value", errors.getFieldValue("name") == null); + } + + public void testResetEmptyBooleanField() throws Exception { + TestController mc = new TestController(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_postProcessed", "visible"); + request.addParameter("postProcessed", "true"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("Correct postProcessed property", tb.isPostProcessed()); + assertTrue("Correct postProcessed value", Boolean.TRUE.equals(errors.getFieldValue("postProcessed"))); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_postProcessed", "visible"); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + errors = (Errors) mv.getModel().get("errors"); + assertTrue("Correct postProcessed property", !tb.isPostProcessed()); + assertTrue("Correct postProcessed value", Boolean.FALSE.equals(errors.getFieldValue("postProcessed"))); + } + + public void testResetEmptyStringArrayField() throws Exception { + TestController mc = new TestController(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_stringArray", "visible"); + request.addParameter("stringArray", "value1"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + assertTrue("Correct stringArray property", + tb.getStringArray() != null && "value1".equals(tb.getStringArray()[0])); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_stringArray", "visible"); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + assertTrue("Correct stringArray property", tb.getStringArray() != null && tb.getStringArray().length == 0); + } + + public void testResetEmptyFieldsTurnedOff() throws Exception { + TestController mc = new TestController() { + protected Object getCommand(HttpServletRequest request) throws Exception { + return new TestBean("original", 99); + } + protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) { + binder.setFieldMarkerPrefix(null); + } + }; + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_name", "visible"); + request.addParameter("name", "test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + TestBean tb = (TestBean) mv.getModel().get("command"); + Errors errors = (Errors) mv.getModel().get("errors"); + assertTrue("Correct name property", "test".equals(tb.getName())); + assertTrue("Correct name value", "test".equals(errors.getFieldValue("name"))); + + request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("_name", "true"); + mv = mc.handleRequest(request, response); + tb = (TestBean) mv.getModel().get("command"); + errors = (Errors) mv.getModel().get("errors"); + assertTrue("Correct name property", "original".equals(tb.getName())); + assertTrue("Correct name value", "original".equals(errors.getFieldValue("name"))); + } + + + private static class TestController extends AbstractCommandController { + + private TestController() { + super(TestBean.class, "person"); + } + + protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) { + Map m = new HashMap(); + assertTrue("Command not null", command != null); + assertTrue("errors not null", errors != null); + m.put("errors", errors); + m.put("command", command); + return new ModelAndView(request.getServletPath(), m); + } + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/ControllerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/ControllerTests.java new file mode 100644 index 00000000000..d54fc6ab3e1 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/ControllerTests.java @@ -0,0 +1,216 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc; + +import java.util.Properties; + +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.util.WebUtils; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class ControllerTests extends TestCase { + + public void testParameterizableViewController() throws Exception { + String viewName = "viewName"; + ParameterizableViewController pvc = new ParameterizableViewController(); + pvc.setViewName(viewName); + pvc.initApplicationContext(); + // We don't care about the params. + ModelAndView mv = pvc.handleRequest(new MockHttpServletRequest("GET", "foo.html"), null); + assertTrue("model has no data", mv.getModel().size() == 0); + assertTrue("model has correct viewname", mv.getViewName().equals(viewName)); + assertTrue("getViewName matches", pvc.getViewName().equals(viewName)); + } + + public void testParameterizableViewControllerWithPropertyNotSet() { + ParameterizableViewController pvc = new ParameterizableViewController(); + try { + pvc.initApplicationContext(); + fail("should require viewName property to be set"); + } + catch (IllegalArgumentException ex){ + // expected + assertTrue("meaningful exception message", ex.getMessage().indexOf("viewName") != -1); + } + } + + public void testServletForwardingController() throws Exception { + ServletForwardingController sfc = new ServletForwardingController(); + sfc.setServletName("action"); + doTestServletForwardingController(sfc, false); + } + + public void testServletForwardingControllerWithInclude() throws Exception { + ServletForwardingController sfc = new ServletForwardingController(); + sfc.setServletName("action"); + doTestServletForwardingController(sfc, true); + } + + public void testServletForwardingControllerWithBeanName() throws Exception { + ServletForwardingController sfc = new ServletForwardingController(); + sfc.setBeanName("action"); + doTestServletForwardingController(sfc, false); + } + + private void doTestServletForwardingController(ServletForwardingController sfc, boolean include) + throws Exception { + + MockControl requestControl = MockControl.createControl(HttpServletRequest.class); + HttpServletRequest request = (HttpServletRequest) requestControl.getMock(); + MockControl responseControl = MockControl.createControl(HttpServletResponse.class); + HttpServletResponse response = (HttpServletResponse) responseControl.getMock(); + MockControl contextControl = MockControl.createControl(ServletContext.class); + ServletContext context = (ServletContext) contextControl.getMock(); + MockControl dispatcherControl = MockControl.createControl(RequestDispatcher.class); + RequestDispatcher dispatcher = (RequestDispatcher) dispatcherControl.getMock(); + + request.getMethod(); + requestControl.setReturnValue("GET", 1); + context.getNamedDispatcher("action"); + contextControl.setReturnValue(dispatcher, 1); + if (include) { + request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE); + requestControl.setReturnValue("somePath", 1); + dispatcher.include(request, response); + dispatcherControl.setVoidCallable(1); + } + else { + request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE); + requestControl.setReturnValue(null, 1); + dispatcher.forward(request, response); + dispatcherControl.setVoidCallable(1); + } + requestControl.replay(); + contextControl.replay(); + dispatcherControl.replay(); + + StaticWebApplicationContext sac = new StaticWebApplicationContext(); + sac.setServletContext(context); + sfc.setApplicationContext(sac); + assertNull(sfc.handleRequest(request, response)); + + requestControl.verify(); + contextControl.verify(); + dispatcherControl.verify(); + } + + public void testServletWrappingController() throws Exception { + HttpServletRequest request = new MockHttpServletRequest("GET", "/somePath"); + HttpServletResponse response = new MockHttpServletResponse(); + + ServletWrappingController swc = new ServletWrappingController(); + swc.setServletClass(TestServlet.class); + swc.setServletName("action"); + Properties props = new Properties(); + props.setProperty("config", "myValue"); + swc.setInitParameters(props); + + swc.afterPropertiesSet(); + assertNotNull(TestServlet.config); + assertEquals("action", TestServlet.config.getServletName()); + assertEquals("myValue", TestServlet.config.getInitParameter("config")); + assertNull(TestServlet.request); + assertFalse(TestServlet.destroyed); + + assertNull(swc.handleRequest(request, response)); + assertEquals(request, TestServlet.request); + assertEquals(response, TestServlet.response); + assertFalse(TestServlet.destroyed); + + swc.destroy(); + assertTrue(TestServlet.destroyed); + } + + public void testServletWrappingControllerWithBeanName() throws Exception { + HttpServletRequest request = new MockHttpServletRequest("GET", "/somePath"); + HttpServletResponse response = new MockHttpServletResponse(); + + ServletWrappingController swc = new ServletWrappingController(); + swc.setServletClass(TestServlet.class); + swc.setBeanName("action"); + + swc.afterPropertiesSet(); + assertNotNull(TestServlet.config); + assertEquals("action", TestServlet.config.getServletName()); + assertNull(TestServlet.request); + assertFalse(TestServlet.destroyed); + + assertNull(swc.handleRequest(request, response)); + assertEquals(request, TestServlet.request); + assertEquals(response, TestServlet.response); + assertFalse(TestServlet.destroyed); + + swc.destroy(); + assertTrue(TestServlet.destroyed); + } + + + public static class TestServlet implements Servlet { + + private static ServletConfig config; + private static ServletRequest request; + private static ServletResponse response; + private static boolean destroyed; + + public TestServlet() { + config = null; + request = null; + response = null; + destroyed = false; + } + + public void init(ServletConfig servletConfig) { + config = servletConfig; + } + + public ServletConfig getServletConfig() { + return config; + } + + public void service(ServletRequest servletRequest, ServletResponse servletResponse) { + request = servletRequest; + response = servletResponse; + } + + public String getServletInfo() { + return "TestServlet"; + } + + public void destroy() { + destroyed = true; + } + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/FormControllerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/FormControllerTests.java new file mode 100644 index 00000000000..dd735910802 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/FormControllerTests.java @@ -0,0 +1,646 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; + +import org.springframework.beans.IndexedTestBean; +import org.springframework.beans.TestBean; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; +import org.springframework.validation.BindException; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; +import org.springframework.validation.Validator; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class FormControllerTests extends TestCase { + + public void testReferenceDataOnForm() throws Exception { + String formView = "f"; + String successView = "s"; + + RefController mc = new RefController(); + mc.setFormView(formView); + mc.setCommandName("tb"); + mc.setSuccessView(successView); + mc.refDataCount = 0; + + HttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name", mv.getViewName().equals(formView)); + + assertTrue("refDataCount == 1", mc.refDataCount == 1); + + TestBean person = (TestBean) mv.getModel().get(mc.getCommandName()); + int[] numbers = (int[]) mv.getModel().get(mc.NUMBERS_ATT); + assertTrue("model is non null", person != null); + assertTrue("numbers is non null", numbers != null); + } + + public void testReferenceDataOnResubmit() throws Exception { + String formView = "f"; + String successView = "s"; + + RefController mc = new RefController(); + mc.setFormView(formView); + mc.setCommandName("tb"); + mc.setSuccessView(successView); + mc.refDataCount = 0; + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/welcome.html"); + request.addParameter("age", "23x"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name", mv.getViewName().equals(formView)); + assertTrue("has errors", mv.getModel().get(BindException.MODEL_KEY_PREFIX + mc.getCommandName()) != null); + + assertTrue("refDataCount == 1", mc.refDataCount == 1); + + TestBean person = (TestBean) mv.getModel().get(mc.getCommandName()); + int[] numbers = (int[]) mv.getModel().get(mc.NUMBERS_ATT); + assertTrue("model is non null", person != null); + assertTrue("numbers is non null", numbers != null); + } + + public void testForm() throws Exception { + String formView = "f"; + String successView = "s"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("name", "rod"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name", mv.getViewName().equals(formView)); + + TestBean person = (TestBean) mv.getModel().get(TestController.BEAN_NAME); + assertTrue("model is non null", person != null); + assertTrue("bean age default ok", person.getAge() == TestController.DEFAULT_AGE); + assertTrue("name not set", person.getName() == null); + } + + public void testBindOnNewForm() throws Exception { + String formView = "f"; + String successView = "s"; + final Integer someNumber = new Integer(12); + + TestController mc = new TestController() { + protected void onBindOnNewForm(HttpServletRequest request, Object command) throws Exception { + TestBean testBean = (TestBean)command; + testBean.setSomeNumber(new Integer(12)); + } + }; + mc.setFormView(formView); + mc.setSuccessView(successView); + mc.setBindOnNewForm(true); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + request.addParameter("name", "rod"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertEquals("returned correct view name", formView, mv.getViewName()); + + TestBean person = (TestBean) mv.getModel().get(TestController.BEAN_NAME); + assertNotNull("model is non null", person); + assertEquals("bean age default ok", person.getAge(), TestController.DEFAULT_AGE); + assertEquals("name set", "rod", person.getName()); + assertEquals("Property [someNumber] not set in onBindOnNewForm callback", someNumber, person.getSomeNumber()); + } + + public void testSubmitWithoutErrors() throws Exception { + String formView = "f"; + String successView = "s"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + + String name = "Rod"; + int age = 32; + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/welcome.html"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + + assertEquals("returned correct view name", successView, mv.getViewName()); + TestBean person = (TestBean) mv.getModel().get(TestController.BEAN_NAME); + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + TestController.BEAN_NAME); + assertTrue("model is non null", person != null); + assertTrue("errors is non null", errors != null); + assertTrue("bean name bound ok", person.getName().equals(name)); + assertTrue("bean age bound ok", person.getAge() == age); + } + + public void testSubmitWithoutValidation() throws Exception { + String formView = "f"; + String successView = "s"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + + String name = "Rod"; + int age = 32; + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/welcome.html"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + request.addParameter("formChange", "true"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + + assertEquals("returned correct view name", formView, mv.getViewName()); + TestBean person = (TestBean) mv.getModel().get(TestController.BEAN_NAME); + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + TestController.BEAN_NAME); + assertTrue("model is non null", person != null); + assertTrue("errors is non null", errors != null); + assertTrue("bean name bound ok", person.getName().equals(name)); + assertTrue("bean age bound ok", person.getAge() == age); + } + + public void testSubmitWithCustomOnSubmit() throws Exception { + String formView = "f"; + + TestControllerWithCustomOnSubmit mc = new TestControllerWithCustomOnSubmit(); + mc.setFormView(formView); + + String name = "Rod"; + int age = 32; + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/welcome.html"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertEquals("returned correct view name", "mySuccess", mv.getViewName()); + assertTrue("no model", mv.getModel().isEmpty()); + } + + public void testSubmitPassedByValidator() throws Exception { + String formView = "f"; + String successView = "s"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + mc.setValidator(new TestValidator()); + + String name = "Roderick Johnson"; + int age = 32; + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/welcome.html"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name: expected '" + successView + "', not '" + mv.getViewName() + "'", + mv.getViewName().equals(successView)); + + TestBean person = (TestBean) mv.getModel().get(TestController.BEAN_NAME); + assertTrue("model is non null", person != null); + assertTrue("bean name bound ok", person.getName().equals(name)); + assertTrue("bean age bound ok", person.getAge() == age); + } + + public void testSubmit1Mismatch() throws Exception { + String formView = "fred"; + String successView = "tony"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + + String name = "Rod"; + String age = "xxx"; + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo.html"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name: expected '" + formView + "', not '" + mv.getViewName() + "'", + mv.getViewName().equals(formView)); + + TestBean person = (TestBean) mv.getModel().get(mc.getCommandName()); + assertTrue("model is non null", person != null); + assertTrue("bean name bound ok", person.getName().equals(name)); + assertTrue("bean age is default", person.getAge() == TestController.DEFAULT_AGE); + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + mc.getCommandName()); + assertTrue("errors returned in model", errors != null); + assertTrue("One error", errors.getErrorCount() == 1); + FieldError fe = errors.getFieldError("age"); + assertTrue("Saved invalid value", fe.getRejectedValue().equals(age)); + assertTrue("Correct field", fe.getField().equals("age")); + } + + public void testSubmit1Mismatch1Invalidated() throws Exception { + String formView = "fred"; + String successView = "tony"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + mc.setValidators(new Validator[] {new TestValidator(), new TestValidator2()}); + + String name = "Rod"; + // will be rejected + String age = "xxx"; + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo.html"); + request.addParameter("name", name); + request.addParameter("age", "" + age); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name: expected '" + formView + "', not '" + mv.getViewName() + "'", + mv.getViewName().equals(formView)); + + TestBean person = (TestBean) mv.getModel().get(TestController.BEAN_NAME); + assertTrue("model is non null", person != null); + + // yes, but it was rejected after binding by the validator + assertTrue("bean name bound ok", person.getName().equals(name)); + assertTrue("bean age is default", person.getAge() == TestController.DEFAULT_AGE); + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + mc.getCommandName()); + assertTrue("errors returned in model", errors != null); + assertTrue("3 errors", errors.getErrorCount() == 3); + FieldError fe = errors.getFieldError("age"); + assertTrue("Saved invalid value", fe.getRejectedValue().equals(age)); + assertTrue("Correct field", fe.getField().equals("age")); + + // raised by first validator + fe = errors.getFieldError("name"); + assertTrue("Saved invalid value", fe.getRejectedValue().equals(name)); + assertTrue("Correct field", fe.getField().equals("name")); + assertTrue("Correct validation code: expected '" +TestValidator.TOOSHORT + "', not '" + + fe.getCode() + "'", fe.getCode().equals(TestValidator.TOOSHORT)); + + // raised by second validator + ObjectError oe = errors.getGlobalError(); + assertEquals("test", oe.getCode()); + assertEquals("testmessage", oe.getDefaultMessage()); + } + + public void testSessionController() throws Exception { + String formView = "f"; + String successView = "s"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + mc.setSessionForm(true); + + // first request: GET form + HttpServletRequest request1 = new MockHttpServletRequest("GET", "/welcome.html"); + HttpServletResponse response1 = new MockHttpServletResponse(); + ModelAndView mv1 = mc.handleRequest(request1, response1); + assertTrue("returned correct view name", mv1.getViewName().equals(formView)); + TestBean person = (TestBean) mv1.getModel().get(TestController.BEAN_NAME); + assertTrue("model is non null", person != null); + assertTrue("Bean age default ok", person.getAge() == TestController.DEFAULT_AGE); + + // second request, using same session: POST submit + MockHttpServletRequest request2 = new MockHttpServletRequest("POST", "/welcome.html"); + request2.setSession(request1.getSession(false)); + HttpServletResponse response2 = new MockHttpServletResponse(); + ModelAndView mv2 = mc.handleRequest(request2, response2); + assertTrue("returned correct view name", mv2.getViewName().equals(successView)); + TestBean person2 = (TestBean) mv2.getModel().get(TestController.BEAN_NAME); + assertTrue("model is same object", person == person2); + } + + public void testDefaultInvalidSubmit() throws Exception { + String formView = "f"; + String successView = "s"; + + TestController mc = new TestController(); + mc.setFormView(formView); + mc.setSuccessView(successView); + mc.setSessionForm(true); + + // invalid request: POST submit + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/welcome.html"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name", mv.getViewName().equals(successView)); + TestBean person = (TestBean) mv.getModel().get(TestController.BEAN_NAME); + assertTrue("model is non null", person != null); + } + + public void testSpecialInvalidSubmit() throws Exception { + String formView = "f"; + String successView = "s"; + + TestController mc = new TestController() { + protected ModelAndView handleInvalidSubmit(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + throw new ServletException("invalid submit"); + } + }; + mc.setFormView(formView); + mc.setSuccessView(successView); + mc.setSessionForm(true); + + // invalid request: POST submit + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/welcome.html"); + HttpServletResponse response = new MockHttpServletResponse(); + try { + mc.handleRequest(request, response); + fail("Should have thrown ServletException"); + } + catch (ServletException ex) { + // expected + } + } + + public void testSubmitWithIndexedProperties() throws Exception { + String formView = "fred"; + String successView = "tony"; + + SimpleFormController mc = new SimpleFormController(); + mc.setCommandClass(IndexedTestBean.class); + mc.setFormView(formView); + mc.setSuccessView(successView); + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo.html"); + request.addParameter("array[0].name", "name3"); + request.addParameter("array[1].age", "name2"); + request.addParameter("list[0].name", "name1"); + request.addParameter("list[1].age", "name0"); + request.addParameter("list[2]", "listobj"); + request.addParameter("map[key1]", "mapobj1"); + request.addParameter("map[key3]", "mapobj2"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name: expected '" + formView + "', not '" + mv.getViewName() + "'", + mv.getViewName().equals(formView)); + + IndexedTestBean bean = (IndexedTestBean) mv.getModel().get(mc.getCommandName()); + assertTrue("model is non null", bean != null); + assertEquals("name3", bean.getArray()[0].getName()); + assertEquals("name1", ((TestBean) bean.getList().get(0)).getName()); + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + mc.getCommandName()); + assertTrue("errors returned in model", errors != null); + assertTrue("2 errors", errors.getErrorCount() == 2); + FieldError fe1 = errors.getFieldError("array[1].age"); + assertTrue("Saved invalid value", fe1.getRejectedValue().equals("name2")); + assertTrue("Correct field", fe1.getField().equals("array[1].age")); + FieldError fe2 = errors.getFieldError("list[1].age"); + assertTrue("Saved invalid value", fe2.getRejectedValue().equals("name0")); + assertTrue("Correct field", fe2.getField().equals("list[1].age")); + + assertEquals("listobj", bean.getList().get(2)); + assertEquals("mapobj1", bean.getMap().get("key1")); + assertEquals("mapobj2", bean.getMap().get("key3")); + } + + public void testFormChangeRequest() throws Exception { + String formView = "fred"; + String successView = "tony"; + final Float myFloat = new Float("123.45"); + + TestController mc = new TestController() { + protected boolean isFormChangeRequest(HttpServletRequest request) { + return (request.getParameter("formChange") != null); + } + + protected void onFormChange(HttpServletRequest request, HttpServletResponse response, Object command) { + assertNotNull("Command should not be null", command); + assertEquals("Incorrect command class", TestBean.class, command.getClass()); + ((TestBean)command).setMyFloat(myFloat); + } + }; + mc.setFormView(formView); + mc.setSuccessView(successView); + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo.html"); + request.addParameter("name", "Rod"); + request.addParameter("age", "99"); + request.addParameter("formChange", "true"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("returned correct view name: expected '" + formView + "', not '" + mv.getViewName() + "'", + mv.getViewName().equals(formView)); + + TestBean person = (TestBean) mv.getModel().get(mc.getCommandName()); + assertTrue("model is non null", person != null); + assertTrue("bean name bound ok", person.getName().equals("Rod")); + assertTrue("bean age is 99", person.getAge() == 99); + assertEquals("Command property myFloat not updated in onFormChange", myFloat, person.getMyFloat()); + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + mc.getCommandName()); + assertTrue("errors returned in model", errors != null); + assertTrue("No errors", errors.getErrorCount() == 0); + } + + public void testFormBindingOfNestedBooleans() throws Exception { + BooleanBindingFormController controller = new BooleanBindingFormController(); + controller.setCommandClass(ListForm.class); + MockHttpServletRequest req = new MockHttpServletRequest("POST", "/myurl"); + MockHttpServletResponse res = new MockHttpServletResponse(); + req.addParameter("oks[0].ok", "true"); + ModelAndView mav = controller.handleRequest(req, res); + ListForm form = (ListForm) mav.getModelMap().get("command"); + Boolean ok = ((Ok) form.getOks().get(0)).getOk(); + assertNotNull(ok); + } + + public void testFormControllerInWebApplicationContext() { + StaticWebApplicationContext ctx = new StaticWebApplicationContext(); + ctx.setServletContext(new MockServletContext()); + RefController mc = new RefController(); + mc.setApplicationContext(ctx); + try { + mc.invokeWebSpecificStuff(); + } + catch (IllegalStateException ex) { + fail("Shouldn't have thrown exception: " + ex.getMessage()); + } + } + + public void testFormControllerInNonWebApplicationContext() { + StaticApplicationContext ctx = new StaticApplicationContext(); + RefController mc = new RefController(); + mc.setApplicationContext(ctx); + try { + mc.invokeWebSpecificStuff(); + fail("Should have thrown IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + + + private static class TestValidator implements Validator { + + public static String TOOSHORT = "tooshort"; + + public boolean supports(Class clazz) { return true; } + + public void validate(Object obj, Errors errors) { + TestBean tb = (TestBean) obj; + if (tb.getName() == null || "".equals(tb.getName())) + errors.rejectValue("name", "needname", null, "need name"); + else if (tb.getName().length() < 5) + errors.rejectValue("name", TOOSHORT, null, "need full name"); + } + } + + + private static class TestValidator2 implements Validator { + + public static String TOOSHORT = "tooshort"; + + public boolean supports(Class clazz) { return true; } + + public void validate(Object obj, Errors errors) { + errors.reject("test", "testmessage"); + } + } + + + private static class TestController extends SimpleFormController { + + public static String BEAN_NAME = "person"; + + public static int DEFAULT_AGE = 52; + + public TestController() { + setCommandClass(TestBean.class); + setCommandName(BEAN_NAME); + } + + protected Object formBackingObject(HttpServletRequest request) throws ServletException { + TestBean person = new TestBean(); + person.setAge(DEFAULT_AGE); + return person; + } + + protected boolean isFormChangeRequest(HttpServletRequest request) { + return (request.getParameter("formChange") != null); + } + } + + + private static class TestControllerWithCustomOnSubmit extends TestController { + + protected ModelAndView onSubmit(Object command) throws Exception { + return new ModelAndView("mySuccess"); + } + } + + + private static class RefController extends SimpleFormController { + + final String NUMBERS_ATT = "NUMBERS"; + + static final int[] NUMBERS = { 1, 2, 3, 4 }; + + int refDataCount; + + public RefController() { + setCommandClass(TestBean.class); + } + + protected Map referenceData(HttpServletRequest request) { + ++refDataCount; + Map m = new HashMap(); + m.put(NUMBERS_ATT, NUMBERS); + return m; + } + + public void invokeWebSpecificStuff() { + getTempDir(); + } + } + + + public static class BooleanBindingFormController extends AbstractFormController { + + protected ModelAndView processFormSubmission + (HttpServletRequest req, HttpServletResponse resp, Object command, BindException errors) throws Exception { + ModelAndView mav = new ModelAndView(); + mav.addObject("command", command); + return mav; + } + + protected ModelAndView showForm( + HttpServletRequest req, HttpServletResponse resp, BindException err) throws Exception { + return null; + } + } + + + public static class Ok { + + private Boolean ok; + + public Boolean getOk () { + return ok; + } + + public void setOk(Boolean ok) { + this.ok = ok; + } + } + + + public static class ListForm { + + private List oks = new ArrayList(); + + public ListForm () { + for (int index = 0; index < 5; index++) { + Ok ok = new Ok(); + oks.add(ok); + } + } + + public List getOks() { + return oks; + } + + public void setOks(List oks) { + this.oks = oks; + } + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/UrlFilenameViewControllerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/UrlFilenameViewControllerTests.java new file mode 100644 index 00000000000..ed45d97f820 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/UrlFilenameViewControllerTests.java @@ -0,0 +1,158 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.PathMatcher; +import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Juergen Hoeller + * @author Rick Evans + * @since 14.09.2005 + */ +public class UrlFilenameViewControllerTests extends TestCase { + + private PathMatcher pathMatcher = new AntPathMatcher(); + + + public void testWithPlainFilename() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("index", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testWithFilenamePlusExtension() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("index", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testWithPrefixAndSuffix() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + ctrl.setPrefix("mypre_"); + ctrl.setSuffix("_mysuf"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("mypre_index_mysuf", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testWithPrefix() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + ctrl.setPrefix("mypre_"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("mypre_index", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testWithSuffix() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + ctrl.setSuffix("_mysuf"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("index_mysuf", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testMultiLevel() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/docs/cvs/commit.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("docs/cvs/commit", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testMultiLevelWithMapping() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/docs/cvs/commit.html"); + exposePathInMapping(request, "/docs/**"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("cvs/commit", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testMultiLevelMappingWithFallback() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/docs/cvs/commit.html"); + exposePathInMapping(request, "/docs/cvs/commit.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("docs/cvs/commit", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testWithContextMapping() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/docs/cvs/commit.html"); + request.setContextPath("/myapp"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("docs/cvs/commit", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + public void testSettingPrefixToNullCausesEmptyStringToBeUsed() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + ctrl.setPrefix(null); + assertNotNull("When setPrefix(..) is called with a null argument, the empty string value must be used instead.", ctrl.getPrefix()); + assertEquals("When setPrefix(..) is called with a null argument, the empty string value must be used instead.", "", ctrl.getPrefix()); + } + + public void testSettingSuffixToNullCausesEmptyStringToBeUsed() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + ctrl.setSuffix(null); + assertNotNull("When setSuffix(..) is called with a null argument, the empty string value must be used instead.", ctrl.getSuffix()); + assertEquals("When setSuffix(..) is called with a null argument, the empty string value must be used instead.", "", ctrl.getSuffix()); + } + + /** + * This is the expected behavior, and it now has a test to prove it. + * http://opensource.atlassian.com/projects/spring/browse/SPR-2789 + */ + public void testNestedPathisUsedAsViewName_InBreakingChangeFromSpring12Line() throws Exception { + UrlFilenameViewController ctrl = new UrlFilenameViewController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/products/view.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = ctrl.handleRequest(request, response); + assertEquals("products/view", mv.getViewName()); + assertTrue(mv.getModel().isEmpty()); + } + + private void exposePathInMapping(MockHttpServletRequest request, String mapping) { + String pathInMapping = this.pathMatcher.extractPathWithinPattern(mapping, request.getRequestURI()); + request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathInMapping); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/WebContentInterceptorTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/WebContentInterceptorTests.java new file mode 100644 index 00000000000..a77b80a3606 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/WebContentInterceptorTests.java @@ -0,0 +1,133 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc; + +import java.util.List; +import java.util.Properties; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.web.servlet.support.WebContentGenerator; + +import org.junit.Before; +import org.junit.Test; +import org.junit.Assert; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; +import static org.junit.Assert.*; +import static org.junit.Assert.*; +import static org.junit.Assert.*; + +/** + * @author Rick Evans + */ +public class WebContentInterceptorTests { + + private MockHttpServletRequest request; + + private MockHttpServletResponse response; + + + @Before + public void setUp() throws Exception { + request = new MockHttpServletRequest(); + request.setMethod(WebContentGenerator.METHOD_GET); + response = new MockHttpServletResponse(); + } + + + @Test + public void preHandleSetsCacheSecondsOnMatchingRequest() throws Exception { + WebContentInterceptor interceptor = new WebContentInterceptor(); + interceptor.setCacheSeconds(10); + + interceptor.preHandle(request, response, null); + + List expiresHeaders = response.getHeaders("Expires"); + assertNotNull("'Expires' header not set (must be) : null", expiresHeaders); + assertTrue("'Expires' header not set (must be) : empty", expiresHeaders.size() > 0); + List cacheControlHeaders = response.getHeaders("Cache-Control"); + assertNotNull("'Cache-Control' header not set (must be) : null", cacheControlHeaders); + assertTrue("'Cache-Control' header not set (must be) : empty", cacheControlHeaders.size() > 0); + } + + @Test + public void preHandleSetsCacheSecondsOnMatchingRequestWithCustomCacheMapping() throws Exception { + Properties mappings = new Properties(); + mappings.setProperty("**/*handle.vm", "-1"); + + WebContentInterceptor interceptor = new WebContentInterceptor(); + interceptor.setCacheSeconds(10); + interceptor.setCacheMappings(mappings); + + request.setRequestURI("http://localhost:7070/example/adminhandle.vm"); + interceptor.preHandle(request, response, null); + + List expiresHeaders = response.getHeaders("Expires"); + assertSame("'Expires' header set (must not be) : empty", 0, expiresHeaders.size()); + List cacheControlHeaders = response.getHeaders("Cache-Control"); + assertSame("'Cache-Control' header set (must not be) : empty", 0, cacheControlHeaders.size()); + + request.setRequestURI("http://localhost:7070/example/bingo.html"); + interceptor.preHandle(request, response, null); + + expiresHeaders = response.getHeaders("Expires"); + assertNotNull("'Expires' header not set (must be) : null", expiresHeaders); + assertTrue("'Expires' header not set (must be) : empty", expiresHeaders.size() > 0); + cacheControlHeaders = response.getHeaders("Cache-Control"); + assertNotNull("'Cache-Control' header not set (must be) : null", cacheControlHeaders); + assertTrue("'Cache-Control' header not set (must be) : empty", cacheControlHeaders.size() > 0); + } + + @Test + public void preHandleSetsCacheSecondsOnMatchingRequestWithNoCaching() throws Exception { + WebContentInterceptor interceptor = new WebContentInterceptor(); + interceptor.setCacheSeconds(0); + + interceptor.preHandle(request, response, null); + + List expiresHeaders = response.getHeaders("Expires"); + assertNotNull("'Expires' header not set (must be) : null", expiresHeaders); + assertTrue("'Expires' header not set (must be) : empty", expiresHeaders.size() > 0); + List cacheControlHeaders = response.getHeaders("Cache-Control"); + assertNotNull("'Cache-Control' header not set (must be) : null", cacheControlHeaders); + assertTrue("'Cache-Control' header not set (must be) : empty", cacheControlHeaders.size() > 0); + } + + @Test + public void preHandleSetsCacheSecondsOnMatchingRequestWithCachingDisabled() throws Exception { + WebContentInterceptor interceptor = new WebContentInterceptor(); + interceptor.setCacheSeconds(-1); + + interceptor.preHandle(request, response, null); + + List expiresHeaders = response.getHeaders("Expires"); + assertSame("'Expires' header set (must not be) : empty", 0, expiresHeaders.size()); + List cacheControlHeaders = response.getHeaders("Cache-Control"); + assertSame("'Cache-Control' header set (must not be) : empty", 0, cacheControlHeaders.size()); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetPathMatcherToNull() throws Exception { + WebContentInterceptor interceptor = new WebContentInterceptor(); + interceptor.setPathMatcher(null); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/WizardFormControllerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/WizardFormControllerTests.java new file mode 100644 index 00000000000..b8e35f02671 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/WizardFormControllerTests.java @@ -0,0 +1,428 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc; + +import java.io.IOException; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import junit.framework.TestCase; + +import org.springframework.beans.TestBean; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.util.ObjectUtils; +import org.springframework.validation.BindException; +import org.springframework.validation.Errors; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Juergen Hoeller + * @since 29.04.2003 + */ +public class WizardFormControllerTests extends TestCase { + + public void testNoDirtyPageChange() throws Exception { + AbstractWizardFormController wizard = new TestWizardController(); + wizard.setAllowDirtyBack(false); + wizard.setAllowDirtyForward(false); + wizard.setPageAttribute("currentPage"); + + assertTrue(wizard.getFormSessionAttributeName() != wizard.getPageSessionAttributeName()); + HttpSession session = performRequest(wizard, null, null, 0, null, 0, "currentPage"); + + Properties params = new Properties(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, null, 0, null, 0, "currentPage"); + // not allowed to go to 1 + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_PAGE, "0"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty("name", "myname"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1.x", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1.y", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty("date", "not a date"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1.y", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // not allowed to go to 0 + + params.clear(); + params.setProperty("age", "32"); + params.setProperty(AbstractWizardFormController.PARAM_PAGE, "1"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 0, "myname", 32, "currentPage"); + // age set -> now allowed to go to 0 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, -1, "myname", 32, null); + } + + public void testCustomSessionAttributes() throws Exception { + AbstractWizardFormController wizard = new TestWizardController() { + protected String getFormSessionAttributeName() { + return "myFormAttr"; + } + protected String getPageSessionAttributeName() { + return "myPageAttr"; + } + }; + wizard.setAllowDirtyBack(false); + wizard.setAllowDirtyForward(false); + wizard.setPageAttribute("currentPage"); + + HttpSession session = performRequest(wizard, null, null, 0, null, 0, "currentPage"); + assertTrue(session.getAttribute("myFormAttr") instanceof TestBean); + assertEquals(new Integer(0), session.getAttribute("myPageAttr")); + + Properties params = new Properties(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, null, 0, null, 0, "currentPage"); + // not allowed to go to 1 + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_PAGE, "0"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty("age", "32"); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, -1, "myname", 32, "currentPage"); + } + + public void testCustomRequestDependentSessionAttributes() throws Exception { + AbstractWizardFormController wizard = new TestWizardController() { + protected String getFormSessionAttributeName(HttpServletRequest request) { + return "myFormAttr" + request.getParameter("formAttr"); + } + protected String getPageSessionAttributeName(HttpServletRequest request) { + return "myPageAttr" + request.getParameter("pageAttr"); + } + }; + wizard.setAllowDirtyBack(false); + wizard.setAllowDirtyForward(false); + wizard.setPageAttribute("currentPage"); + + HttpSession session = performRequest(wizard, null, null, 0, null, 0, "currentPage"); + assertTrue(session.getAttribute("myFormAttr1") instanceof TestBean); + assertEquals(new Integer(0), session.getAttribute("myPageAttr2")); + + Properties params = new Properties(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, null, 0, null, 0, "currentPage"); + // not allowed to go to 1 + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_PAGE, "0"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty("age", "32"); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, -1, "myname", 32, "currentPage"); + } + + public void testDirtyBack() throws Exception { + AbstractWizardFormController wizard = new TestWizardController(); + wizard.setAllowDirtyBack(true); + wizard.setAllowDirtyForward(false); + HttpSession session = performRequest(wizard, null, null, 0, null, 0, null); + + Properties params = new Properties(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 0, null, 0, null); + // not allowed to go to 1 + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 1, "myname", 0, null); + // name set -> now allowed to go to 1 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 0, "myname", 0, null); + // dirty back -> allowed to go to 0 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, 1, "myname", 0, null); + // finish while dirty -> show dirty page (1) + + params.clear(); + params.setProperty("age", "32"); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, -1, "myname", 32, null); + // age set -> now allowed to finish + } + + public void testDirtyForward() throws Exception { + AbstractWizardFormController wizard = new TestWizardController(); + wizard.setAllowDirtyBack(false); + wizard.setAllowDirtyForward(true); + HttpSession session = performRequest(wizard, null, null, 0, null, 0, null); + + Properties params = new Properties(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 1, null, 0, null); + // dirty forward -> allowed to go to 1 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 1, null, 0, null); + // not allowed to go to 0 + + params.clear(); + params.setProperty("age", "32"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 0, null, 32, null); + // age set -> now allowed to go to 0 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, 0, null, 32, null); + // finish while dirty -> show dirty page (0) + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_FINISH + ".x", "value"); + performRequest(wizard, session, params, -1, "myname", 32, null); + // name set -> now allowed to finish + } + + public void testSubmitWithoutValidation() throws Exception { + AbstractWizardFormController wizard = new TestWizardController(); + wizard.setAllowDirtyBack(false); + wizard.setAllowDirtyForward(false); + HttpSession session = performRequest(wizard, null, null, 0, null, 0, null); + + Properties params = new Properties(); + params.setProperty("formChange", "true"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 1, null, 0, null); + // no validation -> allowed to go to 1 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 1, null, 0, null); + // not allowed to go to 0 + + params.clear(); + params.setProperty("age", "32"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 0, null, 32, null); + // age set -> now allowed to go to 0 + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, 0, null, 32, null); + // finish while dirty -> show dirty page (0) + + params.clear(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_FINISH + ".x", "value"); + performRequest(wizard, session, params, -1, "myname", 32, null); + // name set -> now allowed to finish + } + + public void testCancel() throws Exception { + AbstractWizardFormController wizard = new TestWizardController(); + HttpSession session = performRequest(wizard, null, null, 0, null, 0, null); + Properties params = new Properties(); + params.setProperty(AbstractWizardFormController.PARAM_CANCEL, "value"); + performRequest(wizard, session, params, -2, null, 0, null); + + assertTrue(session.getAttribute(wizard.getFormSessionAttributeName()) == null); + assertTrue(session.getAttribute(wizard.getPageSessionAttributeName()) == null); + + session = performRequest(wizard, null, null, 0, null, 0, null); + params = new Properties(); + params.setProperty(AbstractWizardFormController.PARAM_CANCEL + ".y", "value"); + performRequest(wizard, session, params, -2, null, 0, null); + } + + public void testInvalidSubmit() throws Exception { + AbstractWizardFormController wizard = new TestWizardController(); + wizard.setAllowDirtyBack(false); + wizard.setAllowDirtyForward(false); + wizard.setPageAttribute("currentPage"); + HttpSession session = performRequest(wizard, null, null, 0, null, 0, "currentPage"); + + Properties params = new Properties(); + params.setProperty("name", "myname"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "1", "value"); + performRequest(wizard, session, params, 1, "myname", 0, "currentPage"); + + params.clear(); + params.setProperty("age", "32"); + params.setProperty(AbstractWizardFormController.PARAM_TARGET + "0", "value"); + performRequest(wizard, session, params, 0, "myname", 32, "currentPage"); + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, -1, "myname", 32, null); + + params.clear(); + params.setProperty(AbstractWizardFormController.PARAM_FINISH, "value"); + performRequest(wizard, session, params, 0, null, 0, "currentPage"); + // returned to initial page of new wizard form + } + + private HttpSession performRequest( + AbstractWizardFormController wizard, HttpSession session, Properties params, + int target, String name, int age, String pageAttr) throws Exception { + + MockHttpServletRequest request = new MockHttpServletRequest((params != null ? "POST" : "GET"), "/wizard"); + request.addParameter("formAttr", "1"); + request.addParameter("pageAttr", "2"); + if (params != null) { + for (Iterator it = params.keySet().iterator(); it.hasNext();) { + String param = (String) it.next(); + request.addParameter(param, params.getProperty(param)); + } + } + request.setSession(session); + request.setAttribute("target", new Integer(target)); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = wizard.handleRequest(request, response); + if (target >= 0) { + assertTrue("Page " + target + " returned", ("page" + target).equals(mv.getViewName())); + if (pageAttr != null) { + assertTrue("Page attribute set", (new Integer(target)).equals(mv.getModel().get(pageAttr))); + assertTrue("Correct model size", mv.getModel().size() == 3); + } + else { + assertTrue("Correct model size", mv.getModel().size() == 2); + } + assertTrue( + request.getSession().getAttribute(wizard.getFormSessionAttributeName(request)) instanceof TestBean); + assertEquals(new Integer(target), + request.getSession().getAttribute(wizard.getPageSessionAttributeName(request))); + } + else if (target == -1) { + assertTrue("Success target returned", "success".equals(mv.getViewName())); + assertTrue("Correct model size", mv.getModel().size() == 1); + assertTrue(request.getSession().getAttribute(wizard.getFormSessionAttributeName(request)) == null); + assertTrue(request.getSession().getAttribute(wizard.getPageSessionAttributeName(request)) == null); + } + else if (target == -2) { + assertTrue("Cancel view returned", "cancel".equals(mv.getViewName())); + assertTrue("Correct model size", mv.getModel().size() == 1); + assertTrue(request.getSession().getAttribute(wizard.getFormSessionAttributeName(request)) == null); + assertTrue(request.getSession().getAttribute(wizard.getPageSessionAttributeName(request)) == null); + } + TestBean tb = (TestBean) mv.getModel().get("tb"); + assertTrue("Has model", tb != null); + assertTrue("Name is " + name, ObjectUtils.nullSafeEquals(name, tb.getName())); + assertTrue("Age is " + age, tb.getAge() == age); + Errors errors = (Errors) mv.getModel().get(BindException.MODEL_KEY_PREFIX + "tb"); + if (params != null && params.containsKey("formChange")) { + assertNotNull(errors); + assertFalse(errors.hasErrors()); + } + return request.getSession(false); + } + + + private static class TestWizardController extends AbstractWizardFormController { + + public TestWizardController() { + setCommandClass(TestBean.class); + setCommandName("tb"); + setPages(new String[] {"page0", "page1"}); + } + + protected Map referenceData(HttpServletRequest request, int page) throws Exception { + assertEquals(new Integer(page), request.getAttribute("target")); + return super.referenceData(request, page); + } + + protected boolean suppressValidation(HttpServletRequest request, Object command) { + return (request.getParameter("formChange") != null); + } + + protected void validatePage(Object command, Errors errors, int page) { + TestBean tb = (TestBean) command; + switch (page) { + case 0: + if (tb.getName() == null) { + errors.rejectValue("name", "NAME_REQUIRED", null, "Name is required"); + } + break; + case 1: + if (tb.getAge() == 0) { + errors.rejectValue("age", "AGE_REQUIRED", null, "Age is required"); + } + break; + default: + throw new IllegalArgumentException("Invalid page number"); + } + } + + protected ModelAndView processFinish( + HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) + throws ServletException, IOException { + assertTrue(getCurrentPage(request) == 0 || getCurrentPage(request) == 1); + return new ModelAndView("success", getCommandName(), command); + } + + protected ModelAndView processCancel( + HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) + throws ServletException, IOException { + assertTrue(getCurrentPage(request) == 0 || getCurrentPage(request) == 1); + return new ModelAndView("cancel", getCommandName(), command); + } + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/AdminController.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/AdminController.java new file mode 100644 index 00000000000..41ed4c6e8ef --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/AdminController.java @@ -0,0 +1,27 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.annotation; + +import org.springframework.stereotype.Controller; + +/** + * @author Juergen Hoeller + */ +@Controller +public class AdminController { + +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/BuyForm.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/BuyForm.java new file mode 100644 index 00000000000..8a7a6c602ab --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/BuyForm.java @@ -0,0 +1,27 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.annotation; + +import org.springframework.stereotype.Controller; + +/** + * @author Juergen Hoeller + */ +@Controller +public class BuyForm { + +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ControllerClassNameHandlerMappingTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ControllerClassNameHandlerMappingTests.java new file mode 100644 index 00000000000..ec3bd838dd3 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ControllerClassNameHandlerMappingTests.java @@ -0,0 +1,117 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.annotation; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.XmlWebApplicationContext; +import org.springframework.web.servlet.HandlerExecutionChain; +import org.springframework.web.servlet.HandlerMapping; + +/** + * @author Juergen Hoeller + */ +public class ControllerClassNameHandlerMappingTests extends TestCase { + + public static final String LOCATION = "/org/springframework/web/servlet/mvc/annotation/class-mapping.xml"; + + private XmlWebApplicationContext wac; + + private HandlerMapping hm; + + private HandlerMapping hm2; + + private HandlerMapping hm3; + + private HandlerMapping hm4; + + public void setUp() throws Exception { + MockServletContext sc = new MockServletContext(""); + this.wac = new XmlWebApplicationContext(); + this.wac.setServletContext(sc); + this.wac.setConfigLocations(new String[] {LOCATION}); + this.wac.refresh(); + this.hm = (HandlerMapping) this.wac.getBean("mapping"); + this.hm2 = (HandlerMapping) this.wac.getBean("mapping2"); + this.hm3 = (HandlerMapping) this.wac.getBean("mapping3"); + this.hm4 = (HandlerMapping) this.wac.getBean("mapping4"); + } + + public void testIndexUri() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("index"), chain.getHandler()); + + request = new MockHttpServletRequest("GET", "/index/product"); + chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("index"), chain.getHandler()); + } + + public void testMapSimpleUri() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + + request = new MockHttpServletRequest("GET", "/welcome/product"); + chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithContextPath() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/welcome"); + request.setContextPath("/myapp"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithoutControllerSuffix() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/buyform"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("buy"), chain.getHandler()); + + request = new MockHttpServletRequest("GET", "/buyform/product"); + chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("buy"), chain.getHandler()); + } + + public void testWithBasePackage() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/mvc/annotation/welcome"); + HandlerExecutionChain chain = this.hm2.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithBasePackageAndCaseSensitive() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/mvc/annotation/buyForm"); + HandlerExecutionChain chain = this.hm2.getHandler(request); + assertEquals(this.wac.getBean("buy"), chain.getHandler()); + } + + public void testWithFullBasePackage() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/welcome"); + HandlerExecutionChain chain = this.hm3.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithRootAsBasePackage() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/org/springframework/web/servlet/mvc/annotation/welcome"); + HandlerExecutionChain chain = this.hm4.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/IndexController.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/IndexController.java new file mode 100644 index 00000000000..ebbfbdc33fe --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/IndexController.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.annotation; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Juergen Hoeller + */ +@Controller +public class IndexController { + + @RequestMapping + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { + return new ModelAndView("indexView"); + } + +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/MethodNameDispatchingController.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/MethodNameDispatchingController.java new file mode 100644 index 00000000000..e8f97c1f220 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/MethodNameDispatchingController.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.annotation; + +import java.io.IOException; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * @author Juergen Hoeller + */ +@Controller +@RequestMapping("/*.do") +public class MethodNameDispatchingController { + + @RequestMapping + public void myHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myView"); + } + + @RequestMapping + public void myOtherHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myOtherView"); + } + + @RequestMapping(method = RequestMethod.POST) + public void myLangHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myLangView"); + } + + @RequestMapping(method = RequestMethod.POST) + public void mySurpriseHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("mySurpriseView"); + } + +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java new file mode 100644 index 00000000000..78fb102d3ac --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java @@ -0,0 +1,1137 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.annotation; + +import java.io.IOException; +import java.io.Writer; +import java.security.Principal; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; +import org.springframework.aop.interceptor.SimpleTraceInterceptor; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.ITestBean; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.context.annotation.AnnotationConfigUtils; +import org.springframework.core.MethodParameter; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletConfig; +import org.springframework.mock.web.MockServletContext; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ExtendedModelMap; +import org.springframework.ui.Model; +import org.springframework.ui.ModelMap; +import org.springframework.validation.BindingResult; +import org.springframework.validation.Errors; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.support.WebArgumentResolver; +import org.springframework.web.bind.support.WebBindingInitializer; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.context.support.GenericWebApplicationContext; +import org.springframework.web.servlet.DispatcherServlet; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.View; +import org.springframework.web.servlet.ViewResolver; +import org.springframework.web.servlet.mvc.AbstractController; +import org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver; +import org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping; +import org.springframework.web.servlet.view.InternalResourceViewResolver; +import org.springframework.web.util.NestedServletException; + +/** + * @author Juergen Hoeller + * @author Sam Brannen + * @since 2.5 + */ +public class ServletAnnotationControllerTests extends TestCase { + + public void testStandardHandleMethod() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyController.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("test", response.getContentAsString()); + } + + public void testProxiedStandardHandleMethod() throws Exception { + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyController.class)); + DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator(); + autoProxyCreator.setBeanFactory(wac.getBeanFactory()); + wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator); + wac.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor())); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("test", response.getContentAsString()); + } + + public void testEmptyParameterListHandleMethod() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(EmptyParameterListHandlerMethodController.class)); + RootBeanDefinition vrDef = new RootBeanDefinition(InternalResourceViewResolver.class); + vrDef.getPropertyValues().addPropertyValue("suffix", ".jsp"); + wac.registerBeanDefinition("viewResolver", vrDef); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/emptyParameterListHandler"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + EmptyParameterListHandlerMethodController.called = false; + servlet.service(request, response); + assertTrue(EmptyParameterListHandlerMethodController.called); + assertEquals("", response.getContentAsString()); + } + + public void testAdaptedHandleMethods() throws Exception { + doTestAdaptedHandleMethods(MyAdaptedController.class); + } + + public void testAdaptedHandleMethods2() throws Exception { + doTestAdaptedHandleMethods(MyAdaptedController2.class); + } + + public void testAdaptedHandleMethods3() throws Exception { + doTestAdaptedHandleMethods(MyAdaptedController3.class); + } + + private void doTestAdaptedHandleMethods(final Class controllerClass) throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(controllerClass)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath1.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + request.addParameter("param1", "value1"); + request.addParameter("param2", "2"); + servlet.service(request, response); + assertEquals("test", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myPath2.do"); + request.addParameter("param1", "value1"); + request.addParameter("param2", "2"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("test-value1-2", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myPath3.do"); + request.addParameter("param1", "value1"); + request.addParameter("param2", "2"); + request.addParameter("name", "name1"); + request.addParameter("age", "2"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("test-name1-2", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myPath4.do"); + request.addParameter("param1", "value1"); + request.addParameter("param2", "2"); + request.addParameter("name", "name1"); + request.addParameter("age", "value2"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("test-name1-typeMismatch", response.getContentAsString()); + } + + public void testFormController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyFormController.class)); + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + request.addParameter("name", "name1"); + request.addParameter("age", "value2"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString()); + } + + public void testModelFormController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyModelFormController.class)); + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + request.addParameter("name", "name1"); + request.addParameter("age", "value2"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString()); + } + + public void testProxiedFormController() throws Exception { + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyFormController.class)); + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); + DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator(); + autoProxyCreator.setBeanFactory(wac.getBeanFactory()); + wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator); + wac.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor())); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + request.addParameter("name", "name1"); + request.addParameter("age", "value2"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString()); + } + + public void testCommandProvidingFormController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyCommandProvidingFormController.class)); + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); + RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class); + adapterDef.getPropertyValues().addPropertyValue("webBindingInitializer", new MyWebBindingInitializer()); + wac.registerBeanDefinition("handlerAdapter", adapterDef); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + request.addParameter("defaultName", "myDefaultName"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + } + + public void testTypedCommandProvidingFormController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyTypedCommandProvidingFormController.class)); + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); + RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class); + adapterDef.getPropertyValues().addPropertyValue("webBindingInitializer", new MyWebBindingInitializer()); + adapterDef.getPropertyValues().addPropertyValue("customArgumentResolver", new MySpecialArgumentResolver()); + wac.registerBeanDefinition("handlerAdapter", adapterDef); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + request.addParameter("defaultName", "10"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-Integer:10-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myOtherPath.do"); + request.addParameter("defaultName", "10"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-myName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myThirdPath.do"); + request.addParameter("defaultName", "10"); + request.addParameter("age", "100"); + request.addParameter("date", "2007-10-02"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-special-99-special-99", response.getContentAsString()); + } + + public void testBinderInitializingCommandProvidingFormController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyBinderInitializingCommandProvidingFormController.class)); + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + request.addParameter("defaultName", "myDefaultName"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + } + + public void testSpecificBinderInitializingCommandProvidingFormController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MySpecificBinderInitializingCommandProvidingFormController.class)); + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); + request.addParameter("defaultName", "myDefaultName"); + request.addParameter("age", "value2"); + request.addParameter("date", "2007-10-02"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); + } + + public void testParameterDispatchingController() throws Exception { + final MockServletContext servletContext = new MockServletContext(); + final MockServletConfig servletConfig = new MockServletConfig(servletContext); + + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.setServletContext(servletContext); + RootBeanDefinition bd = new RootBeanDefinition(MyParameterDispatchingController.class); + bd.setScope(WebApplicationContext.SCOPE_REQUEST); + wac.registerBeanDefinition("controller", bd); + AnnotationConfigUtils.registerAnnotationConfigProcessors(wac); + wac.getBeanFactory().registerResolvableDependency(ServletConfig.class, servletConfig); + wac.refresh(); + return wac; + } + }; + servlet.init(servletConfig); + + MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + HttpSession session = request.getSession(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + assertSame(servletContext, request.getAttribute("servletContext")); + assertSame(servletConfig, request.getAttribute("servletConfig")); + assertSame(session, request.getAttribute("session")); + assertSame(request, request.getAttribute("request")); + + request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); + response = new MockHttpServletResponse(); + session = request.getSession(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + assertSame(servletContext, request.getAttribute("servletContext")); + assertSame(servletConfig, request.getAttribute("servletConfig")); + assertSame(session, request.getAttribute("session")); + assertSame(request, request.getAttribute("request")); + + request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); + request.addParameter("view", "other"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myOtherView", response.getContentAsString()); + + request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); + request.addParameter("view", "my"); + request.addParameter("lang", "de"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myLangView", response.getContentAsString()); + + request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); + request.addParameter("surprise", "!"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("mySurpriseView", response.getContentAsString()); + } + + public void testMethodNameDispatchingController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MethodNameDispatchingController.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myHandle.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myOtherHandle.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myOtherView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/myLangHandle.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myLangView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/mySurpriseHandle.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("mySurpriseView", response.getContentAsString()); + } + + public void testMethodNameDispatchingControllerWithSuffix() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MethodNameDispatchingController.class)); + InternalPathMethodNameResolver methodNameResolver = new InternalPathMethodNameResolver(); + methodNameResolver.setSuffix("Handle"); + RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class); + adapterDef.getPropertyValues().addPropertyValue("methodNameResolver", methodNameResolver); + wac.registerBeanDefinition("handlerAdapter", adapterDef); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/my.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myOther.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myOtherView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/myLang.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myLangView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/mySurprise.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("mySurpriseView", response.getContentAsString()); + } + + public void testControllerClassNamePlusMethodNameDispatchingController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + RootBeanDefinition mapping = new RootBeanDefinition(ControllerClassNameHandlerMapping.class); + mapping.getPropertyValues().addPropertyValue("excludedPackages", null); + wac.registerBeanDefinition("handlerMapping", mapping); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MethodNameDispatchingController.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/methodnamedispatching/myHandle"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/methodnamedispatching/myOtherHandle.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myOtherView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/methodnamedispatching/myLangHandle.x"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myLangView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/methodnamedispatching/mySurpriseHandle.y"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("mySurpriseView", response.getContentAsString()); + } + + public void testPostMethodNameDispatchingController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyPostMethodNameDispatchingController.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myHandle.do"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals(405, response.getStatus()); + + request = new MockHttpServletRequest("POST", "/myUnknownHandle.do"); + request.addParameter("myParam", "myValue"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals(404, response.getStatus()); + + request = new MockHttpServletRequest("POST", "/myHandle.do"); + request.addParameter("myParam", "myValue"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/myOtherHandle.do"); + request.addParameter("myParam", "myValue"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myOtherView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/myLangHandle.do"); + request.addParameter("myParam", "myValue"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myLangView", response.getContentAsString()); + + request = new MockHttpServletRequest("POST", "/mySurpriseHandle.do"); + request.addParameter("myParam", "myValue"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("mySurpriseView", response.getContentAsString()); + } + + public void testRelativePathDispatchingController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyRelativePathDispatchingController.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myApp/myHandle"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myApp/myOther"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myOtherView", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myApp/myLang"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myLangView", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/myApp/surprise.do"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("mySurpriseView", response.getContentAsString()); + } + + public void testNullCommandController() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(MyNullCommandController.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath"); + request.setUserPrincipal(new OtherPrincipal()); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("myView", response.getContentAsString()); + } + + public void testEquivalentMappingsWithSameMethodName() throws Exception { + @SuppressWarnings("serial") + DispatcherServlet servlet = new DispatcherServlet() { + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + GenericWebApplicationContext wac = new GenericWebApplicationContext(); + wac.registerBeanDefinition("controller", new RootBeanDefinition(ChildController.class)); + wac.refresh(); + return wac; + } + }; + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/child/test"); + request.addParameter("childId", "100"); + MockHttpServletResponse response = new MockHttpServletResponse(); + try { + servlet.service(request, response); + } + catch (NestedServletException ex) { + assertTrue(ex.getCause() instanceof IllegalStateException); + assertTrue(ex.getCause().getMessage().contains("doGet")); + } + } + + + @RequestMapping("/myPath.do") + private static class MyController extends AbstractController { + + protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { + response.getWriter().write("test"); + return null; + } + } + + + private static class BaseController { + + @RequestMapping(method = RequestMethod.GET) + public void myPath2(HttpServletResponse response) throws IOException { + response.getWriter().write("test"); + } + } + + + @Controller + private static class MyAdaptedController { + + @RequestMapping("/myPath1.do") + public void myHandle(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.getWriter().write("test"); + } + + @RequestMapping("/myPath2.do") + public void myHandle(@RequestParam("param1") String p1, @RequestParam("param2") int p2, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + p1 + "-" + p2); + } + + @RequestMapping("/myPath3") + public void myHandle(TestBean tb, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge()); + } + + @RequestMapping("/myPath4.do") + public void myHandle(TestBean tb, Errors errors, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode()); + } + } + + + @Controller + @RequestMapping("/*.do") + private static class MyAdaptedController2 { + + @RequestMapping + public void myHandle(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.getWriter().write("test"); + } + + @RequestMapping("/myPath2.do") + public void myHandle(@RequestParam("param1") String p1, int param2, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + p1 + "-" + param2); + } + + @RequestMapping("/myPath3") + public void myHandle(TestBean tb, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge()); + } + + @RequestMapping("/myPath4.*") + public void myHandle(TestBean tb, Errors errors, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode()); + } + } + + + @Controller + private static class MyAdaptedControllerBase { + + @RequestMapping("/myPath2.do") + public void myHandle(@RequestParam("param1") T p1, int param2, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + p1 + "-" + param2); + } + + @InitBinder + public void initBinder(@RequestParam("param1") T p1, int param2) { + } + + @ModelAttribute + public void modelAttribute(@RequestParam("param1") T p1, int param2) { + } + } + + + @RequestMapping("/*.do") + private static class MyAdaptedController3 extends MyAdaptedControllerBase { + + @RequestMapping + public void myHandle(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.getWriter().write("test"); + } + + @Override + public void myHandle(@RequestParam("param1") String p1, int param2, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + p1 + "-" + param2); + } + + @RequestMapping("/myPath3") + public void myHandle(TestBean tb, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge()); + } + + @RequestMapping("/myPath4.*") + public void myHandle(TestBean tb, Errors errors, HttpServletResponse response) throws IOException { + response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode()); + } + + @InitBinder + public void initBinder(@RequestParam("param1") String p1, int param2) { + } + + @ModelAttribute + public void modelAttribute(@RequestParam("param1") String p1, int param2) { + } + } + + + @Controller + @RequestMapping(method = RequestMethod.GET) + private static class EmptyParameterListHandlerMethodController { + + static boolean called; + + @RequestMapping("/emptyParameterListHandler") + public void emptyParameterListHandler() { + EmptyParameterListHandlerMethodController.called = true; + } + + @RequestMapping("/nonEmptyParameterListHandler") + public void nonEmptyParameterListHandler(HttpServletResponse response) { + } + } + + + @Controller + public static class MyFormController { + + @ModelAttribute("testBeanList") + public List getTestBeans() { + List list = new LinkedList(); + list.add(new TestBean("tb1")); + list.add(new TestBean("tb2")); + return list; + } + + @RequestMapping("/myPath.do") + public String myHandle(@ModelAttribute("myCommand") TestBean tb, BindingResult errors, ModelMap model) { + if (!model.containsKey("myKey")) { + model.addAttribute("myKey", "myValue"); + } + return "myView"; + } + } + + + @Controller + public static class MyModelFormController { + + @ModelAttribute + public List getTestBeans() { + List list = new LinkedList(); + list.add(new TestBean("tb1")); + list.add(new TestBean("tb2")); + return list; + } + + @RequestMapping("/myPath.do") + public String myHandle(@ModelAttribute("myCommand") TestBean tb, BindingResult errors, Model model) { + if (!model.containsAttribute("myKey")) { + model.addAttribute("myKey", "myValue"); + } + return "myView"; + } + } + + + @Controller + private static class MyCommandProvidingFormController extends MyFormController { + + @SuppressWarnings("unused") + @ModelAttribute("myCommand") + private TestBean createTestBean( + @RequestParam T defaultName, Map model, @RequestParam Date date) { + model.put("myKey", "myOriginalValue"); + return new TestBean(defaultName.getClass().getSimpleName() + ":" + defaultName.toString()); + } + + @RequestMapping("/myPath.do") + public String myHandle(@ModelAttribute("myCommand") TestBean tb, BindingResult errors, ModelMap model) { + return super.myHandle(tb, errors, model); + } + + @RequestMapping("/myOtherPath.do") + public String myOtherHandle(TB tb, BindingResult errors, ExtendedModelMap model, MySpecialArg arg) { + TestBean tbReal = (TestBean) tb; + tbReal.setName("myName"); + assertTrue(model.get("ITestBean") instanceof DerivedTestBean); + assertNotNull(arg); + return super.myHandle(tbReal, errors, model); + } + + @RequestMapping("/myThirdPath.do") + public String myThirdHandle(TB tb, Model model) { + model.addAttribute("testBean", new TestBean("special", 99)); + return "myView"; + } + + @ModelAttribute + protected TB2 getModelAttr() { + return (TB2) new DerivedTestBean(); + } + } + + + private static class MySpecialArg { + + public MySpecialArg(String value) { + } + } + + + @Controller + private static class MyTypedCommandProvidingFormController + extends MyCommandProvidingFormController { + } + + + @Controller + private static class MyBinderInitializingCommandProvidingFormController extends MyCommandProvidingFormController { + + @SuppressWarnings("unused") + @InitBinder + private void initBinder(WebDataBinder binder) { + binder.initBeanPropertyAccess(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + dateFormat.setLenient(false); + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); + } + } + + + @Controller + private static class MySpecificBinderInitializingCommandProvidingFormController extends MyCommandProvidingFormController { + + @SuppressWarnings("unused") + @InitBinder({"myCommand", "date"}) + private void initBinder(WebDataBinder binder, String date, @RequestParam("date") String[] date2) { + assertEquals("2007-10-02", date); + assertEquals(1, date2.length); + assertEquals("2007-10-02", date2[0]); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + dateFormat.setLenient(false); + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); + } + } + + + private static class MyWebBindingInitializer implements WebBindingInitializer { + + public void initBinder(WebDataBinder binder, WebRequest request) { + assertNotNull(request.getLocale()); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + dateFormat.setLenient(false); + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); + } + } + + + private static class MySpecialArgumentResolver implements WebArgumentResolver { + + public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) { + if (methodParameter.getParameterType().equals(MySpecialArg.class)) { + return new MySpecialArg("myValue"); + } + return UNRESOLVED; + } + } + + + @Controller + @RequestMapping("/myPath.do") + private static class MyParameterDispatchingController { + + @Autowired + private ServletContext servletContext; + + @Autowired + private ServletConfig servletConfig; + + @Autowired + private HttpSession session; + + @Autowired + private HttpServletRequest request; + + @RequestMapping + public void myHandle(HttpServletResponse response, HttpServletRequest request) throws IOException { + if (this.servletContext == null || this.servletConfig == null || this.session == null || this.request == null) { + throw new IllegalStateException(); + } + response.getWriter().write("myView"); + request.setAttribute("servletContext", this.servletContext); + request.setAttribute("servletConfig", this.servletConfig); + request.setAttribute("session", this.session); + request.setAttribute("request", this.request); + } + + @RequestMapping(params = {"view", "!lang"}) + public void myOtherHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myOtherView"); + } + + @RequestMapping(method = RequestMethod.GET, params = {"view=my", "lang=de"}) + public void myLangHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myLangView"); + } + + @RequestMapping(method = {RequestMethod.POST, RequestMethod.GET}, params = "surprise") + public void mySurpriseHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("mySurpriseView"); + } + } + + + @Controller + @RequestMapping(value = "/*.do", method = RequestMethod.POST, params = "myParam=myValue") + private static class MyPostMethodNameDispatchingController extends MethodNameDispatchingController { + + } + + + @Controller + @RequestMapping("/myApp/*") + private static class MyRelativePathDispatchingController { + + @RequestMapping + public void myHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myView"); + } + + @RequestMapping("*Other") + public void myOtherHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myOtherView"); + } + + @RequestMapping("myLang") + public void myLangHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("myLangView"); + } + + @RequestMapping("surprise") + public void mySurpriseHandle(HttpServletResponse response) throws IOException { + response.getWriter().write("mySurpriseView"); + } + } + + + @Controller + private static class MyNullCommandController { + + @ModelAttribute + public TestBean getTestBean() { + return null; + } + + @ModelAttribute + public Principal getPrincipal() { + return new TestPrincipal(); + } + + @RequestMapping("/myPath") + public void handle(@ModelAttribute TestBean testBean, Errors errors, + @ModelAttribute TestPrincipal modelPrinc, OtherPrincipal requestPrinc, Writer writer) throws IOException { + assertNull(testBean); + assertNotNull(modelPrinc); + assertNotNull(requestPrinc); + assertFalse(errors.hasErrors()); + errors.reject("myCode"); + writer.write("myView"); + } + } + + + private static class TestPrincipal implements Principal { + + public String getName() { + return "test"; + } + } + + + private static class OtherPrincipal implements Principal { + + public String getName() { + return "other"; + } + } + + + private static class TestViewResolver implements ViewResolver { + + public View resolveViewName(final String viewName, Locale locale) throws Exception { + return new View() { + public String getContentType() { + return null; + } + @SuppressWarnings({"unchecked", "deprecation"}) + public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { + TestBean tb = (TestBean) model.get("testBean"); + if (tb == null) { + tb = (TestBean) model.get("myCommand"); + } + if (tb.getName().endsWith("myDefaultName")) { + assertTrue(tb.getDate().getYear() == 107); + } + Errors errors = (Errors) model.get(BindingResult.MODEL_KEY_PREFIX + "testBean"); + if (errors == null) { + errors = (Errors) model.get(BindingResult.MODEL_KEY_PREFIX + "myCommand"); + } + if (errors.hasFieldErrors("date")) { + throw new IllegalStateException(); + } + if (model.containsKey("ITestBean")) { + assertTrue(model.get(BindingResult.MODEL_KEY_PREFIX + "ITestBean") instanceof Errors); + } + List testBeans = (List) model.get("testBeanList"); + if (errors.hasFieldErrors("age")) { + response.getWriter().write(viewName + "-" + tb.getName() + "-" + errors.getFieldError("age").getCode() + + "-" + testBeans.get(0).getName() + "-" + model.get("myKey")); + } + else { + response.getWriter().write(viewName + "-" + tb.getName() + "-" + tb.getAge() + "-" + + errors.getFieldValue("name") + "-" + errors.getFieldValue("age")); + } + } + }; + } + } + + + public static class ParentController { + + @RequestMapping(method = RequestMethod.GET) + public void doGet(HttpServletRequest req, HttpServletResponse resp) { + } + } + + + @Controller + @RequestMapping("/child/test") + public static class ChildController extends ParentController { + + @RequestMapping(method = RequestMethod.GET) + public void doGet(HttpServletRequest req, HttpServletResponse resp, @RequestParam("childId") String id) { + } + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/WelcomeController.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/WelcomeController.java new file mode 100644 index 00000000000..25d532b54b5 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/WelcomeController.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.annotation; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Juergen Hoeller + */ +@Controller +public class WelcomeController { + + @RequestMapping + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { + return new ModelAndView("welcomeView"); + } + +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/AdminController.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/AdminController.java new file mode 100644 index 00000000000..650e201d0fc --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/AdminController.java @@ -0,0 +1,26 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.mapping; + +import org.springframework.web.servlet.mvc.multiaction.MultiActionController; + +/** + * @author Rob Harrop + */ +public class AdminController extends MultiActionController { + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/BuyForm.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/BuyForm.java new file mode 100644 index 00000000000..3f42bdd83af --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/BuyForm.java @@ -0,0 +1,26 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.mapping; + +import org.springframework.web.servlet.mvc.SimpleFormController; + +/** + * @author Rob Harrop + */ +public class BuyForm extends SimpleFormController { + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/Controller.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/Controller.java new file mode 100644 index 00000000000..307b6ab80d8 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/Controller.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.mapping; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Juergen Hoeller + */ +public class Controller implements org.springframework.web.servlet.mvc.Controller { + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { + return new ModelAndView("indexView"); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/ControllerBeanNameHandlerMappingTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/ControllerBeanNameHandlerMappingTests.java new file mode 100644 index 00000000000..5351f35b581 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/ControllerBeanNameHandlerMappingTests.java @@ -0,0 +1,78 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.mapping; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.XmlWebApplicationContext; +import org.springframework.web.servlet.HandlerExecutionChain; +import org.springframework.web.servlet.HandlerMapping; + +/** + * @author Juergen Hoeller + */ +public class ControllerBeanNameHandlerMappingTests extends TestCase { + + public static final String LOCATION = "/org/springframework/web/servlet/mvc/mapping/name-mapping.xml"; + + private XmlWebApplicationContext wac; + + private HandlerMapping hm; + + public void setUp() throws Exception { + MockServletContext sc = new MockServletContext(""); + this.wac = new XmlWebApplicationContext(); + this.wac.setServletContext(sc); + this.wac.setConfigLocations(new String[] {LOCATION}); + this.wac.refresh(); + this.hm = (HandlerMapping) this.wac.getBean("mapping"); + } + + public void testIndexUri() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("index"), chain.getHandler()); + } + + public void testMapSimpleUri() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithContextPath() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/welcome"); + request.setContextPath("/myapp"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithMultiActionControllerMapping() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/admin"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("admin"), chain.getHandler()); + } + + public void testWithoutControllerSuffix() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/buy"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("buy"), chain.getHandler()); + } + +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/ControllerClassNameHandlerMappingTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/ControllerClassNameHandlerMappingTests.java new file mode 100644 index 00000000000..e822f40f043 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/ControllerClassNameHandlerMappingTests.java @@ -0,0 +1,116 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.mapping; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.XmlWebApplicationContext; +import org.springframework.web.servlet.HandlerExecutionChain; +import org.springframework.web.servlet.HandlerMapping; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class ControllerClassNameHandlerMappingTests extends TestCase { + + public static final String LOCATION = "/org/springframework/web/servlet/mvc/mapping/class-mapping.xml"; + + private XmlWebApplicationContext wac; + + private HandlerMapping hm; + + private HandlerMapping hm2; + + private HandlerMapping hm3; + + private HandlerMapping hm4; + + public void setUp() throws Exception { + MockServletContext sc = new MockServletContext(""); + this.wac = new XmlWebApplicationContext(); + this.wac.setServletContext(sc); + this.wac.setConfigLocations(new String[] {LOCATION}); + this.wac.refresh(); + this.hm = (HandlerMapping) this.wac.getBean("mapping"); + this.hm2 = (HandlerMapping) this.wac.getBean("mapping2"); + this.hm3 = (HandlerMapping) this.wac.getBean("mapping3"); + this.hm4 = (HandlerMapping) this.wac.getBean("mapping4"); + } + + public void testIndexUri() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("index"), chain.getHandler()); + } + + public void testMapSimpleUri() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithContextPath() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/welcome"); + request.setContextPath("/myapp"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithMultiActionControllerMapping() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/admin/user"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("admin"), chain.getHandler()); + + request = new MockHttpServletRequest("GET", "/admin/product"); + chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("admin"), chain.getHandler()); + } + + public void testWithoutControllerSuffix() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/buyform"); + HandlerExecutionChain chain = this.hm.getHandler(request); + assertEquals(this.wac.getBean("buy"), chain.getHandler()); + } + + public void testWithBasePackage() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/mvc/mapping/welcome"); + HandlerExecutionChain chain = this.hm2.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithBasePackageAndCaseSensitive() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/mvc/mapping/buyForm"); + HandlerExecutionChain chain = this.hm2.getHandler(request); + assertEquals(this.wac.getBean("buy"), chain.getHandler()); + } + + public void testWithFullBasePackage() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/welcome"); + HandlerExecutionChain chain = this.hm3.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + + public void testWithRootAsBasePackage() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/org/springframework/web/servlet/mvc/mapping/welcome"); + HandlerExecutionChain chain = this.hm4.getHandler(request); + assertEquals(this.wac.getBean("welcome"), chain.getHandler()); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/WelcomeController.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/WelcomeController.java new file mode 100644 index 00000000000..5c36b0989d3 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/mapping/WelcomeController.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.mapping; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.Controller; + +/** + * @author Rob Harrop + */ +public class WelcomeController implements Controller { + + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { + return new ModelAndView("welcomeView"); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/multiaction/MultiActionControllerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/multiaction/MultiActionControllerTests.java new file mode 100644 index 00000000000..ddf7bd44517 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/multiaction/MultiActionControllerTests.java @@ -0,0 +1,720 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.mvc.multiaction; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import junit.framework.TestCase; + +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.TestBean; +import org.springframework.context.ApplicationContextException; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.web.HttpSessionRequiredException; +import org.springframework.web.bind.ServletRequestBindingException; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Colin Sampaleanu + * @author Rob Harrop + * @author Sam Brannen + */ +public class MultiActionControllerTests extends TestCase { + + public void testDefaultInternalPathMethodNameResolver() throws Exception { + doDefaultTestInternalPathMethodNameResolver("/foo.html", "foo"); + doDefaultTestInternalPathMethodNameResolver("/foo/bar.html", "bar"); + doDefaultTestInternalPathMethodNameResolver("/bugal.xyz", "bugal"); + doDefaultTestInternalPathMethodNameResolver("/x/y/z/q/foo.html", "foo"); + doDefaultTestInternalPathMethodNameResolver("qqq.q", "qqq"); + } + + private void doDefaultTestInternalPathMethodNameResolver(String in, String expected) throws Exception { + MultiActionController rc = new MultiActionController(); + HttpServletRequest request = new MockHttpServletRequest("GET", in); + String actual = rc.getMethodNameResolver().getHandlerMethodName(request); + assertEquals("Wrong method name resolved", expected, actual); + } + + public void testCustomizedInternalPathMethodNameResolver() throws Exception { + doTestCustomizedInternalPathMethodNameResolver("/foo.html", "my", null, "myfoo"); + doTestCustomizedInternalPathMethodNameResolver("/foo/bar.html", null, "Handler", "barHandler"); + doTestCustomizedInternalPathMethodNameResolver("/Bugal.xyz", "your", "Method", "yourBugalMethod"); + } + + private void doTestCustomizedInternalPathMethodNameResolver(String in, String prefix, String suffix, String expected) + throws Exception { + + MultiActionController rc = new MultiActionController(); + InternalPathMethodNameResolver resolver = new InternalPathMethodNameResolver(); + if (prefix != null) { + resolver.setPrefix(prefix); + } + if (suffix != null) { + resolver.setSuffix(suffix); + } + rc.setMethodNameResolver(resolver); + HttpServletRequest request = new MockHttpServletRequest("GET", in); + String actual = rc.getMethodNameResolver().getHandlerMethodName(request); + assertEquals("Wrong method name resolved", expected, actual); + } + + public void testParameterMethodNameResolver() throws NoSuchRequestHandlingMethodException { + ParameterMethodNameResolver mnr = new ParameterMethodNameResolver(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo.html"); + request.addParameter("action", "bar"); + assertEquals("bar", mnr.getHandlerMethodName(request)); + + request = new MockHttpServletRequest("GET", "/foo.html"); + try { + mnr.getHandlerMethodName(request); + fail("Should have thrown NoSuchRequestHandlingMethodException"); + } + catch (NoSuchRequestHandlingMethodException expected) { + } + + request = new MockHttpServletRequest("GET", "/foo.html"); + request.addParameter("action", ""); + try { + mnr.getHandlerMethodName(request); + fail("Should have thrown NoSuchRequestHandlingMethodException"); + } + catch (NoSuchRequestHandlingMethodException expected) { + } + + request = new MockHttpServletRequest("GET", "/foo.html"); + request.addParameter("action", " "); + try { + mnr.getHandlerMethodName(request); + fail("Should have thrown NoSuchRequestHandlingMethodException"); + } + catch (NoSuchRequestHandlingMethodException expected) { + } + } + + public void testParameterMethodNameResolverWithCustomParamName() throws NoSuchRequestHandlingMethodException { + ParameterMethodNameResolver mnr = new ParameterMethodNameResolver(); + mnr.setParamName("myparam"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo.html"); + request.addParameter("myparam", "bar"); + assertEquals("bar", mnr.getHandlerMethodName(request)); + } + + public void testParameterMethodNameResolverWithParamNames() throws NoSuchRequestHandlingMethodException { + ParameterMethodNameResolver resolver = new ParameterMethodNameResolver(); + resolver.setDefaultMethodName("default"); + resolver.setMethodParamNames(new String[] { "hello", "spring", "colin" }); + Properties logicalMappings = new Properties(); + logicalMappings.setProperty("hello", "goodbye"); + logicalMappings.setProperty("nina", "colin"); + resolver.setLogicalMappings(logicalMappings); + + // verify default handler + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("this will not match anything", "whatever"); + assertEquals("default", resolver.getHandlerMethodName(request)); + + // verify first resolution strategy (action=method) + request = new MockHttpServletRequest(); + request.addParameter("action", "reset"); + assertEquals("reset", resolver.getHandlerMethodName(request)); + // this one also tests logical mapping + request = new MockHttpServletRequest(); + request.addParameter("action", "nina"); + assertEquals("colin", resolver.getHandlerMethodName(request)); + + // now validate second resolution strategy (parameter existence) + // this also tests logical mapping + request = new MockHttpServletRequest(); + request.addParameter("hello", "whatever"); + assertEquals("goodbye", resolver.getHandlerMethodName(request)); + + request = new MockHttpServletRequest(); + request.addParameter("spring", "whatever"); + assertEquals("spring", resolver.getHandlerMethodName(request)); + + request = new MockHttpServletRequest(); + request.addParameter("hello", "whatever"); + request.addParameter("spring", "whatever"); + assertEquals("goodbye", resolver.getHandlerMethodName(request)); + + request = new MockHttpServletRequest(); + request.addParameter("colin", "whatever"); + request.addParameter("spring", "whatever"); + assertEquals("spring", resolver.getHandlerMethodName(request)); + + // validate image button handling + request = new MockHttpServletRequest(); + request.addParameter("spring.x", "whatever"); + assertEquals("spring", resolver.getHandlerMethodName(request)); + + request = new MockHttpServletRequest(); + request.addParameter("hello.x", "whatever"); + request.addParameter("spring", "whatever"); + assertEquals("goodbye", resolver.getHandlerMethodName(request)); + } + + public void testParameterMethodNameResolverWithDefaultMethodName() throws NoSuchRequestHandlingMethodException { + ParameterMethodNameResolver mnr = new ParameterMethodNameResolver(); + mnr.setDefaultMethodName("foo"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo.html"); + request.addParameter("action", "bar"); + assertEquals("bar", mnr.getHandlerMethodName(request)); + request = new MockHttpServletRequest("GET", "/foo.html"); + assertEquals("foo", mnr.getHandlerMethodName(request)); + } + + public void testInvokesCorrectMethod() throws Exception { + TestMaController mc = new TestMaController(); + HttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + HttpServletResponse response = new MockHttpServletResponse(); + Properties p = new Properties(); + p.put("/welcome.html", "welcome"); + PropertiesMethodNameResolver mnr = new PropertiesMethodNameResolver(); + mnr.setMappings(p); + mc.setMethodNameResolver(mnr); + + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("Invoked welcome method", mc.wasInvoked("welcome")); + assertTrue("view name is welcome", mv.getViewName().equals("welcome")); + assertTrue("Only one method invoked", mc.getInvokedMethods() == 1); + + mc = new TestMaController(); + request = new MockHttpServletRequest("GET", "/subdir/test.html"); + response = new MockHttpServletResponse(); + mv = mc.handleRequest(request, response); + assertTrue("Invoked test method", mc.wasInvoked("test")); + assertTrue("view name is subdir_test", mv.getViewName().equals("test")); + assertTrue("Only one method invoked", mc.getInvokedMethods() == 1); + } + + public void testPathMatching() throws Exception { + TestMaController mc = new TestMaController(); + HttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + HttpServletResponse response = new MockHttpServletResponse(); + Properties p = new Properties(); + p.put("/welc*.html", "welcome"); + PropertiesMethodNameResolver mn = new PropertiesMethodNameResolver(); + mn.setMappings(p); + mc.setMethodNameResolver(mn); + + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("Invoked welcome method", mc.wasInvoked("welcome")); + assertTrue("view name is welcome", mv.getViewName().equals("welcome")); + assertTrue("Only one method invoked", mc.getInvokedMethods() == 1); + + mc = new TestMaController(); + mc.setMethodNameResolver(mn); + request = new MockHttpServletRequest("GET", "/nomatch"); + response = new MockHttpServletResponse(); + try { + mv = mc.handleRequest(request, response); + } + catch (Exception expected) { + } + assertFalse("Not invoking welcome method", mc.wasInvoked("welcome")); + assertTrue("No method invoked", mc.getInvokedMethods() == 0); + } + + public void testInvokesCorrectMethodOnDelegate() throws Exception { + MultiActionController mac = new MultiActionController(); + TestDelegate d = new TestDelegate(); + mac.setDelegate(d); + HttpServletRequest request = new MockHttpServletRequest("GET", "/test.html"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mac.handleRequest(request, response); + assertTrue("view name is test", mv.getViewName().equals("test")); + assertTrue("Delegate was invoked", d.invoked); + } + + public void testInvokesCorrectMethodWithSession() throws Exception { + TestMaController mc = new TestMaController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/inSession.html"); + request.setSession(new MockHttpSession(null)); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("Invoked inSession method", mc.wasInvoked("inSession")); + assertTrue("view name is welcome", mv.getViewName().equals("inSession")); + assertTrue("Only one method invoked", mc.getInvokedMethods() == 1); + + request = new MockHttpServletRequest("GET", "/inSession.html"); + response = new MockHttpServletResponse(); + try { + + mc.handleRequest(request, response); + fail("Must have rejected request without session"); + } + catch (ServletException expected) { + } + } + + public void testInvokesCommandMethodNoSession() throws Exception { + TestMaController mc = new TestMaController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/commandNoSession.html"); + request.addParameter("name", "rod"); + request.addParameter("age", "32"); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("Invoked commandNoSession method", mc.wasInvoked("commandNoSession")); + assertTrue("view name is commandNoSession", mv.getViewName().equals("commandNoSession")); + assertTrue("Only one method invoked", mc.getInvokedMethods() == 1); + } + + public void testInvokesCommandMethodWithSession() throws Exception { + TestMaController mc = new TestMaController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/commandInSession.html"); + request.addParameter("name", "rod"); + request.addParameter("age", "32"); + + request.setSession(new MockHttpSession(null)); + HttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mv = mc.handleRequest(request, response); + assertTrue("Invoked commandInSession method", mc.wasInvoked("commandInSession")); + assertTrue("view name is commandInSession", mv.getViewName().equals("commandInSession")); + assertTrue("Only one method invoked", mc.getInvokedMethods() == 1); + + request = new MockHttpServletRequest("GET", "/commandInSession.html"); + response = new MockHttpServletResponse(); + try { + + mc.handleRequest(request, response); + fail("Must have rejected request without session"); + } + catch (ServletException expected) { + } + } + + public void testSessionRequiredCatchable() throws Exception { + HttpServletRequest request = new MockHttpServletRequest("GET", "/testSession.html"); + HttpServletResponse response = new MockHttpServletResponse(); + TestMaController contr = new TestSessionRequiredController(); + try { + contr.handleRequest(request, response); + fail("Should have thrown exception"); + } + catch (HttpSessionRequiredException ex) { + // assertTrue("session required", ex.equals(t)); + } + request = new MockHttpServletRequest("GET", "/testSession.html"); + response = new MockHttpServletResponse(); + contr = new TestSessionRequiredExceptionHandler(); + ModelAndView mv = contr.handleRequest(request, response); + assertTrue("Name is ok", mv.getViewName().equals("handle(SRE)")); + } + + private void testExceptionNoHandler(TestMaController mc, Throwable t) throws Exception { + HttpServletRequest request = new MockHttpServletRequest("GET", "/testException.html"); + request.setAttribute(TestMaController.THROWABLE_ATT, t); + HttpServletResponse response = new MockHttpServletResponse(); + try { + mc.handleRequest(request, response); + fail("Should have thrown exception"); + } + catch (Throwable ex) { + assertTrue(ex.equals(t)); + } + } + + private void testExceptionNoHandler(Throwable t) throws Exception { + testExceptionNoHandler(new TestMaController(), t); + } + + public void testExceptionNoHandler() throws Exception { + testExceptionNoHandler(new Exception()); + + // must go straight through + testExceptionNoHandler(new ServletException()); + + // subclass of servlet exception + testExceptionNoHandler(new ServletRequestBindingException("foo")); + testExceptionNoHandler(new RuntimeException()); + testExceptionNoHandler(new Error()); + } + + public void testLastModifiedDefault() throws Exception { + TestMaController mc = new TestMaController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + long lastMod = mc.getLastModified(request); + assertTrue("default last modified is -1", lastMod == -1L); + } + + public void testLastModifiedWithMethod() throws Exception { + LastModController mc = new LastModController(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + long lastMod = mc.getLastModified(request); + assertTrue("last modified with method is > -1", lastMod == mc.getLastModified(request)); + } + + private ModelAndView testHandlerCaughtException(TestMaController mc, Throwable t) throws Exception { + HttpServletRequest request = new MockHttpServletRequest("GET", "/testException.html"); + request.setAttribute(TestMaController.THROWABLE_ATT, t); + HttpServletResponse response = new MockHttpServletResponse(); + return mc.handleRequest(request, response); + } + + public void testHandlerCaughtException() throws Exception { + TestMaController mc = new TestExceptionHandler(); + ModelAndView mv = testHandlerCaughtException(mc, new Exception()); + assertNotNull("ModelAndView must not be null", mv); + assertTrue("mv name is handle(Exception)", "handle(Exception)".equals(mv.getViewName())); + assertTrue("Invoked correct method", mc.wasInvoked("handle(Exception)")); + + // WILL GET RUNTIME EXCEPTIONS TOO + testExceptionNoHandler(mc, new Error()); + + mc = new TestServletExceptionHandler(); + mv = testHandlerCaughtException(mc, new ServletException()); + assertTrue(mv.getViewName().equals("handle(ServletException)")); + assertTrue("Invoke correct method", mc.wasInvoked("handle(ServletException)")); + + mv = testHandlerCaughtException(mc, new ServletRequestBindingException("foo")); + assertTrue(mv.getViewName().equals("handle(ServletException)")); + assertTrue("Invoke correct method", mc.wasInvoked("handle(ServletException)")); + + // Check it doesn't affect unknown exceptions + testExceptionNoHandler(mc, new RuntimeException()); + testExceptionNoHandler(mc, new Error()); + testExceptionNoHandler(mc, new SQLException()); + testExceptionNoHandler(mc, new Exception()); + + mc = new TestRuntimeExceptionHandler(); + mv = testHandlerCaughtException(mc, new RuntimeException()); + assertTrue(mv.getViewName().equals("handle(RTE)")); + assertTrue("Invoke correct method", mc.wasInvoked("handle(RTE)")); + mv = testHandlerCaughtException(mc, new FatalBeanException(null, null)); + assertTrue(mv.getViewName().equals("handle(RTE)")); + assertTrue("Invoke correct method", mc.wasInvoked("handle(RTE)")); + + testExceptionNoHandler(mc, new SQLException()); + testExceptionNoHandler(mc, new Exception()); + } + + public void testHandlerReturnsMap() throws Exception { + Map model = new HashMap(); + model.put("message", "Hello World!"); + + MultiActionController mac = new ModelOnlyMultiActionController(model); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mav = mac.handleRequest(request, response); + + assertNotNull("ModelAndView cannot be null", mav); + assertFalse("ModelAndView should not have a view", mav.hasView()); + assertEquals(model, mav.getModel()); + } + + public void testExceptionHandlerReturnsMap() throws Exception { + Map model = new HashMap(); + + MultiActionController mac = new ModelOnlyMultiActionController(model); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mav = mac.handleRequest(request, response); + + assertNotNull("ModelAndView cannot be null", mav); + assertFalse("ModelAndView should not have a view", mav.hasView()); + assertTrue(model.containsKey("exception")); + } + + public void testCannotCallExceptionHandlerDirectly() throws Exception { + Map model = new HashMap(); + + MultiActionController mac = new ModelOnlyMultiActionController(model); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/handleIllegalStateException.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mav = mac.handleRequest(request, response); + assertEquals(HttpServletResponse.SC_NOT_FOUND, response.getStatus()); + } + + public void testHandlerReturnsVoid() throws Exception { + MultiActionController mac = new VoidMultiActionController(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mav = mac.handleRequest(request, response); + + assertNull("ModelAndView must be null", mav); + } + + public void testExceptionHandlerReturnsVoid() throws Exception { + MultiActionController mac = new VoidMultiActionController(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mav = mac.handleRequest(request, response); + + assertNull("ModelAndView must be null", mav); + assertEquals("exception", response.getContentAsString()); + } + + public void testHandlerReturnsString() throws Exception { + MultiActionController mac = new StringMultiActionController(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mav = mac.handleRequest(request, response); + + assertNotNull("ModelAndView cannot be null", mav); + assertTrue("ModelAndView must have a view", mav.hasView()); + assertEquals("Verifying view name", "welcomeString", mav.getViewName()); + } + + public void testExceptionHandlerReturnsString() throws Exception { + MultiActionController mac = new StringMultiActionController(); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index.html"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView mav = mac.handleRequest(request, response); + + assertNotNull("ModelAndView cannot be null", mav); + assertTrue("ModelAndView must have a view", mav.hasView()); + assertEquals("Verifying view name", "handleIllegalStateExceptionString", mav.getViewName()); + } + + + /** No error handlers */ + public static class TestMaController extends MultiActionController { + + public static final String THROWABLE_ATT = "throwable"; + + /** Method name -> object */ + protected Map invoked = new HashMap(); + + public void clear() { + this.invoked.clear(); + } + + public ModelAndView welcome(HttpServletRequest request, HttpServletResponse response) { + this.invoked.put("welcome", Boolean.TRUE); + return new ModelAndView("welcome"); + } + + public ModelAndView commandNoSession(HttpServletRequest request, HttpServletResponse response, TestBean command) { + this.invoked.put("commandNoSession", Boolean.TRUE); + + String pname = request.getParameter("name"); + String page = request.getParameter("age"); + // ALLOW FOR NULL + if (pname == null) { + assertTrue("name null", command.getName() == null); + } + else { + assertTrue("name param set", pname.equals(command.getName())); + } + // if (page == null) + // assertTrue("age default", command.getAge() == 0); + // else + // assertTrue("age set", command.getName().equals(pname)); + // assertTrue("a", + // command.getAge().equals(request.getParameter("name"))); + return new ModelAndView("commandNoSession"); + } + + public ModelAndView inSession(HttpServletRequest request, HttpServletResponse response, HttpSession session) { + this.invoked.put("inSession", Boolean.TRUE); + assertTrue("session non null", session != null); + return new ModelAndView("inSession"); + } + + public ModelAndView commandInSession(HttpServletRequest request, HttpServletResponse response, + HttpSession session, TestBean command) { + this.invoked.put("commandInSession", Boolean.TRUE); + assertTrue("session non null", session != null); + return new ModelAndView("commandInSession"); + } + + public ModelAndView test(HttpServletRequest request, HttpServletResponse response) { + this.invoked.put("test", Boolean.TRUE); + return new ModelAndView("test"); + } + + public ModelAndView testException(HttpServletRequest request, HttpServletResponse response) throws Throwable { + this.invoked.put("testException", Boolean.TRUE); + Throwable t = (Throwable) request.getAttribute(THROWABLE_ATT); + if (t != null) { + throw t; + } + else { + return new ModelAndView("no throwable"); + } + } + + public boolean wasInvoked(String method) { + return this.invoked.get(method) != null; + } + + public int getInvokedMethods() { + return this.invoked.size(); + } + } + + + public static class TestDelegate { + + boolean invoked; + + public ModelAndView test(HttpServletRequest request, HttpServletResponse response) { + this.invoked = true; + return new ModelAndView("test"); + } + } + + + public static class TestExceptionHandler extends TestMaController { + + public ModelAndView handleAnyException(HttpServletRequest request, HttpServletResponse response, Exception ex) { + this.invoked.put("handle(Exception)", Boolean.TRUE); + return new ModelAndView("handle(Exception)"); + } + } + + + public static class TestRuntimeExceptionHandler extends TestMaController { + + public ModelAndView handleRuntimeProblem(HttpServletRequest request, HttpServletResponse response, + RuntimeException ex) { + this.invoked.put("handle(RTE)", Boolean.TRUE); + return new ModelAndView("handle(RTE)"); + } + } + + + public static class TestSessionRequiredController extends TestMaController { + + public ModelAndView testSession(HttpServletRequest request, HttpServletResponse response, HttpSession sess) { + return null; + } + } + + + /** Extends previous to handle exception */ + public static class TestSessionRequiredExceptionHandler extends TestSessionRequiredController { + + public ModelAndView handleServletException(HttpServletRequest request, HttpServletResponse response, + HttpSessionRequiredException ex) { + this.invoked.put("handle(SRE)", Boolean.TRUE); + return new ModelAndView("handle(SRE)"); + } + } + + public static class TestServletExceptionHandler extends TestMaController { + + public ModelAndView handleServletException(HttpServletRequest request, HttpServletResponse response, + ServletException ex) { + this.invoked.put("handle(ServletException)", Boolean.TRUE); + return new ModelAndView("handle(ServletException)"); + } + } + + + public static class LastModController extends MultiActionController { + + public static final String THROWABLE_ATT = "throwable"; + + /** Method name -> object */ + protected HashMap invoked = new HashMap(); + + public void clear() { + this.invoked.clear(); + } + + public ModelAndView welcome(HttpServletRequest request, HttpServletResponse response) { + this.invoked.put("welcome", Boolean.TRUE); + return new ModelAndView("welcome"); + } + + /** Always says content is up to date */ + public long welcomeLastModified(HttpServletRequest request) { + return 1111L; + } + } + + + public static class ModelOnlyMultiActionController extends MultiActionController { + + private final Map model; + + public ModelOnlyMultiActionController(Map model) throws ApplicationContextException { + this.model = model; + } + + public Map welcome(HttpServletRequest request, HttpServletResponse response) { + return this.model; + } + + public Map index(HttpServletRequest request, HttpServletResponse response) { + throw new IllegalStateException(); + } + + public Map handleIllegalStateException(HttpServletRequest request, HttpServletResponse response, + IllegalStateException ex) { + this.model.put("exception", ex); + return this.model; + } + } + + + public static class VoidMultiActionController extends MultiActionController { + + public void welcome(HttpServletRequest request, HttpServletResponse response) { + } + + public void index(HttpServletRequest request, HttpServletResponse response) { + throw new IllegalStateException(); + } + + public void handleIllegalStateException(HttpServletRequest request, HttpServletResponse response, + IllegalStateException ex) throws IOException { + response.getWriter().write("exception"); + } + } + + + public static class StringMultiActionController extends MultiActionController { + + public String welcome(HttpServletRequest request, HttpServletResponse response) { + return "welcomeString"; + } + + public String index(HttpServletRequest request, HttpServletResponse response) { + throw new IllegalStateException(); + } + + public String handleIllegalStateException(HttpServletRequest request, HttpServletResponse response, + IllegalStateException ex) throws IOException { + return "handleIllegalStateExceptionString"; + } + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/theme/ThemeResolverTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/theme/ThemeResolverTests.java new file mode 100644 index 00000000000..a76087bab8d --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/theme/ThemeResolverTests.java @@ -0,0 +1,80 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.theme; + +import junit.framework.TestCase; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.servlet.ThemeResolver; + +/** + * @author Jean-Pierre Pawlak + * @author Juergen Hoeller + * @since 19.06.2003 + */ +public class ThemeResolverTests extends TestCase { + + private static final String TEST_THEME_NAME = "test.theme"; + private static final String DEFAULT_TEST_THEME_NAME = "default.theme"; + + private void internalTest(ThemeResolver themeResolver, boolean shouldSet, String defaultName) { + // create mocks + MockServletContext context = new MockServletContext(); + MockHttpServletRequest request = new MockHttpServletRequest(context); + MockHttpServletResponse response = new MockHttpServletResponse(); + // check original theme + String themeName = themeResolver.resolveThemeName(request); + assertEquals(themeName, defaultName); + // set new theme name + try { + themeResolver.setThemeName(request, response, TEST_THEME_NAME); + if (!shouldSet) + fail("should not be able to set Theme name"); + // check new theme namelocale + themeName = themeResolver.resolveThemeName(request); + assertEquals(TEST_THEME_NAME, themeName); + themeResolver.setThemeName(request, response, null); + themeName = themeResolver.resolveThemeName(request); + assertEquals(themeName, defaultName); + } + catch (UnsupportedOperationException ex) { + if (shouldSet) + fail("should be able to set Theme name"); + } + } + + public void testFixedThemeResolver() { + internalTest(new FixedThemeResolver(), false, AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME); + } + + public void testCookieThemeResolver() { + internalTest(new CookieThemeResolver(), true, AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME); + } + + public void testSessionThemeResolver() { + internalTest(new SessionThemeResolver(), true,AbstractThemeResolver.ORIGINAL_DEFAULT_THEME_NAME); + } + + public void testSessionThemeResolverWithDefault() { + SessionThemeResolver tr = new SessionThemeResolver(); + tr.setDefaultThemeName(DEFAULT_TEST_THEME_NAME); + internalTest(tr, true, DEFAULT_TEST_THEME_NAME); + } + +}