From f19f55a59bc11b893938c89d2958deddda2430d6 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 19 Mar 2013 16:06:37 +0100 Subject: [PATCH] Removed Spring MVC command/form controller class hierarchy --- .../mvc/AbstractCommandController.java | 213 ---- .../portlet/mvc/AbstractFormController.java | 974 ----------------- .../mvc/AbstractWizardFormController.java | 982 ------------------ .../portlet/mvc/BaseCommandController.java | 666 ------------ .../web/portlet/mvc/SimpleFormController.java | 562 ---------- .../web/portlet/DispatcherPortletTests.java | 327 +----- .../SimplePortletApplicationContext.java | 141 --- .../portlet/mvc/CommandControllerTests.java | 478 --------- .../mvc/AbstractCommandController.java | 108 -- .../servlet/mvc/AbstractFormController.java | 678 ------------ .../mvc/AbstractWizardFormController.java | 751 -------------- .../servlet/mvc/BaseCommandController.java | 595 ----------- .../mvc/CancellableFormController.java | 210 ---- .../web/servlet/mvc/SimpleFormController.java | 468 --------- .../servlet/ComplexWebApplicationContext.java | 8 +- .../web/servlet/DispatcherServletTests.java | 95 -- .../servlet/SimpleWebApplicationContext.java | 2 - .../mvc/CancellableFormControllerTests.java | 239 ----- .../servlet/mvc/CommandControllerTests.java | 522 ---------- .../web/servlet/mvc/FormControllerTests.java | 661 ------------ .../mvc/WizardFormControllerTests.java | 438 -------- .../web/servlet/mvc/mapping/BuyForm.java | 19 +- 22 files changed, 14 insertions(+), 9123 deletions(-) delete mode 100644 spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractCommandController.java delete mode 100644 spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractFormController.java delete mode 100644 spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractWizardFormController.java delete mode 100644 spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/BaseCommandController.java delete mode 100644 spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/SimpleFormController.java delete mode 100644 spring-webmvc-portlet/src/test/java/org/springframework/web/portlet/SimplePortletApplicationContext.java delete mode 100644 spring-webmvc-portlet/src/test/java/org/springframework/web/portlet/mvc/CommandControllerTests.java delete mode 100644 spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/AbstractCommandController.java delete mode 100644 spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/AbstractFormController.java delete mode 100644 spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/AbstractWizardFormController.java delete mode 100644 spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/BaseCommandController.java delete mode 100644 spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/CancellableFormController.java delete mode 100644 spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/SimpleFormController.java delete mode 100644 spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/CancellableFormControllerTests.java delete mode 100644 spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/CommandControllerTests.java delete mode 100644 spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/FormControllerTests.java delete mode 100644 spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/WizardFormControllerTests.java diff --git a/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractCommandController.java b/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractCommandController.java deleted file mode 100644 index dca2fd1717..0000000000 --- a/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractCommandController.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright 2002-2012 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.portlet.mvc; - -import javax.portlet.ActionRequest; -import javax.portlet.ActionResponse; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; - -import org.springframework.validation.BindException; -import org.springframework.web.portlet.ModelAndView; -import org.springframework.web.portlet.bind.PortletRequestDataBinder; -import org.springframework.web.portlet.util.PortletUtils; - -/** - *

Abstract base class for custom command controllers. Autopopulates a - * command bean from the request. For command validation, a validator - * (property inherited from BaseCommandController) can be used.

- * - *

This command controller should preferrable not be used to handle form - * submission, because functionality for forms is more offered in more - * detail by the {@link org.springframework.web.portlet.mvc.AbstractFormController - * AbstractFormController} and its corresponding implementations.

- * - *

Exposed configuration properties - * (and those defined by superclass):
- * none (so only those available in superclass).

- * - *

Workflow - * (and that defined by superclass):
- * - * @author John A. Lewis - * @author Juergen Hoeller - * @since 2.0 - * @see #setCommandClass - * @see #setCommandName - * @see #setValidator - * @deprecated as of Spring 3.0, in favor of annotated controllers - */ -@Deprecated -public abstract class AbstractCommandController extends BaseCommandController { - - /** - * This render parameter is used to indicate forward to the render phase - * that a valid command (and errors) object is in the session. - */ - private static final String COMMAND_IN_SESSION_PARAMETER = "command-in-session"; - - private static final String TRUE = Boolean.TRUE.toString(); - - - /** - * Create a new AbstractCommandController. - */ - public AbstractCommandController() { - } - - /** - * Create a new AbstractCommandController. - * @param commandClass class of the command bean - */ - public AbstractCommandController(Class commandClass) { - setCommandClass(commandClass); - } - - /** - * Create a new AbstractCommandController. - * @param commandClass class of the command bean - * @param commandName name of the command bean - */ - public AbstractCommandController(Class commandClass, String commandName) { - setCommandClass(commandClass); - setCommandName(commandName); - } - - - @Override - protected final void handleActionRequestInternal(ActionRequest request, ActionResponse response) - throws Exception { - - // Create the command object. - Object command = getCommand(request); - - // Compute the errors object. - PortletRequestDataBinder binder = bindAndValidate(request, command); - BindException errors = new BindException(binder.getBindingResult()); - - // Actually handle the action. - handleAction(request, response, command, errors); - - // Pass the command and errors forward to the render phase. - setRenderCommandAndErrors(request, command, errors); - setCommandInSession(response); - } - - @Override - protected final ModelAndView handleRenderRequestInternal( - RenderRequest request, RenderResponse response) throws Exception { - - Object command = null; - BindException errors = null; - - // Get the command and errors objects from the session, if they exist. - if (isCommandInSession(request)) { - logger.debug("Render phase obtaining command and errors objects from session"); - command = getRenderCommand(request); - errors = getRenderErrors(request); - } - else { - logger.debug("Render phase creating new command and errors objects"); - command = getCommand(request); - PortletRequestDataBinder binder = bindAndValidate(request, command); - errors = new BindException(binder.getBindingResult()); - } - - return handleRender(request, response, command, errors); - } - - - /** - * Template method for request handling, providing a populated and validated instance - * of the command class, and an Errors object containing binding and validation errors. - *

Call {@code errors.getModel()} to populate the ModelAndView model - * with the command and the Errors instance, under the specified command name, - * as expected by the "spring:bind" tag. - * @param request current action request - * @param response current action response - * @param command the populated command object - * @param errors validation errors holder - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - */ - protected abstract void handleAction( - ActionRequest request, ActionResponse response, Object command, BindException errors) - throws Exception; - - /** - * Template method for render request handling, providing a populated and validated instance - * of the command class, and an Errors object containing binding and validation errors. - *

Call {@code errors.getModel()} to populate the ModelAndView model - * with the command and the Errors instance, under the specified command name, - * as expected by the "spring:bind" tag. - * @param request current render request - * @param response current render response - * @param command the populated command object - * @param errors validation errors holder - * @return a ModelAndView to render, or null if handled directly - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - */ - protected abstract ModelAndView handleRender( - RenderRequest request, RenderResponse response, Object command, BindException errors) - throws Exception; - - - /** - * Return the name of the render parameter that indicates there - * is a valid command (and errors) object in the session. - * @return the name of the render parameter - * @see javax.portlet.RenderRequest#getParameter - */ - protected String getCommandInSessionParameterName() { - return COMMAND_IN_SESSION_PARAMETER; - } - - /** - * Set the action response parameter that indicates there is a - * command (and errors) object in the session for the render phase. - * @param response the current action response - * @see #getCommandInSessionParameterName - * @see #isCommandInSession - */ - protected final void setCommandInSession(ActionResponse response) { - if (logger.isDebugEnabled()) { - logger.debug("Setting render parameter [" + getCommandInSessionParameterName() + - "] to indicate a valid command (and errors) object are in the session"); - } - try { - response.setRenderParameter(getCommandInSessionParameterName(), TRUE); - } - catch (IllegalStateException ex) { - // Ignore in case sendRedirect was already set. - } - } - - /** - * Determine if there is a valid command (and errors) object in the - * session for this render request. - * @param request current render request - * @return if there is a valid command object in the session - * @see #getCommandInSessionParameterName - * @see #setCommandInSession - */ - protected boolean isCommandInSession(RenderRequest request) { - return (TRUE.equals(request.getParameter(getCommandInSessionParameterName())) && - PortletUtils.getSessionAttribute(request, getRenderCommandSessionAttributeName()) != null); - } - -} diff --git a/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractFormController.java b/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractFormController.java deleted file mode 100644 index b901b5314e..0000000000 --- a/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractFormController.java +++ /dev/null @@ -1,974 +0,0 @@ -/* - * Copyright 2002-2012 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.portlet.mvc; - -import java.util.Arrays; -import java.util.Map; - -import javax.portlet.ActionRequest; -import javax.portlet.ActionResponse; -import javax.portlet.PortletException; -import javax.portlet.PortletRequest; -import javax.portlet.PortletSession; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; - -import org.springframework.validation.BindException; -import org.springframework.validation.Errors; -import org.springframework.web.portlet.ModelAndView; -import org.springframework.web.portlet.bind.PortletRequestDataBinder; -import org.springframework.web.portlet.handler.PortletSessionRequiredException; - -/** - *

Form controller that auto-populates a form bean from the request. - * This, either using a new bean instance per request, or using the same bean - * when the {@code sessionForm} property has been set to - * {@code true}.

- * - *

This class is the base class for both framework subclasses such as - * {@link SimpleFormController} and {@link AbstractWizardFormController} - * and custom form controllers that you may provide yourself.

- * - *

A form-input view and an after-submission view have to be provided - * programmatically. To provide those views using configuration properties, - * use the {@link SimpleFormController}.

- * - *

Subclasses need to override {@code showForm} to prepare the form view, - * {@code processFormSubmission} to handle submit requests, and - * {@code renderFormSubmission} to display the results of the submit. - * For the latter two methods, binding errors like type mismatches will be - * reported via the given "errors" holder. For additional custom form validation, - * a validator (property inherited from BaseCommandController) can be used, - * reporting via the same "errors" instance.

- * - *

Comparing this Controller to the Struts notion of the {@code Action} - * shows us that with Spring, you can use any ordinary JavaBeans or database- - * backed JavaBeans without having to implement a framework-specific class - * (like Struts' {@code ActionForm}). More complex properties of JavaBeans - * (Dates, Locales, but also your own application-specific or compound types) - * can be represented and submitted to the controller, by using the notion of - * a {@code java.beans.PropertyEditors}. For more information on that - * subject, see the workflow of this controller and the explanation of the - * {@link BaseCommandController BaseCommandController}.

- * - *

This controller is different from it's servlet counterpart in that it must take - * into account the two phases of a portlet request: the action phase and the render - * phase. See the JSR-168 spec for more details on these two phases. - * Be especially aware that the action phase is called only once, but that the - * render phase will be called repeatedly by the portal; it does this every time - * the page containing the portlet is updated, even if the activity is in some other - * portlet. (This is not quite true, the portal can also be told to cache the results of - * the render for a period of time, but assume it is true for programming purposes.)

- * - *

Workflow - * (and that defined by superclass):
- *

    - *
  1. The controller receives a request for a new form (typically a - * Render Request only). The render phase will proceed to display - * the form as follows.
  2. - *
  3. Call to {@link #formBackingObject formBackingObject()} which by - * default, returns an instance of the commandClass that has been - * configured (see the properties the superclass exposes), but can also be - * overridden to e.g. retrieve an object from the database (that needs to - * be modified using the form).
  4. - *
  5. Call to {@link #initBinder initBinder()} which allows you to - * register custom editors for certain fields (often properties of non- - * primitive or non-String types) of the command class. This will render - * appropriate Strings for those property values, e.g. locale-specific - * date strings.
  6. - *
  7. The {@link PortletRequestDataBinder PortletRequestDataBinder} - * gets applied to populate the new form object with initial request parameters and the - * {@link #onBindOnNewForm(RenderRequest, Object, BindException)} callback method is invoked. - * (only if {@code bindOnNewForm} is set to {@code true}) - * Make sure that the initial parameters do not include the parameter that indicates a - * form submission has occurred.
  8. - *
  9. Call to {@link #showForm(RenderRequest, RenderResponse, - * BindException) showForm} to return a View that should be rendered - * (typically the view that renders the form). This method has to be - * implemented in subclasses.
  10. - *
  11. The showForm() implementation will call {@link #referenceData referenceData}, - * which you can implement to provide any relevant reference data you might need - * when editing a form (e.g. a List of Locale objects you're going to let the - * user select one from).
  12. - *
  13. Model gets exposed and view gets rendered, to let the user fill in - * the form.
  14. - *
  15. The controller receives a form submission (typically an Action - * Request). To use a different way of detecting a form submission, - * override the {@link #isFormSubmission isFormSubmission} method. - * The action phase will proceed to process the form submission as follows.
  16. - *
  17. If {@code sessionForm} is not set, {@link #formBackingObject - * formBackingObject} is called to retrieve a form object. Otherwise, - * the controller tries to find the command object which is already bound - * in the session. If it cannot find the object, the action phase does a - * call to {@link #handleInvalidSubmit handleInvalidSubmit} which - by default - - * tries to create a new form object and resubmit the form. It then sets - * a render parameter that will indicate to the render phase that this was - * an invalid submit.
  18. - *
  19. Still in the action phase of a valid submit, the {@link - * PortletRequestDataBinder PortletRequestDataBinder} gets applied to populate - * the form object with current request parameters.
  20. - *
  21. Call to {@link #onBind onBind(PortletRequest, Object, Errors)} - * which allows you to do custom processing after binding but before - * validation (e.g. to manually bind request parameters to bean - * properties, to be seen by the Validator).
  22. - *
  23. If {@code validateOnBinding} is set, a registered Validator - * will be invoked. The Validator will check the form object properties, - * and register corresponding errors via the given {@link Errors Errors} - * object.
  24. - *
  25. Call to {@link #onBindAndValidate onBindAndValidate} which allows - * you to do custom processing after binding and validation (e.g. to - * manually bind request parameters, and to validate them outside a - * Validator).
  26. - *
  27. Call to {@link #processFormSubmission processFormSubmission} - * to process the submission, with or without binding errors. - * This method has to be implemented in subclasses and will be called - * only once per form submission.
  28. - *
  29. The portal will then call the render phase of processing the form - * submission. This phase will be called repeatedly by the portal every - * time the page is refreshed. All processing here should take this into - * account. Any one-time-only actions (such as modifying a database) must - * be done in the action phase.
  30. - *
  31. If the action phase indicated this is an invalid submit, the render - * phase calls {@link #renderInvalidSubmit renderInvalidSubmit} which – - * also by default – will render the results of the resubmitted - * form. Be sure to override both {@code handleInvalidSubmit} and - * {@code renderInvalidSubmit} if you want to change this overall - * behavior.
  32. - *
  33. Finally, call {@link #renderFormSubmission renderFormSubmission} to - * render the results of the submission, with or without binding errors. - * This method has to be implemented in subclasses and will be called - * repeatedly by the portal.
  34. - *
- *

- * - *

In session form mode, a submission without an existing form object in the - * session is considered invalid, like in the case of a resubmit/reload by the browser. - * The {@link #handleInvalidSubmit handleInvalidSubmit} / - * {@link #renderInvalidSubmit renderInvalidSubmit} methods are invoked then, - * by default trying to resubmit. This can be overridden in subclasses to show - * corresponding messages or to redirect to a new form, in order to avoid duplicate - * submissions. The form object in the session can be considered a transaction token - * in that case.

- * - *

Make sure that any URLs that take you to your form controller are Render URLs, - * so that it will not try to treat the initial call as a form submission. - * If you use action URLs to link to your controller, you will need to override the - * {@link #isFormSubmission isFormSubmission} method to use a different mechanism for - * determining whether a form has been submitted. Make sure this method will work for - * both the ActionRequest and the RenderRequest objects.

- * - *

Note that views should never retrieve form beans from the session but always - * from the request, as prepared by the form controller. Remember that some view - * technologies like Velocity cannot even access a HTTP session.

- * - *

Exposed configuration properties - * (and those defined by superclass):
- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
namedefaultdescription
bindOnNewFormfalseIndicates whether to bind portlet request parameters when - * creating a new form. Otherwise, the parameters will only be - * bound on form submission attempts.
sessionFormfalseIndicates whether the form object should be kept in the session - * when a user asks for a new form. This allows you e.g. to retrieve - * an object from the database, let the user edit it, and then persist - * it again. Otherwise, a new command object will be created for each - * request (even when showing the form again after validation errors).
redirectActionfalseSpecifies whether {@code processFormSubmission} is expected to call - * {@link ActionResponse#sendRedirect ActionResponse.sendRedirect}. - * This is important because some methods may not be called before - * {@link ActionResponse#sendRedirect ActionResponse.sendRedirect} (e.g. - * {@link ActionResponse#setRenderParameter ActionResponse.setRenderParameter}). - * Setting this flag will prevent AbstractFormController from setting render - * parameters that it normally needs for the render phase. - * If this is set true and {@code sendRedirect} is not called, then - * {@code processFormSubmission} must call - * {@link #setFormSubmit setFormSubmit}. - * Otherwise, the render phase will not realize the form was submitted - * and will simply display a new blank form.
renderParametersnullAn array of parameters that will be passed forward from the action - * phase to the render phase if the form needs to be displayed - * again. These can also be passed forward explicitly by calling - * the {@code passRenderParameters} method from any action - * phase method. Abstract descendants of this controller should follow - * similar behavior. If there are parameters you need in - * {@code renderFormSubmission}, then you need to pass those - * forward from {@code processFormSubmission}. If you override the - * default behavior of invalid submits and you set sessionForm to true, - * then you probably will not need to set this because your parameters - * are only going to be needed on the first request.
- *

- * - *

Thanks to Rainer Schmitz and Nick Lothian for their suggestions! - * - * @author John A. Lewis - * @author Juergen Hoeller - * @author Alef Arendsen - * @author Rob Harrop - * @since 2.0 - * @see #showForm(RenderRequest, RenderResponse, BindException) - * @see SimpleFormController - * @see AbstractWizardFormController - * @deprecated as of Spring 3.0, in favor of annotated controllers - */ -@Deprecated -public abstract class AbstractFormController extends BaseCommandController { - - /** - * These render parameters are used to indicate forward to the render phase - * if the form was submitted and if the submission was invalid. - */ - private static final String FORM_SUBMISSION_PARAMETER = "form-submit"; - - private static final String INVALID_SUBMISSION_PARAMETER = "invalid-submit"; - - private static final String TRUE = Boolean.TRUE.toString(); - - - private boolean bindOnNewForm = false; - - private boolean sessionForm = false; - - private boolean redirectAction = false; - - private String[] renderParameters = null; - - - /** - * Create a new AbstractFormController. - *

Subclasses should set the following properties, either in the constructor - * or via a BeanFactory: commandName, commandClass, bindOnNewForm, sessionForm. - * Note that commandClass doesn't need to be set when overriding - * {@code formBackingObject}, as the latter determines the class anyway. - *

"cacheSeconds" is by default set to 0 (-> no caching for all form controllers). - * @see #setCommandName - * @see #setCommandClass - * @see #setBindOnNewForm - * @see #setSessionForm - * @see #formBackingObject - */ - public AbstractFormController() { - setCacheSeconds(0); - } - - /** - * Set if request parameters should be bound to the form object - * in case of a non-submitting request, i.e. a new form. - */ - public final void setBindOnNewForm(boolean bindOnNewForm) { - this.bindOnNewForm = bindOnNewForm; - } - - /** - * Return if request parameters should be bound in case of a new form. - */ - public final boolean isBindOnNewForm() { - return this.bindOnNewForm; - } - - /** - * Activate/deactivate session form mode. In session form mode, - * the form is stored in the session to keep the form object instance - * between requests, instead of creating a new one on each request. - *

This is necessary for either wizard-style controllers that populate a - * single form object from multiple pages, or forms that populate a persistent - * object that needs to be identical to allow for tracking changes. - */ - public final void setSessionForm(boolean sessionForm) { - this.sessionForm = sessionForm; - } - - /** - * Return if session form mode is activated. - */ - public final boolean isSessionForm() { - return this.sessionForm; - } - - /** - * Specify whether the action phase is expected to call - * {@link ActionResponse#sendRedirect}. - * This information is important because some methods may not be called - * before {@link ActionResponse#sendRedirect}, e.g. - * {@link ActionResponse#setRenderParameter} and - * {@link ActionResponse#setRenderParameters}. - *

NOTE: Call this at initialization time of your controller: - * either in the constructor or in the bean definition for your controller. - * @see ActionResponse#sendRedirect - */ - public void setRedirectAction(boolean redirectAction) { - this.redirectAction = redirectAction; - } - - /** - * Return if {@link ActionResponse#sendRedirect} is - * expected to be called in the action phase. - */ - public boolean isRedirectAction() { - return this.redirectAction; - } - - /** - * Specify the list of parameters that should be passed forward - * from the action phase to the render phase whenever the form is - * re-rendered or when {@link #passRenderParameters} is called. - * @see #passRenderParameters - */ - public void setRenderParameters(String[] parameters) { - this.renderParameters = parameters; - } - - /** - * Returns the list of parameters that will be passed forward - * from the action phase to the render phase whenever the form is - * rerendered or when {@link #passRenderParameters} is called. - * @return the list of parameters - * @see #passRenderParameters - */ - public String[] getRenderParameters() { - return this.renderParameters; - } - - - /** - * Handles action phase of two cases: form submissions and showing a new form. - * Delegates the decision between the two to {@code isFormSubmission}, - * always treating requests without existing form session attribute - * as new form when using session form mode. - * @see #isFormSubmission - * @see #processFormSubmission - * @see #handleRenderRequestInternal - */ - @Override - protected void handleActionRequestInternal(ActionRequest request, ActionResponse response) - throws Exception { - - // Form submission or new form to show? - if (isFormSubmission(request)) { - // Fetch form object, bind, validate, process submission. - try { - Object command = getCommand(request); - if (logger.isDebugEnabled()) { - logger.debug("Processing valid submit (redirectAction = " + isRedirectAction() + ")"); - } - if (!isRedirectAction()) { - setFormSubmit(response); - } - PortletRequestDataBinder binder = bindAndValidate(request, command); - BindException errors = new BindException(binder.getBindingResult()); - processFormSubmission(request, response, command, errors); - setRenderCommandAndErrors(request, command, errors); - return; - } - catch (PortletSessionRequiredException ex) { - // Cannot submit a session form if no form object is in the session. - if (logger.isDebugEnabled()) { - logger.debug("Invalid submit detected: " + ex.getMessage()); - } - setFormSubmit(response); - setInvalidSubmit(response); - handleInvalidSubmit(request, response); - return; - } - } - - else { - logger.debug("Not a form submit - passing parameters to render phase"); - passRenderParameters(request, response); - return; - } - } - - /** - * Handles render phase of two cases: form submissions and showing a new form. - * Delegates the decision between the two to {@code isFormSubmission}, - * always treating requests without existing form session attribute - * as new form when using session form mode. - * @see #isFormSubmission - * @see #showNewForm - * @see #processFormSubmission - * @see #handleActionRequestInternal - */ - @Override - protected ModelAndView handleRenderRequestInternal(RenderRequest request, RenderResponse response) - throws Exception { - - // Form submission or new form to show? - if (isFormSubmission(request)) { - - // If it is an invalid submit then handle it. - if (isInvalidSubmission(request)) { - logger.debug("Invalid submit - calling renderInvalidSubmit"); - return renderInvalidSubmit(request, response); - } - - // Valid submit -> render. - logger.debug("Valid submit - calling renderFormSubmission"); - return renderFormSubmission(request, response, getRenderCommand(request), getRenderErrors(request)); - } - - else { - // New form to show: render form view. - return showNewForm(request, response); - } - } - - /** - * Determine if the given request represents a form submission. - *

The default implementation checks to see if this is an ActionRequest - * and treats all action requests as form submission. During the action - * phase it will pass forward a render parameter to indicate to the render - * phase that this is a form submission. This method can check both - * kinds of requests and indicate if this is a form submission. - *

Subclasses can override this to use a custom strategy, e.g. a specific - * request parameter (assumably a hidden field or submit button name). Make - * sure that the override can handle both ActionRequest and RenderRequest - * objects properly. - * @param request current request - * @return if the request represents a form submission - */ - protected boolean isFormSubmission(PortletRequest request) { - return (request instanceof ActionRequest || TRUE.equals(request.getParameter(getFormSubmitParameterName()))); - } - - /** - * Determine if the given request represents an invalid form submission. - */ - protected boolean isInvalidSubmission(PortletRequest request) { - return TRUE.equals(request.getParameter(getInvalidSubmitParameterName())); - } - - /** - * Return the name of the render parameter that indicates this - * was a form submission. - * @return the name of the render parameter - * @see javax.portlet.RenderRequest#getParameter - */ - protected String getFormSubmitParameterName() { - return FORM_SUBMISSION_PARAMETER; - } - - /** - * Return the name of the render parameter that indicates this - * was an invalid form submission. - * @return the name of the render parameter - * @see javax.portlet.RenderRequest#getParameter - */ - protected String getInvalidSubmitParameterName() { - return INVALID_SUBMISSION_PARAMETER; - } - - /** - * Set the action response parameter that indicates this in a form submission. - * @param response the current action response - * @see #getFormSubmitParameterName() - */ - protected final void setFormSubmit(ActionResponse response) { - if (logger.isDebugEnabled()) { - logger.debug("Setting render parameter [" + getFormSubmitParameterName() + - "] to indicate this is a form submission"); - } - try { - response.setRenderParameter(getFormSubmitParameterName(), TRUE); - } - catch (IllegalStateException ex) { - // Ignore in case sendRedirect was already set. - } - } - - /** - * Set the action response parameter that indicates this in an invalid submission. - * @param response the current action response - * @see #getInvalidSubmitParameterName() - */ - protected final void setInvalidSubmit(ActionResponse response) { - if (logger.isDebugEnabled()) { - logger.debug("Setting render parameter [" + getInvalidSubmitParameterName() + - "] to indicate this is an invalid submission"); - } - try { - response.setRenderParameter(getInvalidSubmitParameterName(), TRUE); - } - catch (IllegalStateException ex) { - // Ignore in case sendRedirect was already set. - } - } - - /** - * Return the name of the PortletSession attribute that holds the form object - * for this form controller. - *

The default implementation delegates to the - * {@code getFormSessionAttributeName} version without arguments. - * @param request current HTTP request - * @return the name of the form session attribute, - * or {@code null} if not in session form mode - * @see #getFormSessionAttributeName() - * @see javax.portlet.PortletSession#getAttribute - */ - protected String getFormSessionAttributeName(PortletRequest request) { - return getFormSessionAttributeName(); - } - - /** - * Return the name of the PortletSession attribute that holds the form object - * for this form controller. - *

Default is an internal name, of no relevance to applications, as the form - * session attribute is not usually accessed directly. Can be overridden to use - * an application-specific attribute name, which allows other code to access - * the session attribute directly. - * @return the name of the form session attribute - * @see javax.portlet.PortletSession#getAttribute - */ - protected String getFormSessionAttributeName() { - return getClass().getName() + ".FORM." + getCommandName(); - } - - /** - * Pass the specified list of action request parameters to the render phase - * by putting them into the action response object. This may not be called - * when the action will call will call - * {@link ActionResponse#sendRedirect sendRedirect}. - * @param request the current action request - * @param response the current action response - * @see ActionResponse#setRenderParameter - */ - protected void passRenderParameters(ActionRequest request, ActionResponse response) { - if (this.renderParameters == null) { - return; - } - try { - for (int i = 0; i < this.renderParameters.length; i++) { - String paramName = this.renderParameters[i]; - String paramValues[] = request.getParameterValues(paramName); - if (paramValues != null) { - if (logger.isDebugEnabled()) { - logger.debug("Passing parameter to render phase '" + paramName + "' = " + - (paramValues == null ? "NULL" : Arrays.asList(paramValues).toString())); - } - response.setRenderParameter(paramName, paramValues); - } - } - } - catch (IllegalStateException ex) { - // Ignore in case sendRedirect was already set. - } - } - - - /** - * Show a new form. Prepares a backing object for the current form - * and the given request, including checking its validity. - * @param request current render request - * @param response current render response - * @return the prepared form view - * @throws Exception in case of an invalid new form object - * @see #getErrorsForNewForm - */ - protected final ModelAndView showNewForm(RenderRequest request, RenderResponse response) - throws Exception { - - logger.debug("Displaying new form"); - return showForm(request, response, getErrorsForNewForm(request)); - } - - /** - * Create a BindException instance for a new form. - * Called by {@code showNewForm}. - *

Can be used directly when intending to show a new form but with - * special errors registered on it (for example, on invalid submit). - * Usually, the resulting BindException will be passed to - * {@code showForm}, after registering the errors on it. - * @param request current render request - * @return the BindException instance - * @throws Exception in case of an invalid new form object - */ - protected final BindException getErrorsForNewForm(RenderRequest request) throws Exception { - // Create form-backing object for new form - Object command = formBackingObject(request); - if (command == null) { - throw new PortletException("Form object returned by formBackingObject() must not be null"); - } - if (!checkCommand(command)) { - throw new PortletException("Form object returned by formBackingObject() must match commandClass"); - } - - // Bind without validation, to allow for prepopulating a form, and for - // convenient error evaluation in views (on both first attempt and resubmit). - PortletRequestDataBinder binder = createBinder(request, command); - BindException errors = new BindException(binder.getBindingResult()); - - if (isBindOnNewForm()) { - if (logger.isDebugEnabled()) { - logger.debug("Binding to new form"); - } - binder.bind(request); - onBindOnNewForm(request, command, errors); - } - - // Return BindException object that resulted from binding. - return errors; - } - - /** - * Callback for custom post-processing in terms of binding for a new form. - * Called when preparing a new form if {@code bindOnNewForm} is {@code true}. - *

Default implementation delegates to {@code onBindOnNewForm(request, command)}. - * @param request current render request - * @param command the command object to perform further binding on - * @param errors validation errors holder, allowing for additional - * custom registration of binding errors - * @throws Exception in case of invalid state or arguments - * @see #onBindOnNewForm(RenderRequest, Object) - * @see #setBindOnNewForm - */ - protected void onBindOnNewForm(RenderRequest request, Object command, BindException errors) - throws Exception { - - onBindOnNewForm(request, command); - } - - /** - * Callback for custom post-processing in terms of binding for a new form. - * Called by the default implementation of the {@code onBindOnNewForm} version - * with all parameters, after standard binding when displaying the form view. - * Only called if {@code bindOnNewForm} is set to {@code true}. - *

The default implementation is empty. - * @param request current render request - * @param command the command object to perform further binding on - * @throws Exception in case of invalid state or arguments - * @see #onBindOnNewForm(RenderRequest, Object, BindException) - * @see #setBindOnNewForm(boolean) - */ - protected void onBindOnNewForm(RenderRequest request, Object command) throws Exception { - } - - - /** - * Return the form object for the given request. - *

Calls {@code formBackingObject} if the object is not in the session - * @param request current request - * @return object form to bind onto - * @see #formBackingObject - */ - @Override - protected final Object getCommand(PortletRequest request) throws Exception { - // If not in session-form mode, create a new form-backing object. - if (!isSessionForm()) { - return formBackingObject(request); - } - - // Session-form mode: retrieve form object from portlet session attribute. - PortletSession session = request.getPortletSession(false); - if (session == null) { - throw new PortletSessionRequiredException("Must have session when trying to bind (in session-form mode)"); - } - String formAttrName = getFormSessionAttributeName(request); - Object sessionFormObject = session.getAttribute(formAttrName); - if (sessionFormObject == null) { - throw new PortletSessionRequiredException("Form object not found in session (in session-form mode)"); - } - - // Remove form object from porlet session: we might finish the form workflow - // in this request. If it turns out that we need to show the form view again, - // we'll re-bind the form object to the portlet session. - if (logger.isDebugEnabled()) { - logger.debug("Removing form session attribute [" + formAttrName + "]"); - } - session.removeAttribute(formAttrName); - - // Check the command object to make sure its valid - if (!checkCommand(sessionFormObject)) { - throw new PortletSessionRequiredException("Object found in session does not match commandClass"); - } - - return sessionFormObject; - } - - /** - * Retrieve a backing object for the current form from the given request. - *

The properties of the form object will correspond to the form field values - * in your form view. This object will be exposed in the model under the specified - * command name, to be accessed under that name in the view: for example, with - * a "spring:bind" tag. The default command name is "command". - *

Note that you need to activate session form mode to reuse the form-backing - * object across the entire form workflow. Else, a new instance of the command - * class will be created for each submission attempt, just using this backing - * object as template for the initial form. - *

The default implementation calls {@code BaseCommandController.createCommand}, - * creating a new empty instance of the command class. - * Subclasses can override this to provide a preinitialized backing object. - * @param request current portlet request - * @return the backing object - * @throws Exception in case of invalid state or arguments - * @see #setCommandName - * @see #setCommandClass - * @see #createCommand - */ - protected Object formBackingObject(PortletRequest request) throws Exception { - return createCommand(); - } - - - /** - * Prepare the form model and view, including reference and error data. - * Can show a configured form page, or generate a form view programmatically. - *

A typical implementation will call - * {@code showForm(request, errors, "myView")} - * to prepare the form view for a specific view name, returning the - * ModelAndView provided there. - *

For building a custom ModelAndView, call {@code errors.getModel()} - * to populate the ModelAndView model with the command and the Errors instance, - * under the specified command name, as expected by the "spring:bind" tag. - * You also need to include the model returned by {@code referenceData}. - *

Note: If you decide to have a "formView" property specifying the - * view name, consider using SimpleFormController. - * @param request current render request - * @param response current render response - * @param errors validation errors holder - * @return the prepared form view, or null if handled directly - * @throws Exception in case of invalid state or arguments - * @see #showForm(RenderRequest, BindException, String) - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - * @see #referenceData(PortletRequest, Object, Errors) - * @see SimpleFormController#setFormView - */ - protected abstract ModelAndView showForm(RenderRequest request, RenderResponse response, BindException errors) throws Exception; - - /** - * Prepare model and view for the given form, including reference and errors. - *

In session form mode: Re-puts the form object in the session when - * returning to the form, as it has been removed by getCommand. - *

Can be used in subclasses to redirect back to a specific form page. - * @param request current render request - * @param errors validation errors holder - * @param viewName name of the form view - * @return the prepared form view - * @throws Exception in case of invalid state or arguments - * @see #showForm(RenderRequest, BindException, String, Map) - * @see #showForm(RenderRequest, RenderResponse, BindException) - */ - protected final ModelAndView showForm(RenderRequest request, BindException errors, String viewName) - throws Exception { - - return showForm(request, errors, viewName, null); - } - - /** - * Prepare model and view for the given form, including reference and errors, - * adding a controller-specific control model. - *

In session form mode: Re-puts the form object in the session when returning - * to the form, as it has been removed by getCommand. - *

Can be used in subclasses to redirect back to a specific form page. - * @param request current render request - * @param errors validation errors holder - * @param viewName name of the form view - * @param controlModel model map containing controller-specific control data - * (e.g. current page in wizard-style controllers or special error message) - * @return the prepared form view - * @throws Exception in case of invalid state or arguments - * @see #showForm(RenderRequest, BindException, String) - * @see #showForm(RenderRequest, RenderResponse, BindException) - */ - protected final ModelAndView showForm(RenderRequest request, BindException errors, String viewName, Map controlModel) - throws Exception { - - // In session form mode, re-expose form object as portlet session attribute. - // Re-binding is necessary for proper state handling in a cluster, - // to notify other nodes of changes in the form object. - if (isSessionForm()) { - String formAttrName = getFormSessionAttributeName(request); - if (logger.isDebugEnabled()) { - logger.debug("Setting form session attribute [" + formAttrName + "] to: " + errors.getTarget()); - } - request.getPortletSession().setAttribute(formAttrName, errors.getTarget()); - } - - // Fetch errors model as starting point, containing form object under - // "commandName", and corresponding Errors instance under internal key. - Map model = errors.getModel(); - - // Merge reference data into model, if any. - Map referenceData = referenceData(request, errors.getTarget(), errors); - if (referenceData != null) { - model.putAll(referenceData); - } - - // Merge control attributes into model, if any. - if (controlModel != null) { - model.putAll(controlModel); - } - - // Trigger rendering of the specified view, using the final model. - return new ModelAndView(viewName, model); - } - - /** - * Create a reference data map for the given request, consisting of - * bean name/bean instance pairs as expected by ModelAndView. - *

The default implementation returns {@code null}. - * Subclasses can override this to set reference data used in the view. - * @param request current render request - * @param command form object with request parameters bound onto it - * @param errors validation errors holder - * @return a Map with reference data entries, or null if none - * @throws Exception in case of invalid state or arguments - * @see ModelAndView - */ - protected Map referenceData(PortletRequest request, Object command, Errors errors) throws Exception { - return null; - } - - - /** - * Process render phase of form submission request. Called by {@code handleRequestInternal} - * in case of a form submission, with or without binding errors. Implementations - * need to proceed properly, typically showing a form view in case of binding - * errors or rendering the result of a submit action else. - *

For a success view, call {@code errors.getModel()} to populate the - * ModelAndView model with the command and the Errors instance, under the - * specified command name, as expected by the "spring:bind" tag. For a form view, - * simply return the ModelAndView object privded by {@code showForm}. - * @param request current render request - * @param response current render response - * @param command form object with request parameters bound onto it - * @param errors errors holder - * @return the prepared model and view, or null - * @throws Exception in case of errors - * @see #handleRenderRequestInternal - * @see #processFormSubmission - * @see #isFormSubmission - * @see #showForm(RenderRequest, RenderResponse, BindException) - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - */ - protected abstract ModelAndView renderFormSubmission(RenderRequest request, RenderResponse response, Object command, BindException errors) - throws Exception; - - /** - * Process action phase of form submission request. Called by {@code handleRequestInternal} - * in case of a form submission, with or without binding errors. Implementations - * need to proceed properly, typically performing a submit action if there are no binding errors. - *

Subclasses can implement this to provide custom submission handling - * like triggering a custom action. They can also provide custom validation - * or proceed with the submission accordingly. - * @param request current action request - * @param response current action response - * @param command form object with request parameters bound onto it - * @param errors errors holder (subclass can add errors if it wants to) - * @throws Exception in case of errors - * @see #handleActionRequestInternal - * @see #renderFormSubmission - * @see #isFormSubmission - * @see org.springframework.validation.Errors - */ - protected abstract void processFormSubmission(ActionRequest request, ActionResponse response, Object command, BindException errors) - throws Exception; - - /** - * Handle an invalid submit request, e.g. when in session form mode but no form object - * was found in the session (like in case of an invalid resubmit by the browser). - *

The default implementation simply tries to resubmit the form with a new form object. - * This should also work if the user hit the back button, changed some form data, - * and resubmitted the form. - *

Note: To avoid duplicate submissions, you need to override this method. - * Either show some "invalid submit" message, or call {@code showNewForm} for - * resetting the form (prepopulating it with the current values if "bindOnNewForm" - * is true). In this case, the form object in the session serves as transaction token. - *

-	 * protected ModelAndView renderInvalidSubmit(RenderRequest request, RenderResponse response) throws Exception {
-	 *   return showNewForm(request, response);
-	 * }
- * You can also show a new form but with special errors registered on it: - *
-	 * protected ModelAndView renderInvalidSubmit(RenderRequest request, RenderResponse response) throws Exception {
-	 *   BindException errors = getErrorsForNewForm(request);
-	 *   errors.reject("duplicateFormSubmission", "Duplicate form submission");
-	 *   return showForm(request, response, errors);
-	 * }
- *

WARNING: If you override this method, be sure to also override the action - * phase version of this method so that it will not attempt to perform the resubmit - * action by default. - * @param request current render request - * @param response current render response - * @return a prepared view, or null if handled directly - * @throws Exception in case of errors - * @see #handleInvalidSubmit - */ - protected ModelAndView renderInvalidSubmit(RenderRequest request, RenderResponse response) - throws Exception { - - return renderFormSubmission(request, response, getRenderCommand(request), getRenderErrors(request)); - } - - /** - * Handle an invalid submit request, e.g. when in session form mode but no form object - * was found in the session (like in case of an invalid resubmit by the browser). - *

The default implementation simply tries to resubmit the form with a new form object. - * This should also work if the user hit the back button, changed some form data, - * and resubmitted the form. - *

Note: To avoid duplicate submissions, you need to override this method. - * Most likely you will simply want it to do nothing here in the action phase - * and diplay an appropriate error and a new form in the render phase. - *

-	 * protected void handleInvalidSubmit(ActionRequest request, ActionResponse response) throws Exception {
-	 * }
- *

If you override this method but you do need a command object and bind errors - * in the render phase, be sure to call {@link #setRenderCommandAndErrors setRenderCommandAndErrors} - * from here. - * @param request current action request - * @param response current action response - * @throws Exception in case of errors - * @see #renderInvalidSubmit - * @see #setRenderCommandAndErrors - */ - protected void handleInvalidSubmit(ActionRequest request, ActionResponse response) throws Exception { - passRenderParameters(request, response); - Object command = formBackingObject(request); - if (command == null) { - throw new PortletException("Form object returned by formBackingObject() must not be null"); - } - if (!checkCommand(command)) { - throw new PortletException("Form object returned by formBackingObject() must match commandClass"); - } - PortletRequestDataBinder binder = bindAndValidate(request, command); - BindException errors = new BindException(binder.getBindingResult()); - processFormSubmission(request, response, command, errors); - setRenderCommandAndErrors(request, command, errors); - } - -} diff --git a/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractWizardFormController.java b/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractWizardFormController.java deleted file mode 100644 index e9f98b1cac..0000000000 --- a/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractWizardFormController.java +++ /dev/null @@ -1,982 +0,0 @@ -/* - * Copyright 2002-2012 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.portlet.mvc; - -import java.util.HashMap; -import java.util.Map; -import javax.portlet.ActionRequest; -import javax.portlet.ActionResponse; -import javax.portlet.PortletException; -import javax.portlet.PortletRequest; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; - -import org.springframework.validation.BindException; -import org.springframework.validation.Errors; -import org.springframework.web.portlet.ModelAndView; -import org.springframework.web.portlet.util.PortletUtils; - -/** - * Form controller for typical wizard-style workflows. - * - *

In contrast to classic forms, wizards have more than one form view page. - * Therefore, there are various actions instead of one single submit action: - *

- * - *

Finish and cancel actions can be triggered by request parameters, named - * PARAM_FINISH ("_finish") and PARAM_CANCEL ("_cancel"), ignoring parameter - * values to allow for HTML buttons. The target page for page changes can be - * specified by PARAM_TARGET, appending the page number to the parameter name - * (e.g. "_target1"). The action parameters are recognized when triggered by - * image buttons too (via "_finish.x", "_abort.x", or "_target1.x"). - * - *

The current page number will be stored in the session. It can also be - * specified as request parameter PARAM_PAGE ("_page") in order to properly handle - * usage of the back button in a browser: In this case, a submission will always - * contain the correct page number, even if the user submitted from an old view. - * - *

The page can only be changed if it validates correctly, except if a - * "dirty back" or "dirty forward" is allowed. At finish, all pages get - * validated again to guarantee a consistent state. - * - *

Note that a validator's default validate method is not executed when using - * this class! Rather, the {@code validatePage} implementation should call - * special {@code validateXXX} methods that the validator needs to provide, - * validating certain pieces of the object. These can be combined to validate - * the elements of individual pages. - * - *

Note: Page numbering starts with 0, to be able to pass an array - * consisting of the corresponding view names to the "pages" bean property. - * - *

Parameters indicated with {@code setPassRenderParameters} will be present - * for each page. If there are render parameters you need in {@code renderFinish} - * or {@code renderCancel}, then you need to pass those forward from the - * {@code processFinish} or {@code processCancel} methods, respectively. - - * @author Juergen Hoeller - * @author John A. Lewis - * @since 2.0 - * @see #setPages - * @see #validatePage - * @see #processFinish - * @see #processCancel - * @deprecated as of Spring 3.0, in favor of annotated controllers - */ -@Deprecated -public abstract class AbstractWizardFormController extends AbstractFormController { - - /** - * Parameter triggering the finish action. - * Can be called from any wizard page! - */ - public static final String PARAM_FINISH = "_finish"; - - /** - * Parameter triggering the cancel action. - * Can be called from any wizard page! - */ - public static final String PARAM_CANCEL = "_cancel"; - - /** - * Parameter specifying the target page, - * appending the page number to the name. - */ - public static final String PARAM_TARGET = "_target"; - - /** - * Parameter specifying the current page as value. Not necessary on - * form pages, but allows to properly handle usage of the back button. - * @see #setPageAttribute - */ - public static final String PARAM_PAGE = "_page"; - - - private String[] pages; - - private String pageAttribute; - - private boolean allowDirtyBack = true; - - private boolean allowDirtyForward = false; - - - /** - * Create a new AbstractWizardFormController. - *

"sessionForm" is automatically turned on, "validateOnBinding" - * turned off, and "cacheSeconds" set to 0 by the base class - * (-> no caching for all form controllers). - */ - public AbstractWizardFormController() { - // AbstractFormController sets default cache seconds to 0. - super(); - - // Always needs session to keep data from all pages. - setSessionForm(true); - - // Never validate everything on binding -> - // wizards validate individual pages. - setValidateOnBinding(false); - } - - /** - * Set the wizard pages, i.e. the view names for the pages. - * The array index is interpreted as page number. - * @param pages view names for the pages - */ - public final void setPages(String[] pages) { - if (pages == null || pages.length == 0) { - throw new IllegalArgumentException("No wizard pages defined"); - } - this.pages = pages; - } - - /** - * Return the wizard pages, i.e. the view names for the pages. - * The array index corresponds to the page number. - *

Note that a concrete wizard form controller might override - * {@code getViewName(PortletRequest, Object, int)} to - * determine the view name for each page dynamically. - * @see #getViewName(PortletRequest, Object, int) - */ - public final String[] getPages() { - return this.pages; - } - - /** - * Return the number of wizard pages. - * Useful to check whether the last page has been reached. - *

Note that a concrete wizard form controller might override - * {@code getPageCount(PortletRequest, Object)} to determine - * the page count dynamically. - * @see #getPageCount(PortletRequest, Object) - */ - protected final int getPageCount() { - return this.pages.length; - } - - /** - * Set the name of the page attribute in the model, containing - * an Integer with the current page number. - *

This will be necessary for single views rendering multiple view pages. - * It also allows for specifying the optional "_page" parameter. - * @param pageAttribute name of the page attribute - * @see #PARAM_PAGE - */ - public final void setPageAttribute(String pageAttribute) { - this.pageAttribute = pageAttribute; - } - - /** - * Return the name of the page attribute in the model. - */ - public final String getPageAttribute() { - return this.pageAttribute; - } - - /** - * Set if "dirty back" is allowed, i.e. if moving to a former wizard - * page is allowed in case of validation errors for the current page. - * @param allowDirtyBack if "dirty back" is allowed - */ - public final void setAllowDirtyBack(boolean allowDirtyBack) { - this.allowDirtyBack = allowDirtyBack; - } - - /** - * Return whether "dirty back" is allowed. - */ - public final boolean isAllowDirtyBack() { - return this.allowDirtyBack; - } - - /** - * Set if "dirty forward" is allowed, i.e. if moving to a later wizard - * page is allowed in case of validation errors for the current page. - * @param allowDirtyForward if "dirty forward" is allowed - */ - public final void setAllowDirtyForward(boolean allowDirtyForward) { - this.allowDirtyForward = allowDirtyForward; - } - - /** - * Return whether "dirty forward" is allowed. - */ - public final boolean isAllowDirtyForward() { - return this.allowDirtyForward; - } - - - /** - * Calls page-specific onBindAndValidate method. - */ - @Override - protected final void onBindAndValidate(PortletRequest request, Object command, BindException errors) - throws Exception { - - onBindAndValidate(request, command, errors, getCurrentPage(request)); - } - - /** - * Callback for custom post-processing in terms of binding and validation. - * Called on each submit, after standard binding but before page-specific - * validation of this wizard form controller. - *

Note: AbstractWizardFormController does not perform standard - * validation on binding but rather applies page-specific validation - * on processing the form submission. - * @param request current portlet request - * @param command bound command - * @param errors Errors instance for additional custom validation - * @param page current wizard page - * @throws Exception in case of invalid state or arguments - * @see #bindAndValidate - * @see #processFormSubmission - * @see org.springframework.validation.Errors - */ - protected void onBindAndValidate(PortletRequest request, Object command, BindException errors, int page) - throws Exception { - } - - /** - * Consider an explicit finish or cancel request as a form submission too. - * @see #isFinishRequest(PortletRequest) - * @see #isCancelRequest(PortletRequest) - */ - @Override - protected boolean isFormSubmission(PortletRequest request) { - return super.isFormSubmission(request) || isFinishRequest(request) || isCancelRequest(request); - } - - /** - * Calls page-specific referenceData method. - */ - @Override - protected final Map referenceData(PortletRequest request, Object command, Errors errors) - throws Exception { - - return referenceData(request, command, errors, getCurrentPage(request)); - } - - /** - * Create a reference data map for the given request, consisting of - * bean name/bean instance pairs as expected by ModelAndView. - *

The default implementation delegates to {@link #referenceData(PortletRequest, int)}. - * Subclasses can override this to set reference data used in the view. - * @param request current portlet request - * @param command form object with request parameters bound onto it - * @param errors validation errors holder - * @param page current wizard page - * @return a Map with reference data entries, or null if none - * @throws Exception in case of invalid state or arguments - * @see #referenceData(PortletRequest, int) - * @see org.springframework.web.portlet.ModelAndView - */ - protected Map referenceData(PortletRequest request, Object command, Errors errors, int page) - throws Exception { - - return referenceData(request, page); - } - - /** - * Create a reference data map for the given request, consisting of - * bean name/bean instance pairs as expected by ModelAndView. - *

The default implementation returns {@code null}. - * Subclasses can override this to set reference data used in the view. - * @param request current portlet request - * @param page current wizard page - * @return a Map with reference data entries, or null if none - * @throws Exception in case of invalid state or arguments - * @see org.springframework.web.portlet.ModelAndView - */ - protected Map referenceData(PortletRequest request, int page) throws Exception { - return null; - } - - - /** - * Show the first page as form view. - *

This can be overridden in subclasses, e.g. to prepare wizard-specific - * error views in case of an Exception. - */ - @Override - protected ModelAndView showForm( - RenderRequest request, RenderResponse response, BindException errors) throws Exception { - - return showPage(request, errors, getInitialPage(request, errors.getTarget())); - } - - /** - * Prepare the form model and view, including reference and error data, - * for the given page. Can be used in {@code processFinish} implementations, - * to show the corresponding page in case of validation errors. - * @param request current portlet render request - * @param errors validation errors holder - * @param page number of page to show - * @return the prepared form view - * @throws Exception in case of invalid state or arguments - */ - protected final ModelAndView showPage(RenderRequest request, BindException errors, int page) - throws Exception { - - if (page >= 0 && page < getPageCount(request, errors.getTarget())) { - if (logger.isDebugEnabled()) { - logger.debug("Showing wizard page " + page + " for form bean '" + getCommandName() + "'"); - } - - // Set page session attribute, expose overriding request attribute. - Integer pageInteger = new Integer(page); - String pageAttrName = getPageSessionAttributeName(request); - if (isSessionForm()) { - if (logger.isDebugEnabled()) { - logger.debug("Setting page session attribute [" + pageAttrName + "] to: " + pageInteger); - } - request.getPortletSession().setAttribute(pageAttrName, pageInteger); - } - request.setAttribute(pageAttrName, pageInteger); - - // Set page request attribute for evaluation by views. - Map controlModel = new HashMap(); - if (this.pageAttribute != null) { - controlModel.put(this.pageAttribute, new Integer(page)); - } - String viewName = getViewName(request, errors.getTarget(), page); - return showForm(request, errors, viewName, controlModel); - } - - else { - throw new PortletException("Invalid wizard page number: " + page); - } - } - - /** - * Return the page count for this wizard form controller. - *

The default implementation delegates to {@link #getPageCount()}. - * Can be overridden to dynamically adapt the page count. - * @param request current portlet request - * @param command the command object as returned by formBackingObject - * @return the current page count - * @see #getPageCount - */ - protected int getPageCount(PortletRequest request, Object command) { - return getPageCount(); - } - - /** - * Return the name of the view for the specified page of this wizard form controller. - *

The default implementation takes the view name from the {@link #getPages()} array. - * Can be overridden to dynamically switch the page view or to return view names - * for dynamically defined pages. - * @param request current portlet request - * @param command the command object as returned by {@code formBackingObject} - * @return the current page count - * @see #getPageCount - */ - protected String getViewName(PortletRequest request, Object command, int page) { - return getPages()[page]; - } - - /** - * Return the initial page of the wizard, i.e. the page shown at wizard startup. - *

The default implementation delegates to {@link #getInitialPage(PortletRequest)}. - * @param request current portlet request - * @param command the command object as returned by {@code formBackingObject} - * @return the initial page number - * @see #getInitialPage(PortletRequest) - * @see #formBackingObject - */ - protected int getInitialPage(PortletRequest request, Object command) { - return getInitialPage(request); - } - - /** - * Return the initial page of the wizard, i.e. the page shown at wizard startup. - *

The default implementation returns 0 for first page. - * @param request current portlet request - * @return the initial page number - */ - protected int getInitialPage(PortletRequest request) { - return 0; - } - - /** - * Return the name of the PortletSession attribute that holds the page object - * for this wizard form controller. - *

The default implementation delegates to the {@code getPageSessionAttributeName} - * version without arguments. - * @param request current portlet request - * @return the name of the form session attribute, or null if not in session form mode - * @see #getPageSessionAttributeName - * @see #getFormSessionAttributeName - * @see javax.portlet.PortletSession#getAttribute - */ - protected String getPageSessionAttributeName(PortletRequest request) { - return getPageSessionAttributeName(); - } - - /** - * Return the name of the PortletSession attribute that holds the page object - * for this wizard form controller. - *

Default is an internal name, of no relevance to applications, as the form - * session attribute is not usually accessed directly. Can be overridden to use - * an application-specific attribute name, which allows other code to access - * the session attribute directly. - * @return the name of the page session attribute - * @see #getFormSessionAttributeName - * @see javax.portlet.PortletSession#getAttribute - */ - protected String getPageSessionAttributeName() { - return getClass().getName() + ".PAGE." + getCommandName(); - } - - /** - * Pass the page number to the render phase by setting a render parameter. - * This method may not be called when the action calls - * {@link javax.portlet.ActionResponse#sendRedirect(String)}. - * @param response the current action response - * @param page the page number - * @see ActionResponse#setRenderParameter - */ - protected void setPageRenderParameter(ActionResponse response, int page) { - if (logger.isDebugEnabled()) - logger.debug("Setting page number render parameter [" + PARAM_PAGE + "] to [" + page + "]"); - try { - response.setRenderParameter(PARAM_PAGE, new Integer(page).toString()); - } - catch (IllegalStateException ex) { - // ignore in case sendRedirect was already set - } - } - - /** - * Pass the the parameter that indicates the target page of the request - * forward to the render phase. If the {@code getTargetPage} method - * was overridden, this may need to be overriden as well. - * @param request the current action request - * @param response the current action response - * @see #PARAM_TARGET - * @see #getTargetPage(PortletRequest, int) - * @see #getTargetPage(PortletRequest, Object, Errors, int) - * @see ActionResponse#setRenderParameter - */ - protected void setTargetRenderParameter(ActionRequest request, ActionResponse response) { - try { - Map params = PortletUtils.getParametersStartingWith(request, PARAM_TARGET); - for (Map.Entry entry : params.entrySet()) { - String param = PARAM_TARGET + entry.getKey(); - Object value = entry.getValue(); - if (logger.isDebugEnabled()) { - logger.debug("Setting target render parameter [" + param + "]"); - } - if (value instanceof String) { - response.setRenderParameter(param, (String) value); - } - else if (value instanceof String[]) { - response.setRenderParameter(param, (String[]) value); - } - } - } - catch (IllegalStateException ex) { - // ignore in case sendRedirect was already set - } - } - - /** - * Pass the the parameter that indicates a finish request forward to the - * render phase. If the {@code isFinishRequest} method - * was overridden, this may need to be overriden as well. - * @param request the current action request - * @param response the current action response - * @see #PARAM_FINISH - * @see #isFinishRequest - * @see ActionResponse#setRenderParameter - */ - protected void setFinishRenderParameter(ActionRequest request, ActionResponse response) { - if (logger.isDebugEnabled()) - logger.debug("Setting cancel render parameter [" + PARAM_FINISH + "]"); - try { - String name = PortletUtils.getSubmitParameter(request, PARAM_FINISH); - if (name != null) - response.setRenderParameter(name, request.getParameter(name)); - } - catch (IllegalStateException ex) { - // ignore in case sendRedirect was already set - } - } - - /** - * Pass the the parameter that indicates a cancel request forward to the - * render phase. If the {@code isCancelRequest} method - * was overridden, this may need to be overriden as well. - * @param request the current action request - * @param response the current action response - * @see #PARAM_CANCEL - * @see #isCancelRequest - * @see ActionResponse#setRenderParameter - */ - protected void setCancelRenderParameter(ActionRequest request, ActionResponse response) { - if (logger.isDebugEnabled()) - logger.debug("Setting cancel render parameter [" + PARAM_CANCEL + "]"); - try { - String name = PortletUtils.getSubmitParameter(request, PARAM_CANCEL); - if (name != null) - response.setRenderParameter(name, request.getParameter(name)); - } - catch (IllegalStateException ex) { - // ignore in case sendRedirect was already set - } - } - - /** - * Handle an invalid submit request, e.g. when in session form mode but no form object - * was found in the session (like in case of an invalid resubmit by the browser). - *

The default implementation for wizard form controllers simply shows the initial page - * of a new wizard form. If you want to show some "invalid submit" message, you need - * to override this method. - * @param request current portlet render request - * @param response current portlet render response - * @return a prepared view, or null if handled directly - * @throws Exception in case of errors - * @see #showNewForm - * @see #setBindOnNewForm - * @see #handleInvalidSubmit - */ - @Override - protected ModelAndView renderInvalidSubmit(RenderRequest request, RenderResponse response) - throws Exception { - - return showNewForm(request, response); - } - - /** - * Handle an invalid submit request, e.g. when in session form mode but no form object - * was found in the session (like in case of an invalid resubmit by the browser). - *

The default implementation for wizard form controllers simply shows the initial page - * of a new wizard form, so here in the action phase this method does nothing. If you - * want to take some action on an invalid submit, you need to override this method. - * @param request current portlet action request - * @param response current portlet action response - * @throws Exception in case of errors - * @see #renderInvalidSubmit - */ - @Override - protected void handleInvalidSubmit(ActionRequest request, ActionResponse response) throws Exception { - } - - /** - * Apply wizard workflow: finish, cancel, page change. - * @see #processFormSubmission - */ - @Override - protected final ModelAndView renderFormSubmission(RenderRequest request, RenderResponse response, Object command, BindException errors) - throws Exception { - - int currentPage = getCurrentPage(request); - String pageAttrName = getPageSessionAttributeName(request); - request.setAttribute(pageAttrName, new Integer(currentPage)); - - // cancel? - if (isCancelRequest(request)) { - if (logger.isDebugEnabled()) { - logger.debug("Cancelling wizard for form bean '" + getCommandName() + "'"); - } - return renderCancel(request, response, command, errors); - } - - // finish? - if (isFinishRequest(request)) { - if (logger.isDebugEnabled()) { - logger.debug("Finishing wizard for form bean '" + getCommandName() + "'"); - } - return renderValidatePagesAndFinish(request, response, command, errors, currentPage); - } - - // Normal submit: show specified target page. - int targetPage = getTargetPage(request, command, errors, currentPage); - if (logger.isDebugEnabled()) { - logger.debug("Target page " + targetPage + " requested"); - } - if (targetPage != currentPage) { - if (!errors.hasErrors() || (this.allowDirtyBack && targetPage < currentPage) || - (this.allowDirtyForward && targetPage > currentPage)) { - // Allowed to go to target page. - return showPage(request, errors, targetPage); - } - } - - // Show current page again - return showPage(request, errors, currentPage); - } - - - /** - * Apply wizard workflow: finish, cancel, page change. - * @see #renderFormSubmission - */ - @Override - protected final void processFormSubmission( - ActionRequest request, ActionResponse response, Object command, BindException errors) - throws Exception { - - int currentPage = getCurrentPage(request); - // Remove page session attribute, provide copy as request attribute. - String pageAttrName = getPageSessionAttributeName(request); - if (isSessionForm()) { - if (logger.isDebugEnabled()) { - logger.debug("Removing page session attribute [" + pageAttrName + "]"); - } - request.getPortletSession().removeAttribute(pageAttrName); - } - request.setAttribute(pageAttrName, new Integer(currentPage)); - - // cancel? - if (isCancelRequest(request)) { - if (logger.isDebugEnabled()) { - logger.debug("Cancelling wizard for form bean '" + getCommandName() + "'"); - } - setPageRenderParameter(response, currentPage); - setCancelRenderParameter(request, response); - processCancel(request, response, command, errors); - return; - } - - // finish? - if (isFinishRequest(request)) { - if (logger.isDebugEnabled()) { - logger.debug("Finishing wizard for form bean '" + getCommandName() + "'"); - } - if (!isRedirectAction()) { - setPageRenderParameter(response, currentPage); - setFinishRenderParameter(request, response); - } - validatePagesAndFinish(request, response, command, errors, currentPage); - return; - } - - // Normal submit: validate current page - if (!suppressValidation(request)) { - if (logger.isDebugEnabled()) { - logger.debug("Validating wizard page " + currentPage + " for form bean '" + getCommandName() + "'"); - } - validatePage(command, errors, currentPage, false); - } - - setPageRenderParameter(response, currentPage); - setTargetRenderParameter(request, response); - passRenderParameters(request, response); - - // Give subclasses a change to perform custom post-procession - // of the current page and its command object. - postProcessPage(request, command, errors, currentPage); - - } - - /** - * Return the current page number. Used by {@link #processFormSubmission}. - *

The default implementation checks the page session attribute. - * Subclasses can override this for customized page determination. - * @param request current portlet request - * @return the current page number - * @see #getPageSessionAttributeName() - */ - protected int getCurrentPage(PortletRequest request) { - // Check for overriding attribute in request. - String pageAttrName = getPageSessionAttributeName(request); - Integer pageAttr = (Integer) request.getAttribute(pageAttrName); - if (pageAttr != null) { - return pageAttr.intValue(); - } - // Check for explicit request parameter. - String pageParam = request.getParameter(PARAM_PAGE); - if (pageParam != null) { - return Integer.parseInt(pageParam); - } - // Check for original attribute in session. - if (isSessionForm()) { - pageAttr = (Integer) request.getPortletSession().getAttribute(pageAttrName); - if (pageAttr != null) { - return pageAttr.intValue(); - } - } - throw new IllegalStateException("Page attribute [" + pageAttrName + "] neither found in session nor in request"); - } - - /** - * Determine whether the incoming request is a request to finish the - * processing of the current form. - *

By default, this method returns {@code true} if a parameter - * matching the "_finish" key is present in the request, otherwise it - * returns {@code false}. Subclasses may override this method - * to provide custom logic to detect a finish request. - *

The parameter is recognized both when sent as a plain parameter - * ("_finish") or when triggered by an image button ("_finish.x"). - * @param request current portlet request - * @return whether the request indicates to finish form processing - * @see #PARAM_FINISH - */ - protected boolean isFinishRequest(PortletRequest request) { - return PortletUtils.hasSubmitParameter(request, PARAM_FINISH); - } - - /** - * Determine whether the incoming request is a request to cancel the - * processing of the current form. - *

By default, this method returns {@code true} if a parameter - * matching the "_cancel" key is present in the request, otherwise it - * returns {@code false}. Subclasses may override this method - * to provide custom logic to detect a cancel request. - *

The parameter is recognized both when sent as a plain parameter - * ("_cancel") or when triggered by an image button ("_cancel.x"). - * @param request current portlet request - * @return whether the request indicates to cancel form processing - * @see #PARAM_CANCEL - */ - protected boolean isCancelRequest(PortletRequest request) { - return PortletUtils.hasSubmitParameter(request, PARAM_CANCEL); - } - - /** - * Return the target page specified in the request. - *

The default implementation delegates to {@link #getTargetPage(PortletRequest, int)}. - * Subclasses can override this for customized target page determination. - * @param request current portlet request - * @param command form object with request parameters bound onto it - * @param errors validation errors holder - * @param currentPage the current page, to be returned as fallback - * if no target page specified - * @return the page specified in the request, or current page if not found - * @see #getTargetPage(PortletRequest, int) - */ - protected int getTargetPage(PortletRequest request, Object command, Errors errors, int currentPage) { - return getTargetPage(request, currentPage); - } - - /** - * Return the target page specified in the request. - *

The default implementation examines "_target" parameter (e.g. "_target1"). - * Subclasses can override this for customized target page determination. - * @param request current portlet request - * @param currentPage the current page, to be returned as fallback - * if no target page specified - * @return the page specified in the request, or current page if not found - * @see #PARAM_TARGET - */ - protected int getTargetPage(PortletRequest request, int currentPage) { - return PortletUtils.getTargetPage(request, PARAM_TARGET, currentPage); - } - - /** - * Validate all pages and process finish. - * If there are page validation errors, show the corresponding view page. - * @see #validatePagesAndFinish - */ - private ModelAndView renderValidatePagesAndFinish( - RenderRequest request, RenderResponse response, Object command, BindException errors, int currentPage) - throws Exception { - - // In case of any errors -> show current page. - if (errors.hasErrors()) - return showPage(request, errors, currentPage); - - // No remaining errors -> proceed with finish. - return renderFinish(request, response, command, errors); - } - - /** - * Validate all pages and process finish. - * If there are page validation errors, show the corresponding view page. - * @see #renderValidatePagesAndFinish - */ - private void validatePagesAndFinish( - ActionRequest request, ActionResponse response, Object command, BindException errors, int currentPage) - throws Exception { - - // In case of binding errors -> show current page. - if (errors.hasErrors()) { - setPageRenderParameter(response, currentPage); - passRenderParameters(request, response); - return; - } - - if (!suppressValidation(request)) { - // In case of remaining errors on a page -> show the page. - for (int page = 0; page < getPageCount(request, command); page++) { - validatePage(command, errors, page, true); - if (errors.hasErrors()) { - setPageRenderParameter(response, currentPage); - passRenderParameters(request, response); - return; - } - } - } - - // No remaining errors -> proceed with finish. - if (!isRedirectAction()) - setPageRenderParameter(response, currentPage); - processFinish(request, response, command, errors); - - } - - /** - * Template method for custom validation logic for individual pages. - * The default implementation calls {@code validatePage(command, errors, page)}. - *

Implementations will typically call fine-granular {@code validateXXX} - * methods of this instance's Validator, combining them to validation of the - * corresponding pages. The Validator's default {@code validate} method - * will not be called by a wizard form controller! - * @param command form object with the current wizard state - * @param errors validation errors holder - * @param page number of page to validate - * @param finish whether this method is called during final revalidation on finish - * (else, it is called for validating the current page) - * @see #validatePage(Object, Errors, int) - * @see org.springframework.validation.Validator#validate - */ - protected void validatePage(Object command, Errors errors, int page, boolean finish) { - validatePage(command, errors, page); - } - - /** - * Template method for custom validation logic for individual pages. - * The default implementation is empty. - *

Implementations will typically call fine-granular validateXXX methods of this - * instance's validator, combining them to validation of the corresponding pages. - * The validator's default {@code validate} method will not be called by a - * wizard form controller! - * @param command form object with the current wizard state - * @param errors validation errors holder - * @param page number of page to validate - * @see org.springframework.validation.Validator#validate - */ - protected void validatePage(Object command, Errors errors, int page) { - } - - /** - * Post-process the given page after binding and validation, potentially - * updating its command object. The passed-in request might contain special - * parameters sent by the page. - *

Only invoked when displaying another page or the same page again, - * not when finishing or cancelling. - * @param request current action request - * @param command form object with request parameters bound onto it - * @param errors validation errors holder - * @param page number of page to post-process - * @throws Exception in case of invalid state or arguments - */ - protected void postProcessPage(ActionRequest request, Object command, Errors errors, int page) - throws Exception { - } - - /** - * Template method for the render phase of the finish action of this wizard. - *

The default implementation throws a PortletException, saying that a finish - * render request is not supported by this controller. Thus, you do not need to - * implement this template method if you do not need to render after a finish. - *

Call {@code errors.getModel()} to populate the ModelAndView model - * with the command and the Errors instance, under the specified command name, - * as expected by the "spring:bind" tag. - * @param request current portlet render request - * @param response current portlet render response - * @param command form object with the current wizard state - * @param errors validation errors holder - * @return the finish view - * @throws Exception in case of invalid state or arguments - * @see #processFinish - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - */ - protected ModelAndView renderFinish( - RenderRequest request, RenderResponse response, Object command, BindException errors) - throws Exception { - - throw new PortletException("Wizard form controller class [" + getClass().getName() + "] does not support a finish render request"); - } - - /** - * Template method for the action phase of the finish action of this wizard. - *

The default implementation throws a PortletException, saying that a finish - * action request is not supported by this controller. You will almost certainly - * need to override this method. - * @param request current portlet action request - * @param response current portlet action response - * @param command form object with the current wizard state - * @param errors validation errors holder - * @throws Exception in case of invalid state or arguments - * @see #renderFinish - * @see org.springframework.validation.Errors - */ - protected void processFinish( - ActionRequest request, ActionResponse response, Object command, BindException errors) - throws Exception { - - throw new PortletException( - "Wizard form controller class [" + getClass().getName() + "] does not support a finish action request"); - } - - /** - * Template method for the render phase of the cancel action of this wizard. - *

The default implementation throws a PortletException, saying that a cancel - * render request is not supported by this controller. Thus, you do not need to - * implement this template method if you do not support a cancel operation. - *

Call {@code errors.getModel()} to populate the ModelAndView model - * with the command and the Errors instance, under the specified command name, - * as expected by the "spring:bind" tag. - * @param request current portlet render request - * @param response current portlet render response - * @param command form object with the current wizard state - * @param errors Errors instance containing errors - * @return the cancellation view - * @throws Exception in case of invalid state or arguments - * @see #processCancel - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - */ - protected ModelAndView renderCancel( - RenderRequest request, RenderResponse response, Object command, BindException errors) - throws Exception { - - throw new PortletException( - "Wizard form controller class [" + getClass().getName() + "] does not support a cancel render request"); - } - - /** - * Template method for the action phase of the cancel action of this wizard. - *

The default implementation throws a PortletException, saying that a cancel - * action request is not supported by this controller. Thus, you do not need to - * implement this template method if you do not support a cancel operation. - * @param request current portlet action request - * @param response current portlet action response - * @param command form object with the current wizard state - * @param errors Errors instance containing errors - * @throws Exception in case of invalid state or arguments - * @see #renderCancel - * @see org.springframework.validation.Errors - */ - protected void processCancel( - ActionRequest request, ActionResponse response, Object command, BindException errors) - throws Exception { - - throw new PortletException( - "Wizard form controller class [" + getClass().getName() + "] does not support a cancel action request"); - } - -} diff --git a/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/BaseCommandController.java b/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/BaseCommandController.java deleted file mode 100644 index d1d1451e59..0000000000 --- a/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/BaseCommandController.java +++ /dev/null @@ -1,666 +0,0 @@ -/* - * Copyright 2002-2012 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.portlet.mvc; - -import javax.portlet.ActionRequest; -import javax.portlet.PortletException; -import javax.portlet.PortletRequest; -import javax.portlet.PortletSession; -import javax.portlet.RenderRequest; - -import org.springframework.beans.BeanUtils; -import org.springframework.beans.PropertyEditorRegistrar; -import org.springframework.validation.BindException; -import org.springframework.validation.BindingErrorProcessor; -import org.springframework.validation.MessageCodesResolver; -import org.springframework.validation.ValidationUtils; -import org.springframework.validation.Validator; -import org.springframework.web.bind.support.WebBindingInitializer; -import org.springframework.web.portlet.bind.PortletRequestDataBinder; -import org.springframework.web.portlet.context.PortletWebRequest; -import org.springframework.web.portlet.handler.PortletSessionRequiredException; - -/** - *

Controller implementation which creates an object (the command object) on - * receipt of a request and attempts to populate this object with request parameters.

- * - *

This controller is the base for all controllers wishing to populate - * JavaBeans based on request parameters, validate the content of such - * JavaBeans using {@link Validator Validators} and use custom editors (in the form of - * {@link java.beans.PropertyEditor PropertyEditors}) to transform - * objects into strings and vice versa, for example. Three notions are mentioned here:

- * - *

Command class:
- * An instance of the command class will be created for each request and populated - * with request parameters. A command class can basically be any Java class; the only - * requirement is a no-arg constructor. The command class should preferably be a - * JavaBean in order to be able to populate bean properties with request parameters.

- * - *

Populating using request parameters and PropertyEditors:
- * Upon receiving a request, any BaseCommandController will attempt to fill the - * command object using the request parameters. This is done using the typical - * and well-known JavaBeans property notation. When a request parameter named - * {@code 'firstName'} exists, the framework will attempt to call - * {@code setFirstName([value])} passing the value of the parameter. Nested properties - * are of course supported. For instance a parameter named {@code 'address.city'} - * will result in a {@code getAddress().setCity([value])} call on the - * command class.

- * - *

It's important to realize that you are not limited to String arguments in - * your JavaBeans. Using the PropertyEditor-notion as supplied by the - * java.beans package, you will be able to transform Strings to Objects and - * the other way around. For instance {@code setLocale(Locale loc)} is - * perfectly possible for a request parameter named {@code locale} having - * a value of {@code en}, as long as you register the appropriate - * PropertyEditor in the Controller (see {@link #initBinder initBinder()} - * for more information on that matter).

- * - *

Validators: - * After the controller has successfully populated the command object with - * parameters from the request, it will use any configured validators to - * validate the object. Validation results will be put in a - * {@link org.springframework.validation.Errors Errors} object which can be - * used in a View to render any input problems.

- * - *

Workflow - * (and that defined by superclass):
- * Since this class is an abstract base class for more specific implementation, - * it does not override the {@code handleRequestInternal()} methods and also has no - * actual workflow. Implementing classes like - * {@link AbstractFormController AbstractFormController}, - * {@link AbstractCommandController AbstractCommandController}, - * {@link SimpleFormController SimpleFormController} and - * {@link AbstractWizardFormController AbstractWizardFormController} - * provide actual functionality and workflow. - * More information on workflow performed by superclasses can be found - * here.

- * - *

Exposed configuration properties - * (and those defined by superclass):
- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
name - * defaultdescription
commandNamecommandthe name to use when binding the instantiated command class - * to the request
commandClassnullthe class to use upon receiving a request and which to fill - * using the request parameters. What object is used and whether - * or not it should be created is defined by extending classes - * and their configuration properties and methods.
validatorsnullArray of Validator beans. The validator will be called at appropriate - * places in the workflow of subclasses (have a look at those for more info) - * to validate the command object.
validatornullShort-form property for setting only one Validator bean (usually passed in - * using a <ref bean="beanId"/> property.
validateOnBindingtrueIndicates whether or not to validate the command object after the - * object has been populated with request parameters.
- *

- * - *

Thanks to Rainer Schmitz and Nick Lothian for their suggestions! - * - * @author Juergen Hoeller - * @author John A. Lewis - * @since 2.0 - * @deprecated as of Spring 3.0, in favor of annotated controllers - */ -@Deprecated -public abstract class BaseCommandController extends AbstractController { - - /** - * Unlike the servlet version of these classes, we have to deal with the - * two-phase nature of the portlet request. To do this, we need to pass - * forward the command object and the bind/validation errors that occured - * on the command object from the action phase to the render phase. - * The only direct way to pass things forward and preserve them for each - * render request is through render parameters, but these are limited to - * String objects and we need to pass more complicated objects. The only - * other way to do this is in the session. The bad thing about using the - * session is that we have no way of knowing when we are done re-rendering - * the request and so we don't know when we can remove the objects from - * the session. So we will end up polluting the session with old objects - * when we finally leave the render of this controller and move on to - * somthing else. To minimize the pollution, we will use a static string - * value as the session attribute name. At least this way we are only ever - * leaving one orphaned set behind. The methods that return these names - * can be overridden if you want to use a different method, but be aware - * of the session pollution that may occur. - */ - private static final String RENDER_COMMAND_SESSION_ATTRIBUTE = - "org.springframework.web.portlet.mvc.RenderCommand"; - - private static final String RENDER_ERRORS_SESSION_ATTRIBUTE = - "org.springframework.web.portlet.mvc.RenderErrors"; - - public static final String DEFAULT_COMMAND_NAME = "command"; - - - private String commandName = DEFAULT_COMMAND_NAME; - - private Class commandClass; - - private Validator[] validators; - - private boolean validateOnBinding = true; - - private MessageCodesResolver messageCodesResolver; - - private BindingErrorProcessor bindingErrorProcessor; - - private PropertyEditorRegistrar[] propertyEditorRegistrars; - - private WebBindingInitializer webBindingInitializer; - - - /** - * Set the name of the command in the model. - * The command object will be included in the model under this name. - */ - public final void setCommandName(String commandName) { - this.commandName = commandName; - } - - /** - * Return the name of the command in the model. - */ - public final String getCommandName() { - return this.commandName; - } - - /** - * Set the command class for this controller. - * An instance of this class gets populated and validated on each request. - */ - public final void setCommandClass(Class commandClass) { - this.commandClass = commandClass; - } - - /** - * Return the command class for this controller. - */ - public final Class getCommandClass() { - return this.commandClass; - } - - /** - * Set the primary Validator for this controller. The Validator - * must support the specified command class. If there are one - * or more existing validators set already when this method is - * called, only the specified validator will be kept. Use - * {@link #setValidators(Validator[])} to set multiple validators. - */ - public final void setValidator(Validator validator) { - this.validators = new Validator[] {validator}; - } - - /** - * @return the primary Validator for this controller. - */ - public final Validator getValidator() { - return (this.validators != null && this.validators.length > 0 ? this.validators[0] : null); - } - - /** - * Set the Validators for this controller. - * The Validator must support the specified command class. - */ - public final void setValidators(Validator[] validators) { - this.validators = validators; - } - - /** - * Return the Validators for this controller. - */ - public final Validator[] getValidators() { - return this.validators; - } - - /** - * Set if the Validator should get applied when binding. - */ - public final void setValidateOnBinding(boolean validateOnBinding) { - this.validateOnBinding = validateOnBinding; - } - - /** - * Return if the Validator should get applied when binding. - */ - public final boolean isValidateOnBinding() { - return this.validateOnBinding; - } - - /** - * Set the strategy to use for resolving errors into message codes. - * Applies the given strategy to all data binders used by this controller. - *

Default is {@code null}, i.e. using the default strategy of the data binder. - * @see #createBinder - * @see org.springframework.validation.DataBinder#setMessageCodesResolver - */ - public final void setMessageCodesResolver(MessageCodesResolver messageCodesResolver) { - this.messageCodesResolver = messageCodesResolver; - } - - /** - * Return the strategy to use for resolving errors into message codes (if any). - */ - public final MessageCodesResolver getMessageCodesResolver() { - return this.messageCodesResolver; - } - - /** - * Set the strategy to use for processing binding errors, that is, - * required field errors and {@code PropertyAccessException}s. - *

Default is {@code null}, i.e. using the default strategy of - * the data binder. - * @see #createBinder - * @see org.springframework.validation.DataBinder#setBindingErrorProcessor - */ - public final void setBindingErrorProcessor(BindingErrorProcessor bindingErrorProcessor) { - this.bindingErrorProcessor = bindingErrorProcessor; - } - - /** - * Return the strategy to use for processing binding errors (if any). - */ - public final BindingErrorProcessor getBindingErrorProcessor() { - return this.bindingErrorProcessor; - } - - /** - * Specify a single PropertyEditorRegistrar to be applied - * to every DataBinder that this controller uses. - *

Allows for factoring out the registration of PropertyEditors - * to separate objects, as an alternative to {@code initBinder}. - * @see #initBinder - */ - public final void setPropertyEditorRegistrar(PropertyEditorRegistrar propertyEditorRegistrar) { - this.propertyEditorRegistrars = new PropertyEditorRegistrar[] {propertyEditorRegistrar}; - } - - /** - * Specify one or more PropertyEditorRegistrars to be applied - * to every DataBinder that this controller uses. - *

Allows for factoring out the registration of PropertyEditors - * to separate objects, as alternative to {@code initBinder}. - * @see #initBinder - */ - public final void setPropertyEditorRegistrars(PropertyEditorRegistrar[] propertyEditorRegistrars) { - this.propertyEditorRegistrars = propertyEditorRegistrars; - } - - /** - * Return the PropertyEditorRegistrars (if any) to be applied - * to every DataBinder that this controller uses. - */ - public final PropertyEditorRegistrar[] getPropertyEditorRegistrars() { - return this.propertyEditorRegistrars; - } - - /** - * Specify a WebBindingInitializer which will apply pre-configured - * configuration to every DataBinder that this controller uses. - *

Allows for factoring out the entire binder configuration - * to separate objects, as an alternative to {@link #initBinder}. - */ - public final void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) { - this.webBindingInitializer = webBindingInitializer; - } - - /** - * Return the WebBindingInitializer (if any) which will apply pre-configured - * configuration to every DataBinder that this controller uses. - */ - public final WebBindingInitializer getWebBindingInitializer() { - return this.webBindingInitializer; - } - - - @Override - protected void initApplicationContext() { - if (this.validators != null) { - for (int i = 0; i < this.validators.length; i++) { - if (this.commandClass != null && !this.validators[i].supports(this.commandClass)) - throw new IllegalArgumentException("Validator [" + this.validators[i] + - "] does not support command class [" + - this.commandClass.getName() + "]"); - } - } - } - - - /** - * Retrieve a command object for the given request. - *

The default implementation calls {@link #createCommand()}. - * Subclasses can override this. - * @param request current portlet request - * @return object command to bind onto - * @see #createCommand - */ - protected Object getCommand(PortletRequest request) throws Exception { - return createCommand(); - } - - /** - * Create a new command instance for the command class of this controller. - *

This implementation uses {@code BeanUtils.instantiateClass}, - * so the command needs to have a no-arg constructor (supposed to be - * public, but not required to). - * @return the new command instance - * @throws Exception if the command object could not be instantiated - * @see org.springframework.beans.BeanUtils#instantiateClass(Class) - */ - protected final Object createCommand() throws Exception { - if (this.commandClass == null) { - throw new IllegalStateException("Cannot create command without commandClass being set - " + - "either set commandClass or (in a form controller) override formBackingObject"); - } - if (logger.isDebugEnabled()) { - logger.debug("Creating new command of class [" + this.commandClass.getName() + "]"); - } - return BeanUtils.instantiateClass(this.commandClass); - } - - /** - * Check if the given command object is a valid for this controller, - * i.e. its command class. - * @param command the command object to check - * @return if the command object is valid for this controller - */ - protected final boolean checkCommand(Object command) { - return (this.commandClass == null || this.commandClass.isInstance(command)); - } - - - /** - * Bind the parameters of the given request to the given command object. - * @param request current portlet request - * @param command the command to bind onto - * @return the PortletRequestDataBinder instance for additional custom validation - * @throws Exception in case of invalid state or arguments - */ - protected final PortletRequestDataBinder bindAndValidate(PortletRequest request, Object command) - throws Exception { - - PortletRequestDataBinder binder = createBinder(request, command); - if (!suppressBinding(request)) { - binder.bind(request); - BindException errors = new BindException(binder.getBindingResult()); - onBind(request, command, errors); - if (this.validators != null && isValidateOnBinding() && !suppressValidation(request)) { - for (int i = 0; i < this.validators.length; i++) { - ValidationUtils.invokeValidator(this.validators[i], command, errors); - } - } - onBindAndValidate(request, command, errors); - } - return binder; - } - - /** - * Return whether to suppress binding for the given request. - *

The default implementation always returns {@code false}. - * Can be overridden in subclasses to suppress validation: - * for example, if a special request parameter is set. - * @param request current portlet request - * @return whether to suppress binding for the given request - * @see #suppressValidation - */ - protected boolean suppressBinding(PortletRequest request) { - return false; - } - - /** - * Create a new binder instance for the given command and request. - *

Called by {@code bindAndValidate}. Can be overridden to plug in - * custom PortletRequestDataBinder instances. - *

The default implementation creates a standard PortletRequestDataBinder and - * invokes {@code prepareBinder} and {@code initBinder}. - *

Note that neither {@code prepareBinder} nor {@code initBinder} - * will be invoked automatically if you override this method! Call those methods - * at appropriate points of your overridden method. - * @param request current portlet request - * @param command the command to bind onto - * @return the new binder instance - * @throws Exception in case of invalid state or arguments - * @see #bindAndValidate - * @see #prepareBinder - * @see #initBinder - */ - protected PortletRequestDataBinder createBinder(PortletRequest request, Object command) - throws Exception { - - PortletRequestDataBinder binder = new PortletRequestDataBinder(command, getCommandName()); - prepareBinder(binder); - initBinder(request, binder); - return binder; - } - - /** - * Prepare the given binder, applying the specified MessageCodesResolver, - * BindingErrorProcessor and PropertyEditorRegistrars (if any). - * Called by {@code createBinder}. - * @param binder the new binder instance - * @see #createBinder - * @see #setMessageCodesResolver - * @see #setBindingErrorProcessor - */ - protected final void prepareBinder(PortletRequestDataBinder binder) { - if (useDirectFieldAccess()) { - binder.initDirectFieldAccess(); - } - if (this.messageCodesResolver != null) { - binder.setMessageCodesResolver(this.messageCodesResolver); - } - if (this.bindingErrorProcessor != null) { - binder.setBindingErrorProcessor(this.bindingErrorProcessor); - } - if (this.propertyEditorRegistrars != null) { - for (int i = 0; i < this.propertyEditorRegistrars.length; i++) { - this.propertyEditorRegistrars[i].registerCustomEditors(binder); - } - } - } - - /** - * Determine whether to use direct field access instead of bean property access. - * Applied by {@code prepareBinder}. - *

The default is {@code false}. Can be overridden in subclasses. - * @see #prepareBinder - * @see org.springframework.validation.DataBinder#initDirectFieldAccess() - */ - protected boolean useDirectFieldAccess() { - return false; - } - - /** - * Initialize the given binder instance, for example with custom editors. - * Called by {@code createBinder}. - *

This method allows you to register custom editors for certain fields of your - * command class. For instance, you will be able to transform Date objects into a - * String pattern and back, in order to allow your JavaBeans to have Date properties - * and still be able to set and display them in an HTML interface. - *

The default implementation is empty. - * @param request current portlet request - * @param binder new binder instance - * @throws Exception in case of invalid state or arguments - * @see #createBinder - * @see org.springframework.validation.DataBinder#registerCustomEditor - * @see org.springframework.beans.propertyeditors.CustomDateEditor - */ - protected void initBinder(PortletRequest request, PortletRequestDataBinder binder) throws Exception { - if (this.webBindingInitializer != null) { - this.webBindingInitializer.initBinder(binder, new PortletWebRequest(request)); - } - } - - /** - * Callback for custom post-processing in terms of binding. - * Called on each submit, after standard binding but before validation. - *

The default implementation delegates to {@code onBind(request, command)}. - * @param request current portlet request - * @param command the command object to perform further binding on - * @param errors validation errors holder, allowing for additional - * custom registration of binding errors - * @throws Exception in case of invalid state or arguments - * @see #bindAndValidate - * @see #onBind(PortletRequest, Object) - */ - protected void onBind(PortletRequest request, Object command, BindException errors) throws Exception { - onBind(request, command); - } - - /** - * Callback for custom post-processing in terms of binding. - * Called by the default implementation of the {@code onBind} version with - * all parameters, after standard binding but before validation. - *

The default implementation is empty. - * @param request current portlet request - * @param command the command object to perform further binding on - * @throws Exception in case of invalid state or arguments - * @see #onBind(PortletRequest, Object, BindException) - */ - protected void onBind(PortletRequest request, Object command) throws Exception { - } - - /** - * Return whether to suppress validation for the given request. - *

The default implementation always returns {@code false}. - * Can be overridden in subclasses to suppress validation: - * for example, if a special request parameter is set. - * @param request current portlet request - * @return whether to suppress validation for the given request - */ - protected boolean suppressValidation(PortletRequest request) { - return false; - } - - /** - * Callback for custom post-processing in terms of binding and validation. - * Called on each submit, after standard binding and validation, - * but before error evaluation. - *

The default implementation is empty. - * @param request current portlet request - * @param command the command object, still allowing for further binding - * @param errors validation errors holder, allowing for additional - * custom validation - * @throws Exception in case of invalid state or arguments - * @see #bindAndValidate - * @see org.springframework.validation.Errors - */ - protected void onBindAndValidate(PortletRequest request, Object command, BindException errors) - throws Exception { - } - - - /** - * Return the name of the session attribute that holds - * the render phase command object for this form controller. - * @return the name of the render phase command object session attribute - * @see javax.portlet.PortletSession#getAttribute - */ - protected String getRenderCommandSessionAttributeName() { - return RENDER_COMMAND_SESSION_ATTRIBUTE; - } - - /** - * Return the name of the session attribute that holds - * the render phase command object for this form controller. - * @return the name of the render phase command object session attribute - * @see javax.portlet.PortletSession#getAttribute - */ - protected String getRenderErrorsSessionAttributeName() { - return RENDER_ERRORS_SESSION_ATTRIBUTE; - } - - /** - * Get the command object cached for the render phase. - * @see #getRenderErrors - * @see #getRenderCommandSessionAttributeName - * @see #setRenderCommandAndErrors - */ - protected final Object getRenderCommand(RenderRequest request) throws PortletException { - PortletSession session = request.getPortletSession(false); - if (session == null) { - throw new PortletSessionRequiredException("Could not obtain portlet session"); - } - Object command = session.getAttribute(getRenderCommandSessionAttributeName()); - if (command == null) { - throw new PortletSessionRequiredException("Could not obtain command object from portlet session"); - } - return command; - } - - /** - * Get the bind and validation errors cached for the render phase. - * @see #getRenderCommand - * @see #getRenderErrorsSessionAttributeName - * @see #setRenderCommandAndErrors - */ - protected final BindException getRenderErrors(RenderRequest request) throws PortletException { - PortletSession session = request.getPortletSession(false); - if (session == null) { - throw new PortletSessionRequiredException("Could not obtain portlet session"); - } - BindException errors = (BindException) session.getAttribute(getRenderErrorsSessionAttributeName()); - if (errors == null) { - throw new PortletSessionRequiredException("Could not obtain errors object from portlet session"); - } - return errors; - } - - /** - * Set the command object and errors object for the render phase. - * @param request the current action request - * @param command the command object to preserve for the render phase - * @param errors the errors from binding and validation to preserve for the render phase - * @see #getRenderCommand - * @see #getRenderErrors - * @see #getRenderCommandSessionAttributeName - * @see #getRenderErrorsSessionAttributeName - */ - protected final void setRenderCommandAndErrors( - ActionRequest request, Object command, BindException errors) throws Exception { - - logger.debug("Storing command and error objects in session for render phase"); - PortletSession session = request.getPortletSession(); - session.setAttribute(getRenderCommandSessionAttributeName(), command); - session.setAttribute(getRenderErrorsSessionAttributeName(), errors); - } - -} diff --git a/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/SimpleFormController.java b/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/SimpleFormController.java deleted file mode 100644 index 980afcd3e9..0000000000 --- a/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/SimpleFormController.java +++ /dev/null @@ -1,562 +0,0 @@ -/* - * Copyright 2002-2012 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.portlet.mvc; - -import java.util.Map; - -import javax.portlet.ActionRequest; -import javax.portlet.ActionResponse; -import javax.portlet.PortletException; -import javax.portlet.PortletRequest; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; - -import org.springframework.validation.BindException; -import org.springframework.validation.Errors; -import org.springframework.web.portlet.ModelAndView; - -/** - *

Concrete FormController implementation that provides configurable - * form and success views, and an onSubmit chain for convenient overriding. - * Automatically resubmits to the form view in case of validation errors, - * and renders the success view in case of a valid submission.

- * - *

The workflow of this Controller does not differ much from the one described - * in the {@link AbstractFormController AbstractFormController}. The difference - * is that you do not need to implement {@link #showForm showForm}, - * {@link #processFormSubmission processFormSubmission}, and - * {@link #renderFormSubmission renderFormSubmission}: A form view and a - * success view can be configured declaratively.

- * - *

This controller is different from it's servlet counterpart in that it must take - * into account the two phases of a portlet request: the action phase and the render - * phase. See the JSR-168 spec for more details on these two phases. - * Be especially aware that the action phase is called only once, but that the - * render phase will be called repeatedly by the portal -- it does this every time - * the page containing the portlet is updated, even if the activity is in some other - * portlet. The main difference in the methods in this class is that the - * {@code onSubmit} methods have all been split into {@code onSubmitAction} - * and {@code onSubmitRender} to account for the two phases.

- * - *

Workflow - * (in addition to the superclass):
- *

    - *
  1. Call to {@link #processFormSubmission processFormSubmission} which inspects - * the {@link org.springframework.validation.Errors Errors} object to see if - * any errors have occurred during binding and validation.
  2. - *
  3. If errors occured, the controller will return the configured formView, - * showing the form again (possibly rendering according error messages).
  4. - *
  5. If {@link #isFormChangeRequest isFormChangeRequest} is overridden and returns - * true for the given request, the controller will return the formView too. - * In that case, the controller will also suppress validation. Before returning the formView, - * the controller will invoke {@link #onFormChange}, giving sub-classes a chance - * to make modification to the command object. - * This is intended for requests that change the structure of the form, - * which should not cause validation and show the form in any case.
  6. - *
  7. If no errors occurred, the controller will call - * {@link #onSubmitAction(ActionRequest, ActionResponse, Object, BindException) onSubmitAction} - * during the action phase and then {@link #onSubmitRender(RenderRequest, RenderResponse, - * Object, BindException) onSubmitRender} during the render phase, which in case of the - * default implementation delegate to {@link #onSubmitAction(Object, BindException) - * onSubmitAction} and {@link #onSubmitRender(Object, BindException) onSubmitRender} - * with just the command object. - * The default implementation of the latter method will return the configured - * {@code successView}. Consider just implementing {@link #doSubmitAction doSubmitAction} - * for simply performing a submit action during the action phase and then rendering - * the success view during the render phase.
  8. - *
- *

- * - *

The submit behavior can be customized by overriding one of the - * {@link #onSubmitAction onSubmitAction} or {@link #onSubmitRender onSubmitRender} - * methods. Submit actions can also perform custom validation if necessary - * (typically database-driven checks), calling {@link #showForm(RenderRequest, - * RenderResponse, BindException) showForm} in case of validation errors to show - * the form view again. You do not have to override both the {@code onSubmitAction} and - * {@code onSubmitRender} methods at a given level unless you truly have custom logic to - * perform in both.

- * - *

WARNING: Make sure that any one-time system updates (such as database - * updates or file writes) are performed in either an {@link #onSubmitAction onSubmitAction} - * method or the {@link #doSubmitAction doSubmitAction} method. Logic in the - * {@link #onSubmitRender onSubmitRender} methods may be executed repeatedly by - * the portal whenever the page containing the portlet is updated.

- * - *

Exposed configuration properties - * (and those defined by superclass):
- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
namedefaultdescription
formViewnullIndicates what view to use when the user asks for a new form - * or when validation errors have occurred on form submission.
successViewnullIndicates what view to use when successful form submissions have - * occurred. Such a success view could e.g. display a submission summary. - * More sophisticated actions can be implemented by overriding one of - * the {@link #onSubmitRender(Object) onSubmitRender()} methods.
- *

- * - *

Parameters indicated with {@code setPassRenderParameters} will be - * preserved if the form has errors or if a form change request occurs. - * If there are render parameters you need in {@code onSubmitRender}, - * then you need to pass those forward from {@code onSubmitAction}. - * - *

Thanks to Rainer Schmitz and Nick Lothian for their suggestions! - * - * @author John A. Lewis - * @author Juergen Hoeller - * @author Rob Harrop - * @since 2.0 - * @deprecated as of Spring 3.0, in favor of annotated controllers - */ -@Deprecated -public class SimpleFormController extends AbstractFormController { - - private String formView; - - private String successView; - - - /** - * Create a new SimpleFormController. - *

Subclasses should set the following properties, either in the constructor - * or via a BeanFactory: commandName, commandClass, sessionForm, formView, - * successView. Note that commandClass doesn't need to be set when overriding - * {@code formBackingObject}, as this determines the class anyway. - * @see #setCommandClass(Class) - * @see #setCommandName(String) - * @see #setSessionForm(boolean) - * @see #setFormView - * @see #setSuccessView - * @see #formBackingObject(PortletRequest) - */ - public SimpleFormController() { - // AbstractFormController sets default cache seconds to 0. - super(); - } - - /** - * Set the name of the view that should be used for form display. - */ - public final void setFormView(String formView) { - this.formView = formView; - } - - /** - * Return the name of the view that should be used for form display. - */ - public final String getFormView() { - return this.formView; - } - - /** - * Set the name of the view that should be shown on successful submit. - */ - public final void setSuccessView(String successView) { - this.successView = successView; - } - - /** - * Return the name of the view that should be shown on successful submit. - */ - public final String getSuccessView() { - return this.successView; - } - - - /** - * This implementation shows the configured form view, delegating to the - * analogous showForm version with a controlModel argument. - *

Can be called within onSubmit implementations, to redirect back to the form - * in case of custom validation errors (i.e. not determined by the validator). - *

Can be overridden in subclasses to show a custom view, writing directly - * to the response or preparing the response before rendering a view. - *

If calling showForm with a custom control model in subclasses, it's preferable - * to override the analogous showForm version with a controlModel argument - * (which will handle both standard form showing and custom form showing then). - * @see #setFormView - * @see #showForm(RenderRequest, RenderResponse, BindException, Map) - */ - @Override - protected ModelAndView showForm(RenderRequest request, RenderResponse response, BindException errors) - throws Exception { - - return showForm(request, response, errors, null); - } - - /** - * This implementation shows the configured form view. - *

Can be called within onSubmit implementations, to redirect back to the form - * in case of custom validation errors (i.e. not determined by the validator). - *

Can be overridden in subclasses to show a custom view, writing directly - * to the response or preparing the response before rendering a view. - * @param request current render request - * @param errors validation errors holder - * @param controlModel model map containing controller-specific control data - * (e.g. current page in wizard-style controllers or special error message) - * @return the prepared form view - * @throws Exception in case of invalid state or arguments - * @see #setFormView - */ - protected ModelAndView showForm(RenderRequest request, RenderResponse response, BindException errors, Map controlModel) - throws Exception { - - return showForm(request, errors, getFormView(), controlModel); - } - - /** - * Create a reference data map for the given request and command, - * consisting of bean name/bean instance pairs as expected by ModelAndView. - *

The default implementation delegates to {@link #referenceData(PortletRequest)}. - * Subclasses can override this to set reference data used in the view. - * @param request current portlet request - * @param command form object with request parameters bound onto it - * @param errors validation errors holder - * @return a Map with reference data entries, or null if none - * @throws Exception in case of invalid state or arguments - * @see ModelAndView - */ - @Override - protected Map referenceData(PortletRequest request, Object command, Errors errors) throws Exception { - return referenceData(request); - } - - /** - * Create a reference data map for the given request. - * Called by referenceData version with all parameters. - *

The default implementation returns {@code null}. - * Subclasses can override this to set reference data used in the view. - * @param request current portlet request - * @return a Map with reference data entries, or null if none - * @throws Exception in case of invalid state or arguments - * @see #referenceData(PortletRequest, Object, Errors) - * @see ModelAndView - */ - protected Map referenceData(PortletRequest request) throws Exception { - return null; - } - - - /** - * This implementation calls {@code showForm} in case of errors, - * and delegates to {@code onSubmitRender}'s full version else. - *

This can only be overridden to check for an action that should be executed - * without respect to binding errors, like a cancel action. To just handle successful - * submissions without binding errors, override one of the {@code onSubmitRender} - * methods. - * @see #showForm(RenderRequest, RenderResponse, BindException) - * @see #onSubmitRender(RenderRequest, RenderResponse, Object, BindException) - * @see #onSubmitRender(Object, BindException) - * @see #onSubmitRender(Object) - * @see #processFormSubmission(ActionRequest, ActionResponse, Object, BindException) - */ - @Override - protected ModelAndView renderFormSubmission(RenderRequest request, RenderResponse response, Object command, BindException errors) - throws Exception { - - if (errors.hasErrors() || isFormChangeRequest(request)) { - return showForm(request, response, errors); - } - else { - return onSubmitRender(request, response, command, errors); - } - } - - /** - * This implementation does nothing in case of errors, - * and delegates to {@code onSubmitAction}'s full version else. - *

This can only be overridden to check for an action that should be executed - * without respect to binding errors, like a cancel action. To just handle successful - * submissions without binding errors, override one of the {@code onSubmitAction} - * methods or {@code doSubmitAction}. - * @see #showForm - * @see #onSubmitAction(ActionRequest, ActionResponse, Object, BindException) - * @see #onSubmitAction(Object, BindException) - * @see #onSubmitAction(Object) - * @see #doSubmitAction(Object) - * @see #renderFormSubmission(RenderRequest, RenderResponse, Object, BindException) - */ - @Override - protected void processFormSubmission( - ActionRequest request, ActionResponse response, Object command, BindException errors) - throws Exception { - - if (errors.hasErrors()) { - if (logger.isDebugEnabled()) { - logger.debug("Data binding errors: " + errors.getErrorCount()); - } - if (isRedirectAction()) { - setFormSubmit(response); - } - passRenderParameters(request, response); - } - else if (isFormChangeRequest(request)) { - logger.debug("Detected form change request -> routing request to onFormChange"); - if (isRedirectAction()) { - setFormSubmit(response); - } - passRenderParameters(request, response); - onFormChange(request, response, command, errors); - } - else { - logger.debug("No errors - processing submit"); - onSubmitAction(request, response, command, errors); - } - } - - /** - * This implementation delegates to {@link #isFormChangeRequest}: - * A form change request changes the appearance of the form - * and should not get validated but just show the new form. - * @see #isFormChangeRequest - */ - @Override - protected boolean suppressValidation(PortletRequest request) { - return isFormChangeRequest(request); - } - - /** - * Determine whether the given request is a form change request. - * A form change request changes the appearance of the form - * and should always show the new form, without validation. - *

Gets called by {@link #suppressValidation} and {@link #processFormSubmission}. - * Consequently, this single method determines to suppress validation - * and to show the form view in any case. - *

The default implementation returns {@code false}. - * @param request current portlet request - * @return whether the given request is a form change request - * @see #suppressValidation - * @see #processFormSubmission - */ - protected boolean isFormChangeRequest(PortletRequest request) { - return false; - } - - /** - * Called during form submission if {@link #isFormChangeRequest(PortletRequest)} - * returns {@code true}. Allows subclasses to implement custom logic - * to modify the command object to directly modify data in the form. - *

The default implementation delegates to - * {@code onFormChange(request, response, command)}. - * @param request current action request - * @param response current action response - * @param command form object with request parameters bound onto it - * @param errors validation errors holder, allowing for additional - * custom validation - * @throws Exception in case of errors - * @see #isFormChangeRequest(PortletRequest) - * @see #onFormChange(ActionRequest, ActionResponse, Object) - */ - protected void onFormChange(ActionRequest request, ActionResponse response, Object command, BindException errors) - throws Exception { - - onFormChange(request, response, command); - } - - /** - * Simpler {@code onFormChange} variant, called by the full version - * {@code onFormChange(request, response, command, errors)}. - *

The default implementation is empty. - * @param request current action request - * @param response current action response - * @param command form object with request parameters bound onto it - * @throws Exception in case of errors - * @see #onFormChange(ActionRequest, ActionResponse, Object, BindException) - */ - protected void onFormChange(ActionRequest request, ActionResponse response, Object command) - throws Exception { - } - - - /** - * Submit render phase callback with all parameters. Called in case of submit without errors - * reported by the registered validator, or on every submit if no validator. - *

The default implementation delegates to {@link #onSubmitRender(Object, BindException)}. - * For simply performing a submit action and rendering the specified success view, - * do not implement an {@code onSubmitRender} at all. - *

Subclasses can override this to provide custom rendering to display results of - * the action phase. Implementations can also call {@code showForm} to return to the form - * if the {@code onSubmitAction} failed custom validation. Do not implement multiple - * {@code onSubmitRender} methods: In that case, - * just this method will be called by the controller. - *

Call {@code errors.getModel()} to populate the ModelAndView model - * with the command and the Errors instance, under the specified command name, - * as expected by the "spring:bind" tag. - * @param request current render request - * @param response current render response - * @param command form object with request parameters bound onto it - * @param errors Errors instance without errors (subclass can add errors if it wants to) - * @return the prepared model and view - * @throws Exception in case of errors - * @see #onSubmitAction(ActionRequest, ActionResponse, Object, BindException) - * @see #onSubmitRender(Object, BindException) - * @see #doSubmitAction - * @see #showForm - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - */ - protected ModelAndView onSubmitRender(RenderRequest request, RenderResponse response, Object command, BindException errors) - throws Exception { - - return onSubmitRender(command, errors); - } - - /** - * Submit action phase callback with all parameters. Called in case of submit without errors - * reported by the registered validator respectively on every submit if no validator. - *

The default implementation delegates to {@link #onSubmitAction(Object, BindException)}. - * For simply performing a submit action consider implementing {@code doSubmitAction} - * rather than an {@code onSubmitAction} version. - *

Subclasses can override this to provide custom submission handling like storing - * the object to the database. Implementations can also perform custom validation and - * signal the render phase to call {@code showForm} to return to the form. Do not - * implement multiple {@code onSubmitAction} methods: In that case, - * just this method will be called by the controller. - * @param request current action request - * @param response current action response - * @param command form object with request parameters bound onto it - * @param errors Errors instance without errors (subclass can add errors if it wants to) - * @throws Exception in case of errors - * @see #onSubmitRender(RenderRequest, RenderResponse, Object, BindException) - * @see #onSubmitAction(Object, BindException) - * @see #doSubmitAction - * @see org.springframework.validation.Errors - */ - protected void onSubmitAction(ActionRequest request, ActionResponse response, Object command, BindException errors) - throws Exception { - - onSubmitAction(command, errors); - } - - /** - * Simpler {@code onSubmitRender} version. Called by the default implementation - * of the {@code onSubmitRender} version with all parameters. - *

The default implementation calls {@link #onSubmitRender(Object)}, using the - * returned ModelAndView if actually implemented in a subclass. Else, the - * default behavior will apply: rendering the success view with the command - * and Errors instance as model. - *

Subclasses can override this to provide custom submission handling that - * does not need request and response. - *

Call {@code errors.getModel()} to populate the ModelAndView model - * with the command and the Errors instance, under the specified command name, - * as expected by the "spring:bind" tag. - * @param command form object with request parameters bound onto it - * @param errors Errors instance without errors - * @return the prepared model and view, or null - * @throws Exception in case of errors - * @see #onSubmitRender(RenderRequest, RenderResponse, Object, BindException) - * @see #onSubmitRender(Object) - * @see #onSubmitAction(Object, BindException) - * @see #setSuccessView - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - */ - protected ModelAndView onSubmitRender(Object command, BindException errors) throws Exception { - ModelAndView mv = onSubmitRender(command); - if (mv != null) { - // simplest onSubmit version implemented in custom subclass - return mv; - } - else { - // default behavior: render success view - if (getSuccessView() == null) { - throw new PortletException("successView isn't set"); - } - return new ModelAndView(getSuccessView(), errors.getModel()); - } - } - - /** - * Simpler {@code onSubmitAction} version. Called by the default implementation - * of the {@code onSubmitAction} version with all parameters. - *

The default implementation calls {@link #onSubmitAction(Object)}. - *

Subclasses can override this to provide custom submission handling that - * does not need request and response. - * @param command form object with request parameters bound onto it - * @param errors Errors instance without errors - * @throws Exception in case of errors - * @see #onSubmitAction(ActionRequest, ActionResponse, Object, BindException) - * @see #onSubmitAction(Object) - * @see #onSubmitRender(Object, BindException) - * @see org.springframework.validation.Errors - */ - protected void onSubmitAction(Object command, BindException errors) throws Exception { - onSubmitAction(command); - } - - /** - * Simplest {@code onSubmitRender} version. Called by the default implementation - * of the {@code onSubmitRender} version with command and BindException parameters. - *

This implementation returns null as ModelAndView, making the calling - * {@code onSubmitRender} method perform its default rendering of the success view. - *

Subclasses can override this to provide custom submission handling - * that just depends on the command object. - * @param command form object with request parameters bound onto it - * @return the prepared model and view, or null for default (i.e. successView) - * @throws Exception in case of errors - * @see #onSubmitRender(Object, BindException) - * @see #onSubmitAction(Object) - * @see #doSubmitAction - * @see #setSuccessView - */ - protected ModelAndView onSubmitRender(Object command) throws Exception { - return null; - } - - /** - * Simplest {@code onSubmitAction} version. Called by the default implementation - * of the {@code onSubmitAction} version with command and BindException parameters. - *

This implementation calls {@code doSubmitAction}. - *

Subclasses can override this to provide custom submission handling - * that just depends on the command object. - * @param command form object with request parameters bound onto it - * @throws Exception in case of errors - * @see #onSubmitAction(Object, BindException) - * @see #onSubmitRender(Object) - * @see #doSubmitAction - */ - protected void onSubmitAction(Object command) throws Exception { - doSubmitAction(command); - } - - /** - * Template method for submit actions. Called by the default implementation - * of the simplest {@code onSubmitAction} version. - *

This is the preferred submit callback to implement if you want to - * perform an action (like storing changes to the database) and then render - * the success view with the command and Errors instance as model. - * @param command form object with request parameters bound onto it - * @throws Exception in case of errors - * @see #onSubmitAction(Object) - * @see #onSubmitRender(Object) - * @see #setSuccessView - */ - protected void doSubmitAction(Object command) throws Exception { - } - -} diff --git a/spring-webmvc-portlet/src/test/java/org/springframework/web/portlet/DispatcherPortletTests.java b/spring-webmvc-portlet/src/test/java/org/springframework/web/portlet/DispatcherPortletTests.java index fdb7d9df46..16ee96b7fd 100644 --- a/spring-webmvc-portlet/src/test/java/org/springframework/web/portlet/DispatcherPortletTests.java +++ b/spring-webmvc-portlet/src/test/java/org/springframework/web/portlet/DispatcherPortletTests.java @@ -16,42 +16,29 @@ package org.springframework.web.portlet; -import java.io.IOException; import java.util.Locale; import java.util.Map; import javax.portlet.PortletContext; import javax.portlet.PortletException; import javax.portlet.PortletMode; import javax.portlet.PortletSecurityException; -import javax.portlet.PortletSession; import junit.framework.TestCase; -import org.springframework.tests.sample.beans.TestBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.i18n.LocaleContext; -import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.mock.web.portlet.MockActionRequest; import org.springframework.mock.web.portlet.MockActionResponse; -import org.springframework.mock.web.portlet.MockEvent; -import org.springframework.mock.web.portlet.MockEventRequest; -import org.springframework.mock.web.portlet.MockEventResponse; import org.springframework.mock.web.portlet.MockPortletConfig; import org.springframework.mock.web.portlet.MockPortletContext; -import org.springframework.mock.web.portlet.MockPortletSession; import org.springframework.mock.web.portlet.MockRenderRequest; import org.springframework.mock.web.portlet.MockRenderResponse; import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.request.RequestAttributes; -import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.support.StaticWebApplicationContext; import org.springframework.web.multipart.MaxUploadSizeExceededException; import org.springframework.web.portlet.context.PortletApplicationContextUtils; import org.springframework.web.portlet.context.PortletConfigAwareBean; import org.springframework.web.portlet.context.PortletContextAwareBean; -import org.springframework.web.portlet.context.PortletRequestAttributes; -import org.springframework.web.portlet.handler.PortletSessionRequiredException; import org.springframework.web.portlet.multipart.MultipartActionRequest; import org.springframework.web.portlet.multipart.PortletMultipartResolver; import org.springframework.web.servlet.ViewRendererServlet; @@ -64,25 +51,16 @@ import org.springframework.web.servlet.view.InternalResourceView; */ public class DispatcherPortletTests extends TestCase { - private MockPortletConfig simplePortletConfig; - private MockPortletConfig complexPortletConfig; - private DispatcherPortlet simpleDispatcherPortlet; - private DispatcherPortlet complexDispatcherPortlet; @Override protected void setUp() throws PortletException { - simplePortletConfig = new MockPortletConfig(new MockPortletContext(), "simple"); - complexPortletConfig = new MockPortletConfig(simplePortletConfig.getPortletContext(), "complex"); + complexPortletConfig = new MockPortletConfig(new MockPortletContext(), "complex"); complexPortletConfig.addInitParameter("publishContext", "false"); - simpleDispatcherPortlet = new DispatcherPortlet(); - simpleDispatcherPortlet.setContextClass(SimplePortletApplicationContext.class); - simpleDispatcherPortlet.init(simplePortletConfig); - complexDispatcherPortlet = new DispatcherPortlet(); complexDispatcherPortlet.setContextClass(ComplexPortletApplicationContext.class); complexDispatcherPortlet.setNamespace("test"); @@ -103,14 +81,6 @@ public class DispatcherPortletTests extends TestCase { } public void testDispatcherPortlets() { - assertTrue("Correct namespace", - ("simple" + FrameworkPortlet.DEFAULT_NAMESPACE_SUFFIX).equals(simpleDispatcherPortlet.getNamespace())); - assertTrue("Correct attribute", - (FrameworkPortlet.PORTLET_CONTEXT_PREFIX + "simple").equals(simpleDispatcherPortlet.getPortletContextAttributeName())); - assertTrue("Context published", - simpleDispatcherPortlet.getPortletApplicationContext() == - getPortletContext().getAttribute(FrameworkPortlet.PORTLET_CONTEXT_PREFIX + "simple")); - assertTrue("Correct namespace", "test".equals(complexDispatcherPortlet.getNamespace())); assertTrue("Correct attribute", (FrameworkPortlet.PORTLET_CONTEXT_PREFIX + "complex").equals(complexDispatcherPortlet.getPortletContextAttributeName())); @@ -118,192 +88,6 @@ public class DispatcherPortletTests extends TestCase { getPortletContext().getAttribute(FrameworkPortlet.PORTLET_CONTEXT_PREFIX + "complex") == null); } - public void testSimpleValidActionRequest() throws Exception { - MockActionRequest request = new MockActionRequest(); - MockActionResponse response = new MockActionResponse(); - request.setParameter("action", "form"); - request.setParameter("age", "29"); - simpleDispatcherPortlet.processAction(request, response); - String exceptionParam = response.getRenderParameter(DispatcherPortlet.ACTION_EXCEPTION_RENDER_PARAMETER); - assertNull(exceptionParam); - SimplePortletApplicationContext ac = (SimplePortletApplicationContext)simpleDispatcherPortlet.getPortletApplicationContext(); - String commandAttribute = ac.getRenderCommandSessionAttributeName(); - TestBean testBean = (TestBean) request.getPortletSession().getAttribute(commandAttribute); - assertEquals(39, testBean.getAge()); - } - - public void testSimpleInvalidActionRequest() throws Exception { - MockActionRequest request = new MockActionRequest(); - MockActionResponse response = new MockActionResponse(); - request.setParameter("action", "invalid"); - simpleDispatcherPortlet.processAction(request, response); - String exceptionParam = response.getRenderParameter(DispatcherPortlet.ACTION_EXCEPTION_RENDER_PARAMETER); - assertNotNull(exceptionParam); - assertTrue(exceptionParam.startsWith(NoHandlerFoundException.class.getName())); - } - - - public void testSimpleInvalidActionRequestWithoutHandling() throws Exception { - MockActionRequest request = new MockActionRequest(); - MockActionResponse response = new MockActionResponse(); - request.setParameter("action", "invalid"); - simpleDispatcherPortlet.setForwardActionException(false); - try { - simpleDispatcherPortlet.processAction(request, response); - fail("Should have thrown a " + NoHandlerFoundException.class); - } - catch (NoHandlerFoundException ex) { - // expected - } - } - - public void testSimpleValidEventRequest() throws Exception { - MockEvent event = new MockEvent("test-event"); - MockEventRequest request = new MockEventRequest(event); - MockEventResponse response = new MockEventResponse(); - request.setParameter("action", "form"); - simpleDispatcherPortlet.processEvent(request, response); - assertEquals("test-event", response.getRenderParameter("event")); - } - - public void testSimpleInvalidEventRequest() throws Exception { - MockEvent event = new MockEvent("test-event"); - MockEventRequest request = new MockEventRequest(event); - MockEventResponse response = new MockEventResponse(); - request.setParameter("action", "invalid"); - try { - simpleDispatcherPortlet.processEvent(request, response); - fail("Should have thrown a " + NoHandlerFoundException.class); - } - catch (NoHandlerFoundException ex) { - // expected - } - } - - public void testSimpleInvalidEventRequestWithHandling() throws Exception { - MockEvent event = new MockEvent("event"); - MockEventRequest request = new MockEventRequest(event); - MockEventResponse response = new MockEventResponse(); - request.setParameter("action", "invalid"); - simpleDispatcherPortlet.setForwardEventException(true); - simpleDispatcherPortlet.processEvent(request, response); - String exceptionParam = response.getRenderParameter(DispatcherPortlet.ACTION_EXCEPTION_RENDER_PARAMETER); - assertNotNull(exceptionParam); - assertTrue(exceptionParam.startsWith(NoHandlerFoundException.class.getName())); - } - - public void testSimpleFormViewNoBindOnNewForm() throws Exception { - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - request.setParameter("action", "form"); - request.setParameter("age", "29"); - simpleDispatcherPortlet.doDispatch(request, response); - assertEquals("5", response.getContentAsString()); - } - - public void testSimpleFormViewBindOnNewForm() throws Exception { - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - request.setParameter("action", "form-bind"); - request.setParameter("age", "29"); - simpleDispatcherPortlet.doDispatch(request, response); - assertEquals("34", response.getContentAsString()); - } - - public void testSimpleFormViewWithSessionAndBindOnNewForm() throws Exception { - MockRenderRequest renderRequest = new MockRenderRequest(); - MockRenderResponse renderResponse = new MockRenderResponse(); - renderRequest.setParameter("action", "form-session-bind"); - renderRequest.setParameter("age", "30"); - TestBean testBean = new TestBean(); - testBean.setAge(40); - SimplePortletApplicationContext ac = - (SimplePortletApplicationContext)simpleDispatcherPortlet.getPortletApplicationContext(); - String formAttribute = ac.getFormSessionAttributeName(); - PortletSession session = new MockPortletSession(); - session.setAttribute(formAttribute, testBean); - renderRequest.setSession(session); - simpleDispatcherPortlet.doDispatch(renderRequest, renderResponse); - assertEquals("35", renderResponse.getContentAsString()); - } - - public void testSimpleFormViewWithSessionNoBindOnNewForm() throws Exception { - MockActionRequest actionRequest = new MockActionRequest(); - MockActionResponse actionResponse = new MockActionResponse(); - actionRequest.setSession(new MockPortletSession()); - actionRequest.setParameter("action", "form-session-nobind"); - actionRequest.setParameter("age", "27"); - simpleDispatcherPortlet.processAction(actionRequest, actionResponse); - Map renderParameters = actionResponse.getRenderParameterMap(); - - MockRenderRequest renderRequest = new MockRenderRequest(); - MockRenderResponse renderResponse = new MockRenderResponse(); - renderRequest.setParameters(renderParameters); - renderRequest.setParameter("action", "form-session-nobind"); - renderRequest.setParameter("age", "30"); - renderRequest.setSession(actionRequest.getPortletSession()); - simpleDispatcherPortlet.doDispatch(renderRequest, renderResponse); - assertEquals("finished42", renderResponse.getContentAsString()); - } - - public void testSimpleRequiredSessionFormWithoutSession() throws Exception { - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - request.setParameter("action", "form-session-bind"); - try { - simpleDispatcherPortlet.doDispatch(request, response); - fail("Should have thrown PortletSessionRequiredException"); - } - catch (PortletSessionRequiredException ex) { -// expected - } - } - - public void testSimpleFormSubmission() throws Exception { - MockActionRequest actionRequest = new MockActionRequest(); - MockActionResponse actionResponse = new MockActionResponse(); - actionRequest.setParameter("action", "form"); - actionRequest.setParameter("age", "29"); - simpleDispatcherPortlet.processAction(actionRequest, actionResponse); - - MockRenderRequest renderRequest = new MockRenderRequest(); - MockRenderResponse renderResponse = new MockRenderResponse(); - renderRequest.setSession(actionRequest.getPortletSession()); - renderRequest.setParameters(actionResponse.getRenderParameterMap()); - renderRequest.setParameter("action", "form"); - simpleDispatcherPortlet.doDispatch(renderRequest, renderResponse); - assertEquals("finished44", renderResponse.getContentAsString()); - } - - public void testSimpleFormSubmissionWithValidationError() throws Exception { - MockActionRequest actionRequest = new MockActionRequest(); - MockActionResponse actionResponse = new MockActionResponse(); - actionRequest.setParameter("action", "form"); - actionRequest.setParameter("age", "XX"); - simpleDispatcherPortlet.processAction(actionRequest, actionResponse); - - MockRenderRequest renderRequest = new MockRenderRequest(); - MockRenderResponse renderResponse = new MockRenderResponse(); - renderRequest.setSession(actionRequest.getPortletSession()); - renderRequest.setParameters(actionResponse.getRenderParameterMap()); - renderRequest.setParameter("action", "form"); - simpleDispatcherPortlet.doDispatch(renderRequest, renderResponse); - assertEquals("5", renderResponse.getContentAsString()); - } - - public void testSimpleInvalidRenderRequest() throws Exception { - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - request.setParameter("action", "invalid"); - try { - simpleDispatcherPortlet.doDispatch(request, response); - fail("Should have thrown UnavailableException"); - } - catch (NoHandlerFoundException ex) { -// expected - } - } - public void testPortletModeParameterMappingHelp1() throws Exception { MockActionRequest request = new MockActionRequest(); MockActionResponse response = new MockActionResponse(); @@ -859,115 +643,6 @@ public class DispatcherPortletTests extends TestCase { } } - public void testValidActionRequestWithExistingThreadLocalRequestContext() throws IOException, PortletException { - MockActionRequest request = new MockActionRequest(); - MockActionResponse response = new MockActionResponse(); - request.addPreferredLocale(Locale.GERMAN); - request.setParameter("action", "form"); - request.setParameter("age", "29"); - -// see RequestContextListener.requestInitialized() - try { - LocaleContextHolder.setLocale(request.getLocale()); - RequestContextHolder.setRequestAttributes(new PortletRequestAttributes(request)); - - LocaleContext servletLocaleContext = LocaleContextHolder.getLocaleContext(); - RequestAttributes servletRequestAttrs = RequestContextHolder.getRequestAttributes(); - - simpleDispatcherPortlet.processAction(request, response); - - assertSame(servletLocaleContext, LocaleContextHolder.getLocaleContext()); - assertSame(servletRequestAttrs, RequestContextHolder.getRequestAttributes()); - } - finally { - RequestContextHolder.resetRequestAttributes(); - LocaleContextHolder.resetLocaleContext(); - } - } - - public void testValidRenderRequestWithExistingThreadLocalRequestContext() throws IOException, PortletException { - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - request.addPreferredLocale(Locale.GERMAN); - -// see RequestContextListener.requestInitialized() - try { - LocaleContextHolder.setLocale(request.getLocale()); - RequestContextHolder.setRequestAttributes(new PortletRequestAttributes(request)); - - LocaleContext servletLocaleContext = LocaleContextHolder.getLocaleContext(); - RequestAttributes servletRequestAttrs = RequestContextHolder.getRequestAttributes(); - - request.setParameter("action", "form"); - request.setParameter("age", "29"); - simpleDispatcherPortlet.doDispatch(request, response); - - assertSame(servletLocaleContext, LocaleContextHolder.getLocaleContext()); - assertSame(servletRequestAttrs, RequestContextHolder.getRequestAttributes()); - } - finally { - RequestContextHolder.resetRequestAttributes(); - LocaleContextHolder.resetLocaleContext(); - } - } - - public void testInvalidActionRequestWithExistingThreadLocalRequestContext() throws IOException, PortletException { - MockActionRequest request = new MockActionRequest(); - MockActionResponse response = new MockActionResponse(); - request.addPreferredLocale(Locale.GERMAN); - -// see RequestContextListener.requestInitialized() - try { - LocaleContextHolder.setLocale(request.getLocale()); - RequestContextHolder.setRequestAttributes(new PortletRequestAttributes(request)); - - LocaleContext servletLocaleContext = LocaleContextHolder.getLocaleContext(); - RequestAttributes servletRequestAttrs = RequestContextHolder.getRequestAttributes(); - - request.setParameter("action", "invalid"); - simpleDispatcherPortlet.processAction(request, response); - String exceptionParam = response.getRenderParameter(DispatcherPortlet.ACTION_EXCEPTION_RENDER_PARAMETER); - assertNotNull(exceptionParam); // ensure that an exceptional condition occured - - assertSame(servletLocaleContext, LocaleContextHolder.getLocaleContext()); - assertSame(servletRequestAttrs, RequestContextHolder.getRequestAttributes()); - } - finally { - RequestContextHolder.resetRequestAttributes(); - LocaleContextHolder.resetLocaleContext(); - } - } - - public void testInvalidRenderRequestWithExistingThreadLocalRequestContext() throws IOException, PortletException { - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - request.addPreferredLocale(Locale.GERMAN); - -// see RequestContextListener.requestInitialized() - try { - LocaleContextHolder.setLocale(request.getLocale()); - RequestContextHolder.setRequestAttributes(new PortletRequestAttributes(request)); - - LocaleContext servletLocaleContext = LocaleContextHolder.getLocaleContext(); - RequestAttributes servletRequestAttrs = RequestContextHolder.getRequestAttributes(); - - try { - simpleDispatcherPortlet.doDispatch(request, response); - fail("should have failed to find a handler and raised an NoHandlerFoundExceptionException"); - } - catch (NoHandlerFoundException ex) { -// expected - } - - assertSame(servletLocaleContext, LocaleContextHolder.getLocaleContext()); - assertSame(servletRequestAttrs, RequestContextHolder.getRequestAttributes()); - } - finally { - RequestContextHolder.resetRequestAttributes(); - LocaleContextHolder.resetLocaleContext(); - } - } - public void testDispatcherPortletRefresh() throws PortletException { MockPortletContext portletContext = new MockPortletContext("org/springframework/web/portlet/context"); DispatcherPortlet portlet = new DispatcherPortlet(); diff --git a/spring-webmvc-portlet/src/test/java/org/springframework/web/portlet/SimplePortletApplicationContext.java b/spring-webmvc-portlet/src/test/java/org/springframework/web/portlet/SimplePortletApplicationContext.java deleted file mode 100644 index 3f53c7edfa..0000000000 --- a/spring-webmvc-portlet/src/test/java/org/springframework/web/portlet/SimplePortletApplicationContext.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2002-2013 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.portlet; - -import java.io.IOException; -import java.util.Map; - -import javax.portlet.EventRequest; -import javax.portlet.EventResponse; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; - -import org.springframework.beans.BeansException; -import org.springframework.beans.MutablePropertyValues; -import org.springframework.beans.PropertyValue; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.support.ManagedMap; -import org.springframework.validation.BindException; -import org.springframework.web.portlet.context.StaticPortletApplicationContext; -import org.springframework.web.portlet.handler.ParameterHandlerMapping; -import org.springframework.web.portlet.mvc.EventAwareController; -import org.springframework.web.portlet.mvc.SimpleFormController; - -/** - * @author Mark Fisher - */ -public class SimplePortletApplicationContext extends StaticPortletApplicationContext { - - private String renderCommandSessionAttributeName; - private String formSessionAttributeName; - - @Override - public void refresh() throws BeansException { - MutablePropertyValues pvs = new MutablePropertyValues(); - registerSingleton("controller1", TestFormController.class, pvs); - - pvs = new MutablePropertyValues(); - pvs.add("bindOnNewForm", "true"); - registerSingleton("controller2", TestFormController.class, pvs); - - pvs = new MutablePropertyValues(); - pvs.add("requireSession", "true"); - pvs.add("sessionForm", "true"); - pvs.add("bindOnNewForm", "true"); - registerSingleton("controller3", TestFormController.class, pvs); - - pvs = new MutablePropertyValues(); - pvs.add("requireSession", "true"); - pvs.add("sessionForm", "true"); - pvs.add("bindOnNewForm", "false"); - registerSingleton("controller4", TestFormController.class, pvs); - - pvs = new MutablePropertyValues(); - Map parameterMap = new ManagedMap(); - parameterMap.put("form", new RuntimeBeanReference("controller1")); - parameterMap.put("form-bind", new RuntimeBeanReference("controller2")); - parameterMap.put("form-session-bind", new RuntimeBeanReference("controller3")); - parameterMap.put("form-session-nobind", new RuntimeBeanReference("controller4")); - pvs.addPropertyValue(new PropertyValue("parameterMap", parameterMap)); - registerSingleton("handlerMapping", ParameterHandlerMapping.class, pvs); - - super.refresh(); - - TestFormController controller1 = (TestFormController) getBean("controller1"); - this.renderCommandSessionAttributeName = controller1.getRenderCommandName(); - this.formSessionAttributeName = controller1.getFormSessionName(); - } - - public String getRenderCommandSessionAttributeName() { - return this.renderCommandSessionAttributeName; - } - - public String getFormSessionAttributeName() { - return this.formSessionAttributeName; - } - - - public static class TestFormController extends SimpleFormController implements EventAwareController { - - TestFormController() { - super(); - this.setCommandClass(TestBean.class); - this.setCommandName("testBean"); - this.setFormView("form"); - } - - @Override - public void doSubmitAction(Object command) { - TestBean testBean = (TestBean) command; - testBean.setAge(testBean.getAge() + 10); - } - - @Override - public ModelAndView showForm(RenderRequest request, RenderResponse response, BindException errors) throws Exception { - TestBean testBean = (TestBean) errors.getModel().get(getCommandName()); - this.writeResponse(response, testBean, false); - return null; - } - - @Override - public ModelAndView onSubmitRender(RenderRequest request, RenderResponse response, Object command, BindException errors) - throws IOException { - TestBean testBean = (TestBean) command; - this.writeResponse(response, testBean, true); - return null; - } - - private String getRenderCommandName() { - return this.getRenderCommandSessionAttributeName(); - } - - private String getFormSessionName() { - return this.getFormSessionAttributeName(); - } - - private void writeResponse(RenderResponse response, TestBean testBean, boolean finished) throws IOException { - response.getWriter().write((finished ? "finished" : "") + (testBean.getAge() + 5)); - } - - @Override - public void handleEventRequest(EventRequest request, EventResponse response) throws Exception { - response.setRenderParameter("event", request.getEvent().getName()); - } - } - -} diff --git a/spring-webmvc-portlet/src/test/java/org/springframework/web/portlet/mvc/CommandControllerTests.java b/spring-webmvc-portlet/src/test/java/org/springframework/web/portlet/mvc/CommandControllerTests.java deleted file mode 100644 index 2ea777d8c4..0000000000 --- a/spring-webmvc-portlet/src/test/java/org/springframework/web/portlet/mvc/CommandControllerTests.java +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Copyright 2002-2013 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.portlet.mvc; - -import java.beans.PropertyEditorSupport; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -import javax.portlet.ActionRequest; -import javax.portlet.ActionResponse; -import javax.portlet.PortletRequest; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; -import javax.portlet.WindowState; - -import junit.framework.TestCase; - -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.beans.propertyeditors.CustomDateEditor; -import org.springframework.mock.web.portlet.MockActionRequest; -import org.springframework.mock.web.portlet.MockActionResponse; -import org.springframework.mock.web.portlet.MockRenderRequest; -import org.springframework.mock.web.portlet.MockRenderResponse; -import org.springframework.validation.BindException; -import org.springframework.validation.Errors; -import org.springframework.validation.FieldError; -import org.springframework.validation.ObjectError; -import org.springframework.validation.ValidationUtils; -import org.springframework.validation.Validator; -import org.springframework.web.portlet.ModelAndView; -import org.springframework.web.portlet.bind.PortletRequestDataBinder; -import org.springframework.web.portlet.handler.PortletSessionRequiredException; - -/** - * @author Mark Fisher - */ -@Deprecated -public class CommandControllerTests extends TestCase { - - private static final String ERRORS_KEY = "errors"; - - public void testRenderRequestWithNoParams() throws Exception { - TestController tc = new TestController(); - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - request.setContextPath("test"); - ModelAndView mav = tc.handleRenderRequest(request, response); - assertEquals("test-view", mav.getViewName()); - assertNotNull(mav.getModel().get(tc.getCommandName())); - BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); - assertNotNull(errors); - assertEquals("There should be no errors", 0, errors.getErrorCount()); - } - - public void testRenderRequestWithParams() throws Exception { - TestController tc = new TestController(); - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - String name = "test"; - int age = 30; - request.addParameter("name", name); - request.addParameter("age", "" + age); - request.setContextPath("test"); - ModelAndView mav = tc.handleRenderRequest(request, response); - assertEquals("test-view", mav.getViewName()); - TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); - assertEquals("Name should be bound", name, command.getName()); - assertEquals("Age should be bound", age, command.getAge()); - BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); - assertNotNull(errors); - assertEquals("There should be no errors", 0, errors.getErrorCount()); - } - - public void testRenderRequestWithMismatch() throws Exception { - TestController tc = new TestController(); - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - String name = "test"; - request.addParameter("name", name); - request.addParameter("age", "zzz"); - request.setContextPath("test"); - ModelAndView mav = tc.handleRenderRequest(request, response); - assertEquals("test-view", mav.getViewName()); - TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); - assertNotNull(command); - assertEquals("Name should be bound", name, command.getName()); - BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); - assertEquals("There should be 1 error", 1, errors.getErrorCount()); - assertNotNull(errors.getFieldError("age")); - assertEquals("typeMismatch", errors.getFieldError("age").getCode()); - } - - public void testRenderWhenMinimizedReturnsNull() throws Exception { - TestController tc = new TestController(); - assertFalse(tc.isRenderWhenMinimized()); - MockRenderRequest request = new MockRenderRequest(); - request.setWindowState(WindowState.MINIMIZED); - MockRenderResponse response = new MockRenderResponse(); - ModelAndView mav = tc.handleRenderRequest(request, response); - assertNull("ModelAndView should be null", mav); - } - - public void testAllowRenderWhenMinimized() throws Exception { - TestController tc = new TestController(); - tc.setRenderWhenMinimized(true); - MockRenderRequest request = new MockRenderRequest(); - request.setWindowState(WindowState.MINIMIZED); - request.setContextPath("test"); - MockRenderResponse response = new MockRenderResponse(); - ModelAndView mav = tc.handleRenderRequest(request, response); - assertNotNull("ModelAndView should not be null", mav); - assertEquals("test-view", mav.getViewName()); - assertNotNull(mav.getModel().get(tc.getCommandName())); - BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); - assertEquals("There should be no errors", 0, errors.getErrorCount()); - } - - public void testRequiresSessionWithoutSession() throws Exception { - TestController tc = new TestController(); - tc.setRequireSession(true); - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - try { - tc.handleRenderRequest(request, response); - fail("Should have thrown PortletSessionRequiredException"); - } - catch (PortletSessionRequiredException ex) { - // expected - } - } - - public void testRequiresSessionWithSession() throws Exception { - TestController tc = new TestController(); - tc.setRequireSession(true); - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - - // create the session - request.getPortletSession(true); - try { - tc.handleRenderRequest(request, response); - } - catch (PortletSessionRequiredException ex) { - fail("Should not have thrown PortletSessionRequiredException"); - } - } - - public void testRenderRequestWithoutCacheSetting() throws Exception { - TestController tc = new TestController(); - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - tc.handleRenderRequest(request, response); - String cacheProperty = response.getProperty(RenderResponse.EXPIRATION_CACHE); - assertNull("Expiration-cache should be null", cacheProperty); - } - - public void testRenderRequestWithNegativeCacheSetting() throws Exception { - TestController tc = new TestController(); - tc.setCacheSeconds(-99); - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - tc.handleRenderRequest(request, response); - String cacheProperty = response.getProperty(RenderResponse.EXPIRATION_CACHE); - assertNull("Expiration-cache should be null", cacheProperty); - } - - public void testRenderRequestWithZeroCacheSetting() throws Exception { - TestController tc = new TestController(); - tc.setCacheSeconds(0); - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - tc.handleRenderRequest(request, response); - String cacheProperty = response.getProperty(RenderResponse.EXPIRATION_CACHE); - assertEquals("Expiration-cache should be set to 0 seconds", "0", cacheProperty); - } - - public void testRenderRequestWithPositiveCacheSetting() throws Exception { - TestController tc = new TestController(); - tc.setCacheSeconds(30); - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - tc.handleRenderRequest(request, response); - String cacheProperty = response.getProperty(RenderResponse.EXPIRATION_CACHE); - assertEquals("Expiration-cache should be set to 30 seconds", "30", cacheProperty); - } - - public void testActionRequest() throws Exception { - TestController tc = new TestController(); - MockActionRequest request = new MockActionRequest(); - MockActionResponse response = new MockActionResponse(); - tc.handleActionRequest(request, response); - TestBean command = (TestBean)request.getPortletSession().getAttribute(tc.getRenderCommandSessionAttributeName()); - assertTrue(command.isJedi()); - } - - public void testSuppressBinding() throws Exception { - TestController tc = new TestController() { - @Override - protected boolean suppressBinding(PortletRequest request) { - return true; - } - }; - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - String name = "test"; - int age = 30; - request.addParameter("name", name); - request.addParameter("age", "" + age); - request.setContextPath("test"); - ModelAndView mav = tc.handleRenderRequest(request, response); - assertEquals("test-view", mav.getViewName()); - TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); - assertNotNull(command); - assertTrue("Name should not have been bound", name != command.getName()); - assertTrue("Age should not have been bound", age != command.getAge()); - BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); - assertEquals("There should be no errors", 0, errors.getErrorCount()); - } - - public void testWithCustomDateEditor() throws Exception { - final DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); - TestController tc = new TestController() { - @Override - protected void initBinder(PortletRequest request, PortletRequestDataBinder binder) { - binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); - } - }; - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - String name = "test"; - int age = 30; - request.addParameter("name", name); - request.addParameter("age", "" + age); - String dateString = "07-03-2006"; - Date expectedDate = dateFormat.parse(dateString); - request.addParameter("date", dateString); - ModelAndView mav = tc.handleRenderRequest(request, response); - TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); - assertEquals(name, command.getName()); - assertEquals(age, command.getAge()); - assertEquals(expectedDate, command.getDate()); - BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); - assertEquals("There should be no errors", 0, errors.getErrorCount()); - } - - public void testWithCustomDateEditorEmptyNotAllowed() throws Exception { - final DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); - TestController tc = new TestController() { - @Override - protected void initBinder(PortletRequest request, PortletRequestDataBinder binder) { - binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); - } - }; - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - String name = "test"; - int age = 30; - request.addParameter("name", name); - request.addParameter("age", "" + age); - String emptyString = ""; - request.addParameter("date", emptyString); - ModelAndView mav = tc.handleRenderRequest(request, response); - TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); - assertEquals(name, command.getName()); - assertEquals(age, command.getAge()); - BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); - assertEquals("There should be 1 error", 1, errors.getErrorCount()); - assertNotNull(errors.getFieldError("date")); - assertEquals("typeMismatch", errors.getFieldError("date").getCode()); - assertEquals(emptyString, errors.getFieldError("date").getRejectedValue()); - } - - public void testWithCustomDateEditorEmptyAllowed() throws Exception { - final DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); - TestController tc = new TestController() { - @Override - protected void initBinder(PortletRequest request, PortletRequestDataBinder binder) { - binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); - } - }; - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - String name = "test"; - int age = 30; - request.addParameter("name", name); - request.addParameter("age", "" + age); - String dateString = ""; - request.addParameter("date", dateString); - ModelAndView mav = tc.handleRenderRequest(request, response); - TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); - assertEquals(name, command.getName()); - assertEquals(age, command.getAge()); - BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); - assertEquals("There should be 0 errors", 0, errors.getErrorCount()); - assertNull("date should be null", command.getDate()); - } - - public void testNestedBindingWithPropertyEditor() throws Exception { - TestController tc = new TestController() { - @Override - protected void initBinder(PortletRequest request, PortletRequestDataBinder binder) { - binder.registerCustomEditor(ITestBean.class, new PropertyEditorSupport() { - @Override - public void setAsText(String text) throws IllegalArgumentException { - setValue(new TestBean(text)); - } - }); - } - }; - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - String name = "test"; - String spouseName = "testSpouse"; - int age = 30; - int spouseAge = 31; - request.addParameter("name", name); - request.addParameter("age", "" + age); - request.addParameter("spouse", spouseName); - request.addParameter("spouse.age", "" + spouseAge); - ModelAndView mav = tc.handleRenderRequest(request, response); - TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); - assertEquals(name, command.getName()); - assertEquals(age, command.getAge()); - assertNotNull(command.getSpouse()); - assertEquals(spouseName, command.getSpouse().getName()); - assertEquals(spouseAge, command.getSpouse().getAge()); - BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); - assertEquals("There should be no errors", 0, errors.getErrorCount()); - } - - public void testWithValidatorNotSupportingCommandClass() throws Exception { - Validator v = new Validator() { - @Override - public boolean supports(Class c) { - return false; - } - @Override - public void validate(Object o, Errors e) {} - }; - TestController tc = new TestController(); - tc.setValidator(v); - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - try { - tc.handleRenderRequest(request, response); - fail("Should have thrown IllegalArgumentException"); - } - catch(IllegalArgumentException e) { - // expected - } - } - - public void testWithValidatorAddingGlobalError() throws Exception { - final String errorCode = "someCode"; - final String defaultMessage = "validation error!"; - TestController tc = new TestController(); - tc.setValidator(new Validator() { - @Override - public boolean supports(Class c) { - return TestBean.class.isAssignableFrom(c); - } - @Override - public void validate(Object o, Errors e) { - e.reject(errorCode, defaultMessage); - } - }); - MockRenderRequest request = new MockRenderRequest(); - MockRenderResponse response = new MockRenderResponse(); - ModelAndView mav = tc.handleRenderRequest(request, response); - BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); - assertEquals("There should be 1 error", 1, errors.getErrorCount()); - ObjectError error = errors.getGlobalError(); - assertEquals(error.getCode(), errorCode); - assertEquals(error.getDefaultMessage(), defaultMessage); - } - - public void testWithValidatorAndNullFieldError() throws Exception { - final String errorCode = "someCode"; - final String defaultMessage = "validation error!"; - TestController tc = new TestController(); - tc.setValidator(new Validator() { - @Override - public boolean supports(Class c) { - return TestBean.class.isAssignableFrom(c); - } - @Override - public void validate(Object o, Errors e) { - ValidationUtils.rejectIfEmpty(e, "name", errorCode, defaultMessage); - } - }); - MockRenderRequest request = new MockRenderRequest(); - int age = 32; - request.setParameter("age", "" + age); - MockRenderResponse response = new MockRenderResponse(); - ModelAndView mav = tc.handleRenderRequest(request, response); - TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); - assertNull("name should be null", command.getName()); - assertEquals(age, command.getAge()); - BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); - assertEquals("There should be 1 error", 1, errors.getErrorCount()); - FieldError error = errors.getFieldError("name"); - assertEquals(error.getCode(), errorCode); - assertEquals(error.getDefaultMessage(), defaultMessage); - } - - public void testWithValidatorAndWhitespaceFieldError() throws Exception { - final String errorCode = "someCode"; - final String defaultMessage = "validation error!"; - TestController tc = new TestController(); - tc.setValidator(new Validator() { - @Override - public boolean supports(Class c) { - return TestBean.class.isAssignableFrom(c); - } - @Override - public void validate(Object o, Errors e) { - ValidationUtils.rejectIfEmptyOrWhitespace(e, "name", errorCode, defaultMessage); - } - }); - MockRenderRequest request = new MockRenderRequest(); - int age = 32; - String whitespace = " \t "; - request.setParameter("age", "" + age); - request.setParameter("name", whitespace); - MockRenderResponse response = new MockRenderResponse(); - ModelAndView mav = tc.handleRenderRequest(request, response); - TestBean command = (TestBean)mav.getModel().get(tc.getCommandName()); - assertTrue(command.getName().equals(whitespace)); - assertEquals(age, command.getAge()); - BindException errors = (BindException)mav.getModel().get(ERRORS_KEY); - assertEquals("There should be 1 error", 1, errors.getErrorCount()); - FieldError error = errors.getFieldError("name"); - assertEquals("rejected value should contain whitespace", whitespace, error.getRejectedValue()); - assertEquals(error.getCode(), errorCode); - assertEquals(error.getDefaultMessage(), defaultMessage); - } - - private static class TestController extends AbstractCommandController { - - private TestController() { - super(TestBean.class, "testBean"); - } - - @Override - protected void handleAction(ActionRequest request, ActionResponse response, Object command, BindException errors) { - ((TestBean)command).setJedi(true); - } - - @Override - protected ModelAndView handleRender(RenderRequest request, RenderResponse response, Object command, BindException errors) { - assertNotNull(command); - assertNotNull(errors); - Map model = new HashMap(); - model.put(getCommandName(), command); - model.put(ERRORS_KEY, errors); - return new ModelAndView(request.getContextPath() + "-view", model); - } - } - -} diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/AbstractCommandController.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/AbstractCommandController.java deleted file mode 100644 index 6c4731ff1f..0000000000 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/AbstractCommandController.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2002-2012 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 org.springframework.validation.BindException; -import org.springframework.web.bind.ServletRequestDataBinder; -import org.springframework.web.servlet.ModelAndView; - -/** - * Abstract base class for custom command controllers. - * - *

Autopopulates a command bean from the request. For command validation, - * a validator (property inherited from {@link BaseCommandController}) can be - * used. - * - *

In most cases this command controller should not be used to handle form - * submission, because functionality for forms is offered in more detail by the - * {@link org.springframework.web.servlet.mvc.AbstractFormController} and its - * corresponding implementations. - * - *

Exposed configuration properties - * (and those defined by superclass):
- * none (so only those available in superclass).

- * - *

Workflow - * (and that defined by superclass):
- * - * @author Rod Johnson - * @author Juergen Hoeller - * @see #setCommandClass - * @see #setCommandName - * @see #setValidator - * @deprecated as of Spring 3.0, in favor of annotated controllers - */ -@Deprecated -public abstract class AbstractCommandController extends BaseCommandController { - - /** - * Create a new AbstractCommandController. - */ - public AbstractCommandController() { - } - - /** - * Create a new AbstractCommandController. - * @param commandClass class of the command bean - */ - public AbstractCommandController(Class commandClass) { - setCommandClass(commandClass); - } - - /** - * Create a new AbstractCommandController. - * @param commandClass class of the command bean - * @param commandName name of the command bean - */ - public AbstractCommandController(Class commandClass, String commandName) { - setCommandClass(commandClass); - setCommandName(commandName); - } - - - @Override - protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) - throws Exception { - - Object command = getCommand(request); - ServletRequestDataBinder binder = bindAndValidate(request, command); - BindException errors = new BindException(binder.getBindingResult()); - return handle(request, response, command, errors); - } - - /** - * Template method for request handling, providing a populated and validated instance - * of the command class, and an Errors object containing binding and validation errors. - *

Call {@code errors.getModel()} to populate the ModelAndView model - * with the command and the Errors instance, under the specified command name, - * as expected by the "spring:bind" tag. - * @param request current HTTP request - * @param response current HTTP response - * @param command the populated command object - * @param errors validation errors holder - * @return a ModelAndView to render, or {@code null} if handled directly - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - */ - protected abstract ModelAndView handle( - HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) - throws Exception; - -} diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/AbstractFormController.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/AbstractFormController.java deleted file mode 100644 index da72de2f51..0000000000 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/AbstractFormController.java +++ /dev/null @@ -1,678 +0,0 @@ -/* - * Copyright 2002-2012 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.Map; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.springframework.validation.BindException; -import org.springframework.validation.Errors; -import org.springframework.web.HttpSessionRequiredException; -import org.springframework.web.bind.ServletRequestDataBinder; -import org.springframework.web.servlet.ModelAndView; - -/** - *

Form controller that auto-populates a form bean from the request. - * This, either using a new bean instance per request, or using the same bean - * when the {@code sessionForm} property has been set to {@code true}.

- * - *

This class is the base class for both framework subclasses such as - * {@link SimpleFormController} and {@link AbstractWizardFormController} - * and custom form controllers that you may provide yourself.

- * - *

A form-input view and an after-submission view have to be provided - * programmatically. To provide those views using configuration properties, - * use the {@link SimpleFormController}.

- * - *

Subclasses need to override {@code showForm} to prepare the form view, - * and {@code processFormSubmission} to handle submit requests. For the latter, - * binding errors like type mismatches will be reported via the given "errors" holder. - * For additional custom form validation, a validator (property inherited from - * BaseCommandController) can be used, reporting via the same "errors" instance.

- * - *

Comparing this Controller to the Struts notion of the {@code Action} - * shows us that with Spring, you can use any ordinary JavaBeans or database- - * backed JavaBeans without having to implement a framework-specific class - * (like Struts' {@code ActionForm}). More complex properties of JavaBeans - * (Dates, Locales, but also your own application-specific or compound types) - * can be represented and submitted to the controller, by using the notion of - * a {@code java.beans.PropertyEditor}. For more information on that - * subject, see the workflow of this controller and the explanation of the - * {@link BaseCommandController}.

- * - *

Workflow - * (and that defined by superclass):
- *

    - *
  1. The controller receives a request for a new form (typically a GET).
  2. - *
  3. Call to {@link #formBackingObject formBackingObject()} which by default, - * returns an instance of the commandClass that has been configured - * (see the properties the superclass exposes), but can also be overridden - * to e.g. retrieve an object from the database (that needs to be modified - * using the form).
  4. - *
  5. Call to {@link #initBinder initBinder()} which allows you to register - * custom editors for certain fields (often properties of non-primitive - * or non-String types) of the command class. This will render appropriate - * Strings for those property values, e.g. locale-specific date strings.
  6. - *
  7. Only if {@code bindOnNewForm} is set to {@code true}, then - * {@link org.springframework.web.bind.ServletRequestDataBinder ServletRequestDataBinder} - * gets applied to populate the new form object with initial request parameters and the - * {@link #onBindOnNewForm(HttpServletRequest, Object, BindException)} callback method is - * called. Note: any defined Validators are not applied at this point, to allow - * partial binding. However be aware that any Binder customizations applied via - * initBinder() (such as - * {@link org.springframework.validation.DataBinder#setRequiredFields(String[])} will - * still apply. As such, if using bindOnNewForm=true and initBinder() customizations are - * used to validate fields instead of using Validators, in the case that only some fields - * will be populated for the new form, there will potentially be some bind errors for - * missing fields in the errors object. Any view (JSP, etc.) that displays binder errors - * needs to be intelligent and for this case take into account whether it is displaying the - * initial form view or subsequent post results, skipping error display for the former.
  8. - *
  9. Call to {@link #showForm(HttpServletRequest, HttpServletResponse, BindException) showForm()} - * to return a View that should be rendered (typically the view that renders - * the form). This method has to be implemented in subclasses.
  10. - *
  11. The showForm() implementation will call {@link #referenceData referenceData()}, - * which you can implement to provide any relevant reference data you might need - * when editing a form (e.g. a List of Locale objects you're going to let the - * user select one from).
  12. - *
  13. Model gets exposed and view gets rendered, to let the user fill in the form.
  14. - *
  15. The controller receives a form submission (typically a POST). - * To use a different way of detecting a form submission, override the - * {@link #isFormSubmission isFormSubmission} method. - *
  16. - *
  17. If {@code sessionForm} is not set, {@link #formBackingObject formBackingObject()} - * is called to retrieve a form object. Otherwise, the controller tries to - * find the command object which is already bound in the session. If it cannot - * find the object, it does a call to {@link #handleInvalidSubmit handleInvalidSubmit} - * which - by default - tries to create a new form object and resubmit the form.
  18. - *
  19. The {@link org.springframework.web.bind.ServletRequestDataBinder ServletRequestDataBinder} - * gets applied to populate the form object with current request parameters. - *
  20. Call to {@link #onBind onBind(HttpServletRequest, Object, Errors)} which allows - * you to do custom processing after binding but before validation (e.g. to manually - * bind request parameters to bean properties, to be seen by the Validator).
  21. - *
  22. If {@code validateOnBinding} is set, a registered Validator will be invoked. - * The Validator will check the form object properties, and register corresponding - * errors via the given {@link org.springframework.validation.Errors Errors}
  23. object. - *
  24. Call to {@link #onBindAndValidate onBindAndValidate()} which allows you - * to do custom processing after binding and validation (e.g. to manually - * bind request parameters, and to validate them outside a Validator).
  25. - *
  26. Call {@link #processFormSubmission(HttpServletRequest, HttpServletResponse, - * Object, BindException) processFormSubmission()} to process the submission, with - * or without binding errors. This method has to be implemented in subclasses.
  27. - *
- *

- * - *

In session form mode, a submission without an existing form object in the - * session is considered invalid, like in case of a resubmit/reload by the browser. - * The {@link #handleInvalidSubmit handleInvalidSubmit} method is invoked then, - * by default trying to resubmit. It can be overridden in subclasses to show - * corresponding messages or to redirect to a new form, in order to avoid duplicate - * submissions. The form object in the session can be considered a transaction - * token in that case.

- * - *

Note that views should never retrieve form beans from the session but always - * from the request, as prepared by the form controller. Remember that some view - * technologies like Velocity cannot even access a HTTP session.

- * - *

Exposed configuration properties - * (and those defined by superclass):
- *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
namedefaultdescription
bindOnNewFormfalseIndicates whether to bind servlet request parameters when - * creating a new form. Otherwise, the parameters will only be - * bound on form submission attempts.
sessionFormfalseIndicates whether the form object should be kept in the session - * when a user asks for a new form. This allows you e.g. to retrieve - * an object from the database, let the user edit it, and then persist - * it again. Otherwise, a new command object will be created for each - * request (even when showing the form again after validation errors).
- *

- * - * @author Rod Johnson - * @author Juergen Hoeller - * @author Alef Arendsen - * @author Rob Harrop - * @author Colin Sampaleanu - * @see #showForm(HttpServletRequest, HttpServletResponse, BindException) - * @see #processFormSubmission - * @see SimpleFormController - * @see AbstractWizardFormController - * @deprecated as of Spring 3.0, in favor of annotated controllers - */ -@Deprecated -public abstract class AbstractFormController extends BaseCommandController { - - private boolean bindOnNewForm = false; - - private boolean sessionForm = false; - - - /** - * Create a new AbstractFormController. - *

Subclasses should set the following properties, either in the constructor - * or via a BeanFactory: commandName, commandClass, bindOnNewForm, sessionForm. - * Note that "commandClass" doesn't need to be set when overriding - * {@link #formBackingObject}, since the latter determines the class anyway. - *

"cacheSeconds" is by default set to 0 (-> no caching for all form controllers). - * @see #setCommandName - * @see #setCommandClass - * @see #setBindOnNewForm - * @see #setSessionForm - * @see #formBackingObject - */ - public AbstractFormController() { - setCacheSeconds(0); - } - - /** - * Set whether request parameters should be bound to the form object - * in case of a non-submitting request, that is, a new form. - */ - public final void setBindOnNewForm(boolean bindOnNewForm) { - this.bindOnNewForm = bindOnNewForm; - } - - /** - * Return {@code true} if request parameters should be bound in case of a new form. - */ - public final boolean isBindOnNewForm() { - return this.bindOnNewForm; - } - - /** - * Activate/deactivate session form mode. In session form mode, - * the form is stored in the session to keep the form object instance - * between requests, instead of creating a new one on each request. - *

This is necessary for either wizard-style controllers that populate a - * single form object from multiple pages, or forms that populate a persistent - * object that needs to be identical to allow for tracking changes. - *

Please note that the {@link AbstractFormController} class (and all - * subclasses of it unless stated to the contrary) do not support - * the notion of a conversation. This is important in the context of this - * property, because it means that there is only one form per session: - * this means that if session form mode is activated and a user opens up - * say two tabs in their browser and attempts to edit two distinct objects - * using the same form, then the shared session state can potentially - * (and most probably will) be overwritten by the last tab to be opened, - * which can lead to errors when either of the forms in each is finally - * submitted. - *

If you need to have per-form, per-session state management (that is, - * stateful web conversations), the recommendation is to use - * Spring WebFlow, - * which has full support for conversations and has a much more flexible - * usage model overall. - * @param sessionForm {@code true} if session form mode is to be activated - */ - public final void setSessionForm(boolean sessionForm) { - this.sessionForm = sessionForm; - } - - /** - * Return {@code true} if session form mode is activated. - */ - public final boolean isSessionForm() { - return this.sessionForm; - } - - - /** - * Handles two cases: form submissions and showing a new form. - * Delegates the decision between the two to {@link #isFormSubmission}, - * always treating requests without existing form session attribute - * as new form when using session form mode. - * @see #isFormSubmission - * @see #showNewForm - * @see #processFormSubmission - */ - @Override - protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) - throws Exception { - - // Form submission or new form to show? - if (isFormSubmission(request)) { - // Fetch form object from HTTP session, bind, validate, process submission. - try { - Object command = getCommand(request); - ServletRequestDataBinder binder = bindAndValidate(request, command); - BindException errors = new BindException(binder.getBindingResult()); - return processFormSubmission(request, response, command, errors); - } - catch (HttpSessionRequiredException ex) { - // Cannot submit a session form if no form object is in the session. - if (logger.isDebugEnabled()) { - logger.debug("Invalid submit detected: " + ex.getMessage()); - } - return handleInvalidSubmit(request, response); - } - } - - else { - // New form to show: render form view. - return showNewForm(request, response); - } - } - - /** - * Determine if the given request represents a form submission. - *

The default implementation treats a POST request as form submission. - * Note: If the form session attribute doesn't exist when using session form - * mode, the request is always treated as new form by handleRequestInternal. - *

Subclasses can override this to use a custom strategy, e.g. a specific - * request parameter (assumably a hidden field or submit button name). - * @param request current HTTP request - * @return if the request represents a form submission - */ - protected boolean isFormSubmission(HttpServletRequest request) { - return "POST".equals(request.getMethod()); - } - - /** - * Return the name of the HttpSession attribute that holds the form object - * for this form controller. - *

The default implementation delegates to the {@link #getFormSessionAttributeName()} - * variant without arguments. - * @param request current HTTP request - * @return the name of the form session attribute, or {@code null} if not in session form mode - * @see #getFormSessionAttributeName - * @see javax.servlet.http.HttpSession#getAttribute - */ - protected String getFormSessionAttributeName(HttpServletRequest request) { - return getFormSessionAttributeName(); - } - - /** - * Return the name of the HttpSession attribute that holds the form object - * for this form controller. - *

Default is an internal name, of no relevance to applications, as the form - * session attribute is not usually accessed directly. Can be overridden to use - * an application-specific attribute name, which allows other code to access - * the session attribute directly. - * @return the name of the form session attribute - * @see javax.servlet.http.HttpSession#getAttribute - */ - protected String getFormSessionAttributeName() { - return getClass().getName() + ".FORM." + getCommandName(); - } - - - /** - * Show a new form. Prepares a backing object for the current form - * and the given request, including checking its validity. - * @param request current HTTP request - * @param response current HTTP response - * @return the prepared form view - * @throws Exception in case of an invalid new form object - * @see #getErrorsForNewForm - */ - protected final ModelAndView showNewForm(HttpServletRequest request, HttpServletResponse response) - throws Exception { - - logger.debug("Displaying new form"); - return showForm(request, response, getErrorsForNewForm(request)); - } - - /** - * Create a BindException instance for a new form. - * Called by {@link #showNewForm}. - *

Can be used directly when intending to show a new form but with - * special errors registered on it (for example, on invalid submit). - * Usually, the resulting BindException will be passed to - * {@link #showForm(HttpServletRequest, HttpServletResponse, BindException)}, - * after registering the errors on it. - * @param request current HTTP request - * @return the BindException instance - * @throws Exception in case of an invalid new form object - * @see #showNewForm - * @see #showForm(HttpServletRequest, HttpServletResponse, BindException) - * @see #handleInvalidSubmit - */ - protected final BindException getErrorsForNewForm(HttpServletRequest request) throws Exception { - // Create form-backing object for new form. - Object command = formBackingObject(request); - if (command == null) { - throw new ServletException("Form object returned by formBackingObject() must not be null"); - } - if (!checkCommand(command)) { - throw new ServletException("Form object returned by formBackingObject() must match commandClass"); - } - - // Bind without validation, to allow for prepopulating a form, and for - // convenient error evaluation in views (on both first attempt and resubmit). - ServletRequestDataBinder binder = createBinder(request, command); - BindException errors = new BindException(binder.getBindingResult()); - if (isBindOnNewForm()) { - logger.debug("Binding to new form"); - binder.bind(request); - onBindOnNewForm(request, command, errors); - } - - // Return BindException object that resulted from binding. - return errors; - } - - /** - * Callback for custom post-processing in terms of binding for a new form. - * Called when preparing a new form if {@code bindOnNewForm} is {@code true}. - *

The default implementation delegates to {@code onBindOnNewForm(request, command)}. - * @param request current HTTP request - * @param command the command object to perform further binding on - * @param errors validation errors holder, allowing for additional - * custom registration of binding errors - * @throws Exception in case of invalid state or arguments - * @see #onBindOnNewForm(javax.servlet.http.HttpServletRequest, Object) - * @see #setBindOnNewForm - */ - protected void onBindOnNewForm(HttpServletRequest request, Object command, BindException errors) - throws Exception { - - onBindOnNewForm(request, command); - } - - /** - * Callback for custom post-processing in terms of binding for a new form. - *

Called by the default implementation of the - * {@link #onBindOnNewForm(HttpServletRequest, Object, BindException)} variant - * with all parameters, after standard binding when displaying the form view. - * Only called if {@code bindOnNewForm} is set to {@code true}. - *

The default implementation is empty. - * @param request current HTTP request - * @param command the command object to perform further binding on - * @throws Exception in case of invalid state or arguments - * @see #onBindOnNewForm(HttpServletRequest, Object, BindException) - * @see #setBindOnNewForm(boolean) - */ - protected void onBindOnNewForm(HttpServletRequest request, Object command) throws Exception { - } - - - /** - * Return the form object for the given request. - *

Calls {@link #formBackingObject} if not in session form mode. - * Else, retrieves the form object from the session. Note that the form object - * gets removed from the session, but it will be re-added when showing the - * form for resubmission. - * @param request current HTTP request - * @return object form to bind onto - * @throws org.springframework.web.HttpSessionRequiredException - * if a session was expected but no active session (or session form object) found - * @throws Exception in case of invalid state or arguments - * @see #formBackingObject - */ - @Override - protected final Object getCommand(HttpServletRequest request) throws Exception { - // If not in session-form mode, create a new form-backing object. - if (!isSessionForm()) { - return formBackingObject(request); - } - - // Session-form mode: retrieve form object from HTTP session attribute. - HttpSession session = request.getSession(false); - if (session == null) { - throw new HttpSessionRequiredException("Must have session when trying to bind (in session-form mode)"); - } - String formAttrName = getFormSessionAttributeName(request); - Object sessionFormObject = session.getAttribute(formAttrName); - if (sessionFormObject == null) { - throw new HttpSessionRequiredException("Form object not found in session (in session-form mode)"); - } - - // Remove form object from HTTP session: we might finish the form workflow - // in this request. If it turns out that we need to show the form view again, - // we'll re-bind the form object to the HTTP session. - if (logger.isDebugEnabled()) { - logger.debug("Removing form session attribute [" + formAttrName + "]"); - } - session.removeAttribute(formAttrName); - - return currentFormObject(request, sessionFormObject); - } - - /** - * Retrieve a backing object for the current form from the given request. - *

The properties of the form object will correspond to the form field values - * in your form view. This object will be exposed in the model under the specified - * command name, to be accessed under that name in the view: for example, with - * a "spring:bind" tag. The default command name is "command". - *

Note that you need to activate session form mode to reuse the form-backing - * object across the entire form workflow. Else, a new instance of the command - * class will be created for each submission attempt, just using this backing - * object as template for the initial form. - *

The default implementation calls {@link #createCommand()}, - * creating a new empty instance of the specified command class. - * Subclasses can override this to provide a preinitialized backing object. - * @param request current HTTP request - * @return the backing object - * @throws Exception in case of invalid state or arguments - * @see #setCommandName - * @see #setCommandClass - * @see #createCommand - */ - protected Object formBackingObject(HttpServletRequest request) throws Exception { - return createCommand(); - } - - /** - * Return the current form object to use for binding and further processing, - * based on the passed-in form object as found in the HttpSession. - *

The default implementation simply returns the session form object as-is. - * Subclasses can override this to post-process the session form object, - * for example reattaching it to a persistence manager. - * @param sessionFormObject the form object retrieved from the HttpSession - * @return the form object to use for binding and further processing - * @throws Exception in case of invalid state or arguments - */ - protected Object currentFormObject(HttpServletRequest request, Object sessionFormObject) throws Exception { - return sessionFormObject; - } - - - /** - * Prepare the form model and view, including reference and error data. - * Can show a configured form page, or generate a form view programmatically. - *

A typical implementation will call - * {@code showForm(request, errors, "myView")} - * to prepare the form view for a specific view name, returning the - * ModelAndView provided there. - *

For building a custom ModelAndView, call {@code errors.getModel()} - * to populate the ModelAndView model with the command and the Errors instance, - * under the specified command name, as expected by the "spring:bind" tag. - * You also need to include the model returned by {@link #referenceData}. - *

Note: If you decide to have a "formView" property specifying the - * view name, consider using SimpleFormController. - * @param request current HTTP request - * @param response current HTTP response - * @param errors validation errors holder - * @return the prepared form view, or {@code null} if handled directly - * @throws Exception in case of invalid state or arguments - * @see #showForm(HttpServletRequest, BindException, String) - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - * @see #referenceData(HttpServletRequest, Object, Errors) - * @see SimpleFormController#setFormView - */ - protected abstract ModelAndView showForm( - HttpServletRequest request, HttpServletResponse response, BindException errors) - throws Exception; - - /** - * Prepare model and view for the given form, including reference and errors. - *

In session form mode: Re-puts the form object in the session when - * returning to the form, as it has been removed by getCommand. - *

Can be used in subclasses to redirect back to a specific form page. - * @param request current HTTP request - * @param errors validation errors holder - * @param viewName name of the form view - * @return the prepared form view - * @throws Exception in case of invalid state or arguments - */ - protected final ModelAndView showForm(HttpServletRequest request, BindException errors, String viewName) - throws Exception { - - return showForm(request, errors, viewName, null); - } - - /** - * Prepare model and view for the given form, including reference and errors, - * adding a controller-specific control model. - *

In session form mode: Re-puts the form object in the session when returning - * to the form, as it has been removed by getCommand. - *

Can be used in subclasses to redirect back to a specific form page. - * @param request current HTTP request - * @param errors validation errors holder - * @param viewName name of the form view - * @param controlModel model map containing controller-specific control data - * (e.g. current page in wizard-style controllers or special error message) - * @return the prepared form view - * @throws Exception in case of invalid state or arguments - */ - protected final ModelAndView showForm( - HttpServletRequest request, BindException errors, String viewName, Map controlModel) - throws Exception { - - // In session form mode, re-expose form object as HTTP session attribute. - // Re-binding is necessary for proper state handling in a cluster, - // to notify other nodes of changes in the form object. - if (isSessionForm()) { - String formAttrName = getFormSessionAttributeName(request); - if (logger.isDebugEnabled()) { - logger.debug("Setting form session attribute [" + formAttrName + "] to: " + errors.getTarget()); - } - request.getSession().setAttribute(formAttrName, errors.getTarget()); - } - - // Fetch errors model as starting point, containing form object under - // "commandName", and corresponding Errors instance under internal key. - Map model = errors.getModel(); - - // Merge reference data into model, if any. - Map referenceData = referenceData(request, errors.getTarget(), errors); - if (referenceData != null) { - model.putAll(referenceData); - } - - // Merge control attributes into model, if any. - if (controlModel != null) { - model.putAll(controlModel); - } - - // Trigger rendering of the specified view, using the final model. - return new ModelAndView(viewName, model); - } - - /** - * Create a reference data map for the given request, consisting of - * bean name/bean instance pairs as expected by ModelAndView. - *

The default implementation returns {@code null}. - * Subclasses can override this to set reference data used in the view. - * @param request current HTTP request - * @param command form object with request parameters bound onto it - * @param errors validation errors holder - * @return a Map with reference data entries, or {@code null} if none - * @throws Exception in case of invalid state or arguments - * @see ModelAndView - */ - protected Map referenceData(HttpServletRequest request, Object command, Errors errors) throws Exception { - return null; - } - - - /** - * Process form submission request. Called by {@link #handleRequestInternal} - * in case of a form submission, with or without binding errors. Implementations - * need to proceed properly, typically showing a form view in case of binding - * errors or performing a submit action else. - *

Subclasses can implement this to provide custom submission handling like - * triggering a custom action. They can also provide custom validation and call - * {@link #showForm(HttpServletRequest, HttpServletResponse, BindException)} - * or proceed with the submission accordingly. - *

For a success view, call {@code errors.getModel()} to populate the - * ModelAndView model with the command and the Errors instance, under the - * specified command name, as expected by the "spring:bind" tag. For a form view, - * simply return the ModelAndView object provided by - * {@link #showForm(HttpServletRequest, HttpServletResponse, BindException)}. - * @param request current servlet request - * @param response current servlet response - * @param command form object with request parameters bound onto it - * @param errors holder without errors (subclass can add errors if it wants to) - * @return the prepared model and view, or {@code null} - * @throws Exception in case of errors - * @see #handleRequestInternal - * @see #isFormSubmission - * @see #showForm(HttpServletRequest, HttpServletResponse, BindException) - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - */ - protected abstract ModelAndView processFormSubmission( - HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) - throws Exception; - - /** - * Handle an invalid submit request, e.g. when in session form mode but no form object - * was found in the session (like in case of an invalid resubmit by the browser). - *

The default implementation simply tries to resubmit the form with a new - * form object. This should also work if the user hit the back button, changed - * some form data, and resubmitted the form. - *

Note: To avoid duplicate submissions, you need to override this method. - * Either show some "invalid submit" message, or call {@link #showNewForm} for - * resetting the form (prepopulating it with the current values if "bindOnNewForm" - * is true). In this case, the form object in the session serves as transaction token. - *

-	 * protected ModelAndView handleInvalidSubmit(HttpServletRequest request, HttpServletResponse response) throws Exception {
-	 *   return showNewForm(request, response);
-	 * }
- * You can also show a new form but with special errors registered on it: - *
-	 * protected ModelAndView handleInvalidSubmit(HttpServletRequest request, HttpServletResponse response) throws Exception {
-	 *   BindException errors = getErrorsForNewForm(request);
-	 *   errors.reject("duplicateFormSubmission", "Duplicate form submission");
-	 *   return showForm(request, response, errors);
-	 * }
- * @param request current HTTP request - * @param response current HTTP response - * @return a prepared view, or {@code null} if handled directly - * @throws Exception in case of errors - * @see #showNewForm - * @see #getErrorsForNewForm - * @see #showForm(HttpServletRequest, HttpServletResponse, BindException) - * @see #setBindOnNewForm - */ - protected ModelAndView handleInvalidSubmit(HttpServletRequest request, HttpServletResponse response) - throws Exception { - - Object command = formBackingObject(request); - ServletRequestDataBinder binder = bindAndValidate(request, command); - BindException errors = new BindException(binder.getBindingResult()); - return processFormSubmission(request, response, command, errors); - } - -} diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/AbstractWizardFormController.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/AbstractWizardFormController.java deleted file mode 100644 index a53836a7a4..0000000000 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/AbstractWizardFormController.java +++ /dev/null @@ -1,751 +0,0 @@ -/* - * Copyright 2002-2012 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.HashMap; -import java.util.Map; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.validation.BindException; -import org.springframework.validation.Errors; -import org.springframework.web.servlet.ModelAndView; -import org.springframework.web.util.WebUtils; - -/** - * Form controller for typical wizard-style workflows. - * - *

In contrast to classic forms, wizards have more than one form view page. - * Therefore, there are various actions instead of one single submit action: - *

- * - *

Finish and cancel actions can be triggered by request parameters, named - * PARAM_FINISH ("_finish") and PARAM_CANCEL ("_cancel"), ignoring parameter - * values to allow for HTML buttons. The target page for page changes can be - * specified by PARAM_TARGET, appending the page number to the parameter name - * (e.g. "_target1"). The action parameters are recognized when triggered by - * image buttons too (via "_finish.x", "_abort.x", or "_target1.x"). - * - *

The current page number will be stored in the session. It can also be - * specified as request parameter PARAM_PAGE ("_page") in order to properly handle - * usage of the back button in a browser: In this case, a submission will always - * contain the correct page number, even if the user submitted from an old view. - * - *

The page can only be changed if it validates correctly, except if a - * "dirty back" or "dirty forward" is allowed. At finish, all pages get - * validated again to guarantee a consistent state. - * - *

Note that a validator's default validate method is not executed when using - * this class! Rather, the {@link #validatePage} implementation should call - * special {@code validateXXX} methods that the validator needs to provide, - * validating certain pieces of the object. These can be combined to validate - * the elements of individual pages. - * - *

Note: Page numbering starts with 0, to be able to pass an array - * consisting of the corresponding view names to the "pages" bean property. - * - * @author Juergen Hoeller - * @since 25.04.2003 - * @see #setPages - * @see #validatePage - * @see #processFinish - * @see #processCancel - * @deprecated as of Spring 3.0, in favor of annotated controllers - */ -@Deprecated -public abstract class AbstractWizardFormController extends AbstractFormController { - - /** - * Parameter triggering the finish action. - * Can be called from any wizard page! - */ - public static final String PARAM_FINISH = "_finish"; - - /** - * Parameter triggering the cancel action. - * Can be called from any wizard page! - */ - public static final String PARAM_CANCEL = "_cancel"; - - /** - * Parameter specifying the target page, - * appending the page number to the name. - */ - public static final String PARAM_TARGET = "_target"; - - /** - * Parameter specifying the current page as value. Not necessary on - * form pages, but allows to properly handle usage of the back button. - * @see #setPageAttribute - */ - public static final String PARAM_PAGE = "_page"; - - - private String[] pages; - - private String pageAttribute; - - private boolean allowDirtyBack = true; - - private boolean allowDirtyForward = false; - - - /** - * Create a new AbstractWizardFormController. - *

"sessionForm" is automatically turned on, "validateOnBinding" - * turned off, and "cacheSeconds" set to 0 by the base class - * (-> no caching for all form controllers). - */ - public AbstractWizardFormController() { - // AbstractFormController sets default cache seconds to 0. - super(); - - // Always needs session to keep data from all pages. - setSessionForm(true); - - // Never validate everything on binding -> - // wizards validate individual pages. - setValidateOnBinding(false); - } - - /** - * Set the wizard pages, i.e. the view names for the pages. - * The array index is interpreted as page number. - * @param pages view names for the pages - */ - public final void setPages(String[] pages) { - if (pages == null || pages.length == 0) { - throw new IllegalArgumentException("No wizard pages defined"); - } - this.pages = pages; - } - - /** - * Return the wizard pages, i.e. the view names for the pages. - * The array index corresponds to the page number. - *

Note that a concrete wizard form controller might override - * {@link #getViewName(HttpServletRequest, Object, int)} to - * determine the view name for each page dynamically. - * @see #getViewName(javax.servlet.http.HttpServletRequest, Object, int) - */ - public final String[] getPages() { - return this.pages; - } - - /** - * Return the number of wizard pages. - * Useful to check whether the last page has been reached. - *

Note that a concrete wizard form controller might override - * {@link #getPageCount(HttpServletRequest, Object)} to determine - * the page count dynamically. The default implementation of that extended - * {@code getPageCount} variant returns the static page count as - * determined by this {@code getPageCount()} method. - * @see #getPageCount(javax.servlet.http.HttpServletRequest, Object) - */ - protected final int getPageCount() { - return this.pages.length; - } - - /** - * Set the name of the page attribute in the model, containing - * an Integer with the current page number. - *

This will be necessary for single views rendering multiple view pages. - * It also allows for specifying the optional "_page" parameter. - * @param pageAttribute name of the page attribute - * @see #PARAM_PAGE - */ - public final void setPageAttribute(String pageAttribute) { - this.pageAttribute = pageAttribute; - } - - /** - * Return the name of the page attribute in the model. - */ - public final String getPageAttribute() { - return this.pageAttribute; - } - - /** - * Set if "dirty back" is allowed, that is, if moving to a former wizard - * page is allowed in case of validation errors for the current page. - * @param allowDirtyBack if "dirty back" is allowed - */ - public final void setAllowDirtyBack(boolean allowDirtyBack) { - this.allowDirtyBack = allowDirtyBack; - } - - /** - * Return whether "dirty back" is allowed. - */ - public final boolean isAllowDirtyBack() { - return this.allowDirtyBack; - } - - /** - * Set if "dirty forward" is allowed, that is, if moving to a later wizard - * page is allowed in case of validation errors for the current page. - * @param allowDirtyForward if "dirty forward" is allowed - */ - public final void setAllowDirtyForward(boolean allowDirtyForward) { - this.allowDirtyForward = allowDirtyForward; - } - - /** - * Return whether "dirty forward" is allowed. - */ - public final boolean isAllowDirtyForward() { - return this.allowDirtyForward; - } - - - /** - * Calls page-specific onBindAndValidate method. - */ - @Override - protected final void onBindAndValidate(HttpServletRequest request, Object command, BindException errors) - throws Exception { - - onBindAndValidate(request, command, errors, getCurrentPage(request)); - } - - /** - * Callback for custom post-processing in terms of binding and validation. - * Called on each submit, after standard binding but before page-specific - * validation of this wizard form controller. - *

Note: AbstractWizardFormController does not perform standand - * validation on binding but rather applies page-specific validation - * on processing the form submission. - * @param request current HTTP request - * @param command bound command - * @param errors Errors instance for additional custom validation - * @param page current wizard page - * @throws Exception in case of invalid state or arguments - * @see #bindAndValidate - * @see #processFormSubmission - * @see org.springframework.validation.Errors - */ - protected void onBindAndValidate(HttpServletRequest request, Object command, BindException errors, int page) - throws Exception { - } - - /** - * Consider an explicit finish or cancel request as a form submission too. - * @see #isFinishRequest(javax.servlet.http.HttpServletRequest) - * @see #isCancelRequest(javax.servlet.http.HttpServletRequest) - */ - @Override - protected boolean isFormSubmission(HttpServletRequest request) { - return super.isFormSubmission(request) || isFinishRequest(request) || isCancelRequest(request); - } - - /** - * Calls page-specific referenceData method. - */ - @Override - protected final Map referenceData(HttpServletRequest request, Object command, Errors errors) - throws Exception { - - return referenceData(request, command, errors, getCurrentPage(request)); - } - - /** - * Create a reference data map for the given request, consisting of - * bean name/bean instance pairs as expected by ModelAndView. - *

The default implementation delegates to referenceData(HttpServletRequest, int). - * Subclasses can override this to set reference data used in the view. - * @param request current HTTP request - * @param command form object with request parameters bound onto it - * @param errors validation errors holder - * @param page current wizard page - * @return a Map with reference data entries, or {@code null} if none - * @throws Exception in case of invalid state or arguments - * @see #referenceData(HttpServletRequest, int) - * @see ModelAndView - */ - protected Map referenceData(HttpServletRequest request, Object command, Errors errors, int page) - throws Exception { - - return referenceData(request, page); - } - - /** - * Create a reference data map for the given request, consisting of - * bean name/bean instance pairs as expected by ModelAndView. - *

The default implementation returns {@code null}. - * Subclasses can override this to set reference data used in the view. - * @param request current HTTP request - * @param page current wizard page - * @return a Map with reference data entries, or {@code null} if none - * @throws Exception in case of invalid state or arguments - * @see ModelAndView - */ - protected Map referenceData(HttpServletRequest request, int page) throws Exception { - return null; - } - - - /** - * Show the first page as form view. - *

This can be overridden in subclasses, e.g. to prepare wizard-specific - * error views in case of an Exception. - */ - @Override - protected ModelAndView showForm( - HttpServletRequest request, HttpServletResponse response, BindException errors) - throws Exception { - - return showPage(request, errors, getInitialPage(request, errors.getTarget())); - } - - /** - * Prepare the form model and view, including reference and error data, - * for the given page. Can be used in {@link #processFinish} implementations, - * to show the corresponding page in case of validation errors. - * @param request current HTTP request - * @param errors validation errors holder - * @param page number of page to show - * @return the prepared form view - * @throws Exception in case of invalid state or arguments - */ - protected final ModelAndView showPage(HttpServletRequest request, BindException errors, int page) - throws Exception { - - if (page >= 0 && page < getPageCount(request, errors.getTarget())) { - if (logger.isDebugEnabled()) { - logger.debug("Showing wizard page " + page + " for form bean '" + getCommandName() + "'"); - } - - // Set page session attribute, expose overriding request attribute. - Integer pageInteger = new Integer(page); - String pageAttrName = getPageSessionAttributeName(request); - if (isSessionForm()) { - if (logger.isDebugEnabled()) { - logger.debug("Setting page session attribute [" + pageAttrName + "] to: " + pageInteger); - } - request.getSession().setAttribute(pageAttrName, pageInteger); - } - request.setAttribute(pageAttrName, pageInteger); - - // Set page request attribute for evaluation by views. - Map controlModel = new HashMap(); - if (this.pageAttribute != null) { - controlModel.put(this.pageAttribute, new Integer(page)); - } - String viewName = getViewName(request, errors.getTarget(), page); - return showForm(request, errors, viewName, controlModel); - } - - else { - throw new ServletException("Invalid wizard page number: " + page); - } - } - - /** - * Return the page count for this wizard form controller. - * The default implementation delegates to {@link #getPageCount()}. - *

Can be overridden to dynamically adapt the page count. - * @param request current HTTP request - * @param command the command object as returned by formBackingObject - * @return the current page count - * @see #getPageCount - */ - protected int getPageCount(HttpServletRequest request, Object command) { - return getPageCount(); - } - - /** - * Return the name of the view for the specified page of this wizard form controller. - *

The default implementation takes the view name from the {@link #getPages()} array. - *

Can be overridden to dynamically switch the page view or to return view names - * for dynamically defined pages. - * @param request current HTTP request - * @param command the command object as returned by formBackingObject - * @param page the current page number - * @return the current page count - * @see #getPageCount - */ - protected String getViewName(HttpServletRequest request, Object command, int page) { - return getPages()[page]; - } - - /** - * Return the initial page of the wizard, that is, the page shown at wizard startup. - *

The default implementation delegates to {@link #getInitialPage(HttpServletRequest)}. - * @param request current HTTP request - * @param command the command object as returned by formBackingObject - * @return the initial page number - * @see #getInitialPage(HttpServletRequest) - * @see #formBackingObject - */ - protected int getInitialPage(HttpServletRequest request, Object command) { - return getInitialPage(request); - } - - /** - * Return the initial page of the wizard, that is, the page shown at wizard startup. - *

The default implementation returns 0 for first page. - * @param request current HTTP request - * @return the initial page number - */ - protected int getInitialPage(HttpServletRequest request) { - return 0; - } - - /** - * Return the name of the HttpSession attribute that holds the page object - * for this wizard form controller. - *

The default implementation delegates to the {@link #getPageSessionAttributeName()} - * variant without arguments. - * @param request current HTTP request - * @return the name of the form session attribute, or {@code null} if not in session form mode - * @see #getPageSessionAttributeName - * @see #getFormSessionAttributeName(javax.servlet.http.HttpServletRequest) - * @see javax.servlet.http.HttpSession#getAttribute - */ - protected String getPageSessionAttributeName(HttpServletRequest request) { - return getPageSessionAttributeName(); - } - - /** - * Return the name of the HttpSession attribute that holds the page object - * for this wizard form controller. - *

Default is an internal name, of no relevance to applications, as the form - * session attribute is not usually accessed directly. Can be overridden to use - * an application-specific attribute name, which allows other code to access - * the session attribute directly. - * @return the name of the page session attribute - * @see #getFormSessionAttributeName - * @see javax.servlet.http.HttpSession#getAttribute - */ - protected String getPageSessionAttributeName() { - return getClass().getName() + ".PAGE." + getCommandName(); - } - - /** - * Handle an invalid submit request, e.g. when in session form mode but no form object - * was found in the session (like in case of an invalid resubmit by the browser). - *

The default implementation for wizard form controllers simply shows the initial page - * of a new wizard form. If you want to show some "invalid submit" message, you need - * to override this method. - * @param request current HTTP request - * @param response current HTTP response - * @return a prepared view, or {@code null} if handled directly - * @throws Exception in case of errors - * @see #showNewForm - * @see #setBindOnNewForm - */ - @Override - protected ModelAndView handleInvalidSubmit(HttpServletRequest request, HttpServletResponse response) - throws Exception { - - return showNewForm(request, response); - } - - - /** - * Apply wizard workflow: finish, cancel, page change. - */ - @Override - protected final ModelAndView processFormSubmission( - HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) - throws Exception { - - int currentPage = getCurrentPage(request); - // Remove page session attribute, provide copy as request attribute. - String pageAttrName = getPageSessionAttributeName(request); - if (isSessionForm()) { - if (logger.isDebugEnabled()) { - logger.debug("Removing page session attribute [" + pageAttrName + "]"); - } - request.getSession().removeAttribute(pageAttrName); - } - request.setAttribute(pageAttrName, new Integer(currentPage)); - - // cancel? - if (isCancelRequest(request)) { - if (logger.isDebugEnabled()) { - logger.debug("Cancelling wizard for form bean '" + getCommandName() + "'"); - } - return processCancel(request, response, command, errors); - } - - // finish? - if (isFinishRequest(request)) { - if (logger.isDebugEnabled()) { - logger.debug("Finishing wizard for form bean '" + getCommandName() + "'"); - } - return validatePagesAndFinish(request, response, command, errors, currentPage); - } - - // Normal submit: validate current page and show specified target page. - if (!suppressValidation(request, command, errors)) { - if (logger.isDebugEnabled()) { - logger.debug("Validating wizard page " + currentPage + " for form bean '" + getCommandName() + "'"); - } - validatePage(command, errors, currentPage, false); - } - - // Give subclasses a change to perform custom post-procession - // of the current page and its command object. - postProcessPage(request, command, errors, currentPage); - - int targetPage = getTargetPage(request, command, errors, currentPage); - if (logger.isDebugEnabled()) { - logger.debug("Target page " + targetPage + " requested"); - } - if (targetPage != currentPage) { - if (!errors.hasErrors() || (this.allowDirtyBack && targetPage < currentPage) || - (this.allowDirtyForward && targetPage > currentPage)) { - // Allowed to go to target page. - return showPage(request, errors, targetPage); - } - } - - // Show current page again. - return showPage(request, errors, currentPage); - } - - /** - * Return the current page number. Used by {@link #processFormSubmission}. - *

The default implementation checks the page session attribute. - * Subclasses can override this for customized page determination. - * @param request current HTTP request - * @return the current page number - * @see #getPageSessionAttributeName() - */ - protected int getCurrentPage(HttpServletRequest request) { - // Check for overriding attribute in request. - String pageAttrName = getPageSessionAttributeName(request); - Integer pageAttr = (Integer) request.getAttribute(pageAttrName); - if (pageAttr != null) { - return pageAttr.intValue(); - } - // Check for explicit request parameter. - String pageParam = request.getParameter(PARAM_PAGE); - if (pageParam != null) { - return Integer.parseInt(pageParam); - } - // Check for original attribute in session. - if (isSessionForm()) { - pageAttr = (Integer) request.getSession().getAttribute(pageAttrName); - if (pageAttr != null) { - return pageAttr.intValue(); - } - } - throw new IllegalStateException( - "Page attribute [" + pageAttrName + "] neither found in session nor in request"); - } - - /** - * Determine whether the incoming request is a request to finish the - * processing of the current form. - *

By default, this method returns {@code true} if a parameter - * matching the "_finish" key is present in the request, otherwise it - * returns {@code false}. Subclasses may override this method - * to provide custom logic to detect a finish request. - *

The parameter is recognized both when sent as a plain parameter - * ("_finish") or when triggered by an image button ("_finish.x"). - * @param request current HTTP request - * @return whether the request indicates to finish form processing - * @see #PARAM_FINISH - */ - protected boolean isFinishRequest(HttpServletRequest request) { - return WebUtils.hasSubmitParameter(request, PARAM_FINISH); - } - - /** - * Determine whether the incoming request is a request to cancel the - * processing of the current form. - *

By default, this method returns {@code true} if a parameter - * matching the "_cancel" key is present in the request, otherwise it - * returns {@code false}. Subclasses may override this method - * to provide custom logic to detect a cancel request. - *

The parameter is recognized both when sent as a plain parameter - * ("_cancel") or when triggered by an image button ("_cancel.x"). - * @return whether the request indicates to cancel form processing - * @param request current HTTP request - * @see #PARAM_CANCEL - */ - protected boolean isCancelRequest(HttpServletRequest request) { - return WebUtils.hasSubmitParameter(request, PARAM_CANCEL); - } - - /** - * Return the target page specified in the request. - *

The default implementation delegates to {@link #getTargetPage(HttpServletRequest, int)}. - * Subclasses can override this for customized target page determination. - * @param request current HTTP request - * @param command form object with request parameters bound onto it - * @param errors validation errors holder - * @param currentPage the current page, to be returned as fallback - * if no target page specified - * @return the page specified in the request, or current page if not found - * @see #getTargetPage(HttpServletRequest, int) - */ - protected int getTargetPage(HttpServletRequest request, Object command, Errors errors, int currentPage) { - return getTargetPage(request, currentPage); - } - - /** - * Return the target page specified in the request. - *

The default implementation examines "_target" parameter (e.g. "_target1"). - * Subclasses can override this for customized target page determination. - * @param request current HTTP request - * @param currentPage the current page, to be returned as fallback - * if no target page specified - * @return the page specified in the request, or current page if not found - * @see #PARAM_TARGET - */ - protected int getTargetPage(HttpServletRequest request, int currentPage) { - return WebUtils.getTargetPage(request, PARAM_TARGET, currentPage); - } - - /** - * Validate all pages and process finish. - * If there are page validation errors, show the corresponding view page. - */ - private ModelAndView validatePagesAndFinish( - HttpServletRequest request, HttpServletResponse response, Object command, BindException errors, - int currentPage) throws Exception { - - // In case of binding errors -> show current page. - if (errors.hasErrors()) { - return showPage(request, errors, currentPage); - } - - if (!suppressValidation(request, command, errors)) { - // In case of remaining errors on a page -> show the page. - for (int page = 0; page < getPageCount(request, command); page++) { - validatePage(command, errors, page, true); - if (errors.hasErrors()) { - return showPage(request, errors, page); - } - } - } - - // No remaining errors -> proceed with finish. - return processFinish(request, response, command, errors); - } - - - /** - * Template method for custom validation logic for individual pages. - * The default implementation calls {@link #validatePage(Object, Errors, int)}. - *

Implementations will typically call fine-granular {@code validateXXX} - * methods of this instance's Validator, combining them to validation of the - * corresponding pages. The Validator's default {@code validate} method - * will not be called by a wizard form controller! - * @param command form object with the current wizard state - * @param errors validation errors holder - * @param page number of page to validate - * @param finish whether this method is called during final revalidation on finish - * (else, it is called for validating the current page) - * @see #validatePage(Object, Errors, int) - * @see org.springframework.validation.Validator#validate - */ - protected void validatePage(Object command, Errors errors, int page, boolean finish) { - validatePage(command, errors, page); - } - - /** - * Template method for custom validation logic for individual pages. - * The default implementation is empty. - *

Implementations will typically call fine-granular validateXXX methods of this - * instance's validator, combining them to validation of the corresponding pages. - * The validator's default {@code validate} method will not be called by a - * wizard form controller! - * @param command form object with the current wizard state - * @param errors validation errors holder - * @param page number of page to validate - * @see org.springframework.validation.Validator#validate - */ - protected void validatePage(Object command, Errors errors, int page) { - } - - /** - * Post-process the given page after binding and validation, potentially - * updating its command object. The passed-in request might contain special - * parameters sent by the page. - *

Only invoked when displaying another page or the same page again, - * not when finishing or cancelling. - * @param request current HTTP request - * @param command form object with request parameters bound onto it - * @param errors validation errors holder - * @param page number of page to post-process - * @throws Exception in case of invalid state or arguments - */ - protected void postProcessPage(HttpServletRequest request, Object command, Errors errors, int page) - throws Exception { - } - - /** - * Template method for processing the final action of this wizard. - *

Call {@code errors.getModel()} to populate the ModelAndView model - * with the command and the Errors instance, under the specified command name, - * as expected by the "spring:bind" tag. - *

You can call the {@link #showPage} method to return back to the wizard, - * in case of last-minute validation errors having been found that you would - * like to present to the user within the original wizard form. - * @param request current HTTP request - * @param response current HTTP response - * @param command form object with the current wizard state - * @param errors validation errors holder - * @return the finish view - * @throws Exception in case of invalid state or arguments - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - * @see #showPage(javax.servlet.http.HttpServletRequest, org.springframework.validation.BindException, int) - */ - protected abstract ModelAndView processFinish( - HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) - throws Exception; - - /** - * Template method for processing the cancel action of this wizard. - *

The default implementation throws a ServletException, saying that a cancel - * operation is not supported by this controller. Thus, you do not need to - * implement this template method if you do not support a cancel operation. - *

Call {@code errors.getModel()} to populate the ModelAndView model - * with the command and the Errors instance, under the specified command name, - * as expected by the "spring:bind" tag. - * @param request current HTTP request - * @param response current HTTP response - * @param command form object with the current wizard state - * @param errors Errors instance containing errors - * @return the cancellation view - * @throws Exception in case of invalid state or arguments - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - */ - protected ModelAndView processCancel( - HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) - throws Exception { - - throw new ServletException( - "Wizard form controller class [" + getClass().getName() + "] does not support a cancel operation"); - } - -} diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/BaseCommandController.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/BaseCommandController.java deleted file mode 100644 index 2f47edaa25..0000000000 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/BaseCommandController.java +++ /dev/null @@ -1,595 +0,0 @@ -/* - * Copyright 2002-2012 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 org.springframework.beans.BeanUtils; -import org.springframework.beans.PropertyEditorRegistrar; -import org.springframework.validation.BindException; -import org.springframework.validation.BindingErrorProcessor; -import org.springframework.validation.MessageCodesResolver; -import org.springframework.validation.ValidationUtils; -import org.springframework.validation.Validator; -import org.springframework.web.bind.ServletRequestDataBinder; -import org.springframework.web.bind.support.WebBindingInitializer; -import org.springframework.web.context.request.ServletWebRequest; - -/** - *

Controller implementation which creates an object (the command object) on - * receipt of a request and attempts to populate this object with request parameters.

- * - *

This controller is the base for all controllers wishing to populate - * JavaBeans based on request parameters, validate the content of such - * JavaBeans using {@link org.springframework.validation.Validator Validators} - * and use custom editors (in the form of - * {@link java.beans.PropertyEditor PropertyEditors}) to transform - * objects into strings and vice versa, for example. Three notions are mentioned here:

- * - *

Command class:
- * An instance of the command class will be created for each request and populated - * with request parameters. A command class can basically be any Java class; the only - * requirement is a no-arg constructor. The command class should preferably be a - * JavaBean in order to be able to populate bean properties with request parameters.

- * - *

Populating using request parameters and PropertyEditors:
- * Upon receiving a request, any BaseCommandController will attempt to fill the - * command object using the request parameters. This is done using the typical - * and well-known JavaBeans property notation. When a request parameter named - * {@code 'firstName'} exists, the framework will attempt to call - * {@code setFirstName([value])} passing the value of the parameter. Nested properties - * are of course supported. For instance a parameter named {@code 'address.city'} - * will result in a {@code getAddress().setCity([value])} call on the - * command class.

- * - *

It's important to realise that you are not limited to String arguments in - * your JavaBeans. Using the PropertyEditor-notion as supplied by the - * java.beans package, you will be able to transform Strings to Objects and - * the other way around. For instance {@code setLocale(Locale loc)} is - * perfectly possible for a request parameter named {@code locale} having - * a value of {@code en}, as long as you register the appropriate - * PropertyEditor in the Controller (see {@link #initBinder initBinder()} - * for more information on that matter.

- * - *

Validators: - * After the controller has successfully populated the command object with - * parameters from the request, it will use any configured validators to - * validate the object. Validation results will be put in a - * {@link org.springframework.validation.Errors Errors} object which can be - * used in a View to render any input problems.

- * - *

Workflow - * (and that defined by superclass):
- * Since this class is an abstract base class for more specific implementation, - * it does not override the handleRequestInternal() method and also has no - * actual workflow. Implementing classes like - * {@link AbstractFormController AbstractFormController}, - * {@link AbstractCommandController AbstractcommandController}, - * {@link SimpleFormController SimpleFormController} and - * {@link AbstractWizardFormController AbstractWizardFormController} - * provide actual functionality and workflow. - * More information on workflow performed by superclasses can be found - * here.

- * - *

Exposed configuration properties - * (and those defined by superclass):
- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
name - * defaultdescription
commandNamecommandthe name to use when binding the instantiated command class - * to the request
commandClassnullthe class to use upon receiving a request and which to fill - * using the request parameters. What object is used and whether - * or not it should be created is defined by extending classes - * and their configuration properties and methods.
validatorsnullArray of Validator beans. The validator will be called at appropriate - * places in the workflow of subclasses (have a look at those for more info) - * to validate the command object.
validatornullShort-form property for setting only one Validator bean (usually passed in - * using a <ref bean="beanId"/> property.
validateOnBindingtrueIndicates whether or not to validate the command object after the - * object has been populated with request parameters.
- *

- * - * @author Rod Johnson - * @author Juergen Hoeller - * @deprecated as of Spring 3.0, in favor of annotated controllers - */ -@Deprecated -public abstract class BaseCommandController extends AbstractController { - - /** Default command name used for binding command objects: "command" */ - public static final String DEFAULT_COMMAND_NAME = "command"; - - - private String commandName = DEFAULT_COMMAND_NAME; - - private Class commandClass; - - private Validator[] validators; - - private boolean validateOnBinding = true; - - private MessageCodesResolver messageCodesResolver; - - private BindingErrorProcessor bindingErrorProcessor; - - private PropertyEditorRegistrar[] propertyEditorRegistrars; - - private WebBindingInitializer webBindingInitializer; - - - /** - * Set the name of the command in the model. - * The command object will be included in the model under this name. - */ - public final void setCommandName(String commandName) { - this.commandName = commandName; - } - - /** - * Return the name of the command in the model. - */ - public final String getCommandName() { - return this.commandName; - } - - /** - * Set the command class for this controller. - * An instance of this class gets populated and validated on each request. - */ - public final void setCommandClass(Class commandClass) { - this.commandClass = commandClass; - } - - /** - * Return the command class for this controller. - */ - public final Class getCommandClass() { - return this.commandClass; - } - - /** - * Set the primary Validator for this controller. The Validator - * must support the specified command class. If there are one - * or more existing validators set already when this method is - * called, only the specified validator will be kept. Use - * {@link #setValidators(Validator[])} to set multiple validators. - */ - public final void setValidator(Validator validator) { - this.validators = new Validator[] {validator}; - } - - /** - * Return the primary Validator for this controller. - */ - public final Validator getValidator() { - return (this.validators != null && this.validators.length > 0 ? this.validators[0] : null); - } - - /** - * Set the Validators for this controller. - * The Validator must support the specified command class. - */ - public final void setValidators(Validator[] validators) { - this.validators = validators; - } - - /** - * Return the Validators for this controller. - */ - public final Validator[] getValidators() { - return this.validators; - } - - /** - * Set if the Validator should get applied when binding. - */ - public final void setValidateOnBinding(boolean validateOnBinding) { - this.validateOnBinding = validateOnBinding; - } - - /** - * Return if the Validator should get applied when binding. - */ - public final boolean isValidateOnBinding() { - return this.validateOnBinding; - } - - /** - * Set the strategy to use for resolving errors into message codes. - * Applies the given strategy to all data binders used by this controller. - *

Default is {@code null}, i.e. using the default strategy of - * the data binder. - * @see #createBinder - * @see org.springframework.validation.DataBinder#setMessageCodesResolver - */ - public final void setMessageCodesResolver(MessageCodesResolver messageCodesResolver) { - this.messageCodesResolver = messageCodesResolver; - } - - /** - * Return the strategy to use for resolving errors into message codes (if any). - */ - public final MessageCodesResolver getMessageCodesResolver() { - return this.messageCodesResolver; - } - - /** - * Set the strategy to use for processing binding errors, that is, - * required field errors and {@code PropertyAccessException}s. - *

Default is {@code null}, that is, using the default strategy - * of the data binder. - * @see #createBinder - * @see org.springframework.validation.DataBinder#setBindingErrorProcessor - */ - public final void setBindingErrorProcessor(BindingErrorProcessor bindingErrorProcessor) { - this.bindingErrorProcessor = bindingErrorProcessor; - } - - /** - * Return the strategy to use for processing binding errors (if any). - */ - public final BindingErrorProcessor getBindingErrorProcessor() { - return this.bindingErrorProcessor; - } - - /** - * Specify a single PropertyEditorRegistrar to be applied - * to every DataBinder that this controller uses. - *

Allows for factoring out the registration of PropertyEditors - * to separate objects, as an alternative to {@link #initBinder}. - * @see #initBinder - */ - public final void setPropertyEditorRegistrar(PropertyEditorRegistrar propertyEditorRegistrar) { - this.propertyEditorRegistrars = new PropertyEditorRegistrar[] {propertyEditorRegistrar}; - } - - /** - * Specify multiple PropertyEditorRegistrars to be applied - * to every DataBinder that this controller uses. - *

Allows for factoring out the registration of PropertyEditors - * to separate objects, as an alternative to {@link #initBinder}. - * @see #initBinder - */ - public final void setPropertyEditorRegistrars(PropertyEditorRegistrar[] propertyEditorRegistrars) { - this.propertyEditorRegistrars = propertyEditorRegistrars; - } - - /** - * Return the PropertyEditorRegistrars (if any) to be applied - * to every DataBinder that this controller uses. - */ - public final PropertyEditorRegistrar[] getPropertyEditorRegistrars() { - return this.propertyEditorRegistrars; - } - - /** - * Specify a WebBindingInitializer which will apply pre-configured - * configuration to every DataBinder that this controller uses. - *

Allows for factoring out the entire binder configuration - * to separate objects, as an alternative to {@link #initBinder}. - */ - public final void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) { - this.webBindingInitializer = webBindingInitializer; - } - - /** - * Return the WebBindingInitializer (if any) which will apply pre-configured - * configuration to every DataBinder that this controller uses. - */ - public final WebBindingInitializer getWebBindingInitializer() { - return this.webBindingInitializer; - } - - - @Override - protected void initApplicationContext() { - if (this.validators != null) { - for (int i = 0; i < this.validators.length; i++) { - if (this.commandClass != null && !this.validators[i].supports(this.commandClass)) - throw new IllegalArgumentException("Validator [" + this.validators[i] + - "] does not support command class [" + - this.commandClass.getName() + "]"); - } - } - } - - - /** - * Retrieve a command object for the given request. - *

The default implementation calls {@link #createCommand}. - * Subclasses can override this. - * @param request current HTTP request - * @return object command to bind onto - * @throws Exception if the command object could not be obtained - * @see #createCommand - */ - protected Object getCommand(HttpServletRequest request) throws Exception { - return createCommand(); - } - - /** - * Create a new command instance for the command class of this controller. - *

This implementation uses {@code BeanUtils.instantiateClass}, - * so the command needs to have a no-arg constructor (supposed to be - * public, but not required to). - * @return the new command instance - * @throws Exception if the command object could not be instantiated - * @see org.springframework.beans.BeanUtils#instantiateClass(Class) - */ - protected final Object createCommand() throws Exception { - if (this.commandClass == null) { - throw new IllegalStateException("Cannot create command without commandClass being set - " + - "either set commandClass or (in a form controller) override formBackingObject"); - } - if (logger.isDebugEnabled()) { - logger.debug("Creating new command of class [" + this.commandClass.getName() + "]"); - } - return BeanUtils.instantiateClass(this.commandClass); - } - - /** - * Check if the given command object is a valid for this controller, - * i.e. its command class. - * @param command the command object to check - * @return if the command object is valid for this controller - */ - protected final boolean checkCommand(Object command) { - return (this.commandClass == null || this.commandClass.isInstance(command)); - } - - - /** - * Bind the parameters of the given request to the given command object. - * @param request current HTTP request - * @param command the command to bind onto - * @return the ServletRequestDataBinder instance for additional custom validation - * @throws Exception in case of invalid state or arguments - */ - protected final ServletRequestDataBinder bindAndValidate(HttpServletRequest request, Object command) - throws Exception { - - ServletRequestDataBinder binder = createBinder(request, command); - BindException errors = new BindException(binder.getBindingResult()); - if (!suppressBinding(request)) { - binder.bind(request); - onBind(request, command, errors); - if (this.validators != null && isValidateOnBinding() && !suppressValidation(request, command, errors)) { - for (int i = 0; i < this.validators.length; i++) { - ValidationUtils.invokeValidator(this.validators[i], command, errors); - } - } - onBindAndValidate(request, command, errors); - } - return binder; - } - - /** - * Return whether to suppress binding for the given request. - *

The default implementation always returns "false". Can be overridden - * in subclasses to suppress validation, for example, if a special - * request parameter is set. - * @param request current HTTP request - * @return whether to suppress binding for the given request - * @see #suppressValidation - */ - protected boolean suppressBinding(HttpServletRequest request) { - return false; - } - - /** - * Create a new binder instance for the given command and request. - *

Called by {@link #bindAndValidate}. Can be overridden to plug in - * custom ServletRequestDataBinder instances. - *

The default implementation creates a standard ServletRequestDataBinder - * and invokes {@link #prepareBinder} and {@link #initBinder}. - *

Note that neither {@link #prepareBinder} nor {@link #initBinder} will - * be invoked automatically if you override this method! Call those methods - * at appropriate points of your overridden method. - * @param request current HTTP request - * @param command the command to bind onto - * @return the new binder instance - * @throws Exception in case of invalid state or arguments - * @see #bindAndValidate - * @see #prepareBinder - * @see #initBinder - */ - protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object command) - throws Exception { - - ServletRequestDataBinder binder = new ServletRequestDataBinder(command, getCommandName()); - prepareBinder(binder); - initBinder(request, binder); - return binder; - } - - /** - * Prepare the given binder, applying the specified MessageCodesResolver, - * BindingErrorProcessor and PropertyEditorRegistrars (if any). - * Called by {@link #createBinder}. - * @param binder the new binder instance - * @see #createBinder - * @see #setMessageCodesResolver - * @see #setBindingErrorProcessor - */ - protected final void prepareBinder(ServletRequestDataBinder binder) { - if (useDirectFieldAccess()) { - binder.initDirectFieldAccess(); - } - if (this.messageCodesResolver != null) { - binder.setMessageCodesResolver(this.messageCodesResolver); - } - if (this.bindingErrorProcessor != null) { - binder.setBindingErrorProcessor(this.bindingErrorProcessor); - } - if (this.propertyEditorRegistrars != null) { - for (int i = 0; i < this.propertyEditorRegistrars.length; i++) { - this.propertyEditorRegistrars[i].registerCustomEditors(binder); - } - } - } - - /** - * Determine whether to use direct field access instead of bean property access. - * Applied by {@link #prepareBinder}. - *

Default is "false". Can be overridden in subclasses. - * @return whether to use direct field access ({@code true}) - * or bean property access ({@code false}) - * @see #prepareBinder - * @see org.springframework.validation.DataBinder#initDirectFieldAccess() - */ - protected boolean useDirectFieldAccess() { - return false; - } - - /** - * Initialize the given binder instance, for example with custom editors. - * Called by {@link #createBinder}. - *

This method allows you to register custom editors for certain fields of your - * command class. For instance, you will be able to transform Date objects into a - * String pattern and back, in order to allow your JavaBeans to have Date properties - * and still be able to set and display them in an HTML interface. - *

The default implementation is empty. - * @param request current HTTP request - * @param binder the new binder instance - * @throws Exception in case of invalid state or arguments - * @see #createBinder - * @see org.springframework.validation.DataBinder#registerCustomEditor - * @see org.springframework.beans.propertyeditors.CustomDateEditor - */ - protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception { - if (this.webBindingInitializer != null) { - this.webBindingInitializer.initBinder(binder, new ServletWebRequest(request)); - } - } - - /** - * Callback for custom post-processing in terms of binding. - * Called on each submit, after standard binding but before validation. - *

The default implementation delegates to {@link #onBind(HttpServletRequest, Object)}. - * @param request current HTTP request - * @param command the command object to perform further binding on - * @param errors validation errors holder, allowing for additional - * custom registration of binding errors - * @throws Exception in case of invalid state or arguments - * @see #bindAndValidate - * @see #onBind(HttpServletRequest, Object) - */ - protected void onBind(HttpServletRequest request, Object command, BindException errors) throws Exception { - onBind(request, command); - } - - /** - * Callback for custom post-processing in terms of binding. - *

Called by the default implementation of the - * {@link #onBind(HttpServletRequest, Object, BindException)} variant - * with all parameters, after standard binding but before validation. - *

The default implementation is empty. - * @param request current HTTP request - * @param command the command object to perform further binding on - * @throws Exception in case of invalid state or arguments - * @see #onBind(HttpServletRequest, Object, BindException) - */ - protected void onBind(HttpServletRequest request, Object command) throws Exception { - } - - /** - * Return whether to suppress validation for the given request. - *

The default implementation delegates to {@link #suppressValidation(HttpServletRequest, Object)}. - * @param request current HTTP request - * @param command the command object to validate - * @param errors validation errors holder, allowing for additional - * custom registration of binding errors - * @return whether to suppress validation for the given request - */ - protected boolean suppressValidation(HttpServletRequest request, Object command, BindException errors) { - return suppressValidation(request, command); - } - - /** - * Return whether to suppress validation for the given request. - *

Called by the default implementation of the - * {@link #suppressValidation(HttpServletRequest, Object, BindException)} variant - * with all parameters. - *

The default implementation delegates to {@link #suppressValidation(HttpServletRequest)}. - * @param request current HTTP request - * @param command the command object to validate - * @return whether to suppress validation for the given request - */ - protected boolean suppressValidation(HttpServletRequest request, Object command) { - return suppressValidation(request); - } - - /** - * Return whether to suppress validation for the given request. - *

Called by the default implementation of the - * {@link #suppressValidation(HttpServletRequest, Object)} variant - * with all parameters. - *

The default implementation is empty. - * @param request current HTTP request - * @return whether to suppress validation for the given request - * @deprecated as of Spring 2.0.4, in favor of the - * {@link #suppressValidation(HttpServletRequest, Object)} variant - */ - @Deprecated - protected boolean suppressValidation(HttpServletRequest request) { - return false; - } - - /** - * Callback for custom post-processing in terms of binding and validation. - * Called on each submit, after standard binding and validation, - * but before error evaluation. - *

The default implementation is empty. - * @param request current HTTP request - * @param command the command object, still allowing for further binding - * @param errors validation errors holder, allowing for additional - * custom validation - * @throws Exception in case of invalid state or arguments - * @see #bindAndValidate - * @see org.springframework.validation.Errors - */ - protected void onBindAndValidate(HttpServletRequest request, Object command, BindException errors) - throws Exception { - } - -} diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/CancellableFormController.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/CancellableFormController.java deleted file mode 100644 index 1bd9ef8970..0000000000 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/CancellableFormController.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2002-2012 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 org.springframework.validation.BindException; -import org.springframework.web.servlet.ModelAndView; -import org.springframework.web.util.WebUtils; - -/** - *

Extension of {@code SimpleFormController} that supports "cancellation" - * of form processing. By default, this controller looks for a given parameter in the - * request, identified by the {@code cancelParamKey}. If this parameter is present, - * then the controller will return the configured {@code cancelView}, otherwise - * processing is passed back to the superclass.

- * - *

Workflow - * (in addition to the superclass):
- *

    - *
  1. Call to {@link #processFormSubmission processFormSubmission} which calls - * {@link #isCancelRequest} to see if the incoming request is to cancel the - * current form entry. By default, {@link #isCancelRequest} returns {@code true} - * if the configured {@code cancelParamKey} exists in the request. - * This behavior can be overridden in subclasses.
  2. - *
  3. If {@link #isCancelRequest} returns {@code false}, then the controller - * will delegate all processing back to {@link SimpleFormController SimpleFormController}, - * otherwise it will call the {@link #onCancel} version with all parameters. - * By default, that method will delegate to the {@link #onCancel} version with just - * the command object, which will in turn simply return the configured - * {@code cancelView}. This behavior can be overridden in subclasses.
  4. - *
- *

- * - *

Thanks to Erwin Bolwidt for submitting the original prototype - * of such a cancellable form controller!

- * - * @author Rob Harrop - * @author Juergen Hoeller - * @since 1.2.3 - * @see #setCancelParamKey - * @see #setCancelView - * @see #isCancelRequest(javax.servlet.http.HttpServletRequest) - * @see #onCancel(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, Object) - * @deprecated as of Spring 3.0, in favor of annotated controllers - */ -@Deprecated -public class CancellableFormController extends SimpleFormController { - - /** - * Default parameter triggering the cancel action. - * Can be called even with validation errors on the form. - */ - private static final String PARAM_CANCEL = "_cancel"; - - - private String cancelParamKey = PARAM_CANCEL; - - private String cancelView; - - - /** - * Set the key of the request parameter used to identify a cancel request. - * Default is "_cancel". - *

The parameter is recognized both when sent as a plain parameter - * ("_cancel") or when triggered by an image button ("_cancel.x"). - */ - public final void setCancelParamKey(String cancelParamKey) { - this.cancelParamKey = cancelParamKey; - } - - /** - * Return the key of the request parameter used to identify a cancel request. - */ - public final String getCancelParamKey() { - return this.cancelParamKey; - } - - /** - * Sets the name of the cancel view. - */ - public final void setCancelView(String cancelView) { - this.cancelView = cancelView; - } - - /** - * Gets the name of the cancel view. - */ - public final String getCancelView() { - return this.cancelView; - } - - - /** - * Consider an explicit cancel request as a form submission too. - * @see #isCancelRequest(javax.servlet.http.HttpServletRequest) - */ - @Override - protected boolean isFormSubmission(HttpServletRequest request) { - return super.isFormSubmission(request) || isCancelRequest(request); - } - - /** - * Suppress validation for an explicit cancel request too. - * @see #isCancelRequest(javax.servlet.http.HttpServletRequest) - */ - @Override - protected boolean suppressValidation(HttpServletRequest request, Object command) { - return super.suppressValidation(request, command) || isCancelRequest(request); - } - - /** - * This implementation first checks to see if the incoming is a cancel request, - * through a call to {@link #isCancelRequest}. If so, control is passed to - * {@link #onCancel}; otherwise, control is passed up to - * {@link SimpleFormController#processFormSubmission}. - * @see #isCancelRequest - * @see #onCancel(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, Object) - * @see SimpleFormController#processFormSubmission - */ - @Override - protected ModelAndView processFormSubmission( - HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) - throws Exception { - - if (isCancelRequest(request)) { - return onCancel(request, response, command); - } - else { - return super.processFormSubmission(request, response, command, errors); - } - } - - /** - * Determine whether the incoming request is a request to cancel the - * processing of the current form. - *

By default, this method returns {@code true} if a parameter - * matching the configured {@code cancelParamKey} is present in - * the request, otherwise it returns {@code false}. Subclasses may - * override this method to provide custom logic to detect a cancel request. - *

The parameter is recognized both when sent as a plain parameter - * ("_cancel") or when triggered by an image button ("_cancel.x"). - * @param request current HTTP request - * @see #setCancelParamKey - * @see #PARAM_CANCEL - */ - protected boolean isCancelRequest(HttpServletRequest request) { - return WebUtils.hasSubmitParameter(request, getCancelParamKey()); - } - - /** - * Callback method for handling a cancel request. Called if {@link #isCancelRequest} - * returns {@code true}. - *

Default implementation delegates to {@code onCancel(Object)} to return - * the configured {@code cancelView}. Subclasses may override either of the two - * methods to build a custom {@link ModelAndView ModelAndView} that may contain model - * parameters used in the cancel view. - *

If you simply want to move the user to a new view and you don't want to add - * additional model parameters, use {@link #setCancelView(String)} rather than - * overriding an {@code onCancel} method. - * @param request current servlet request - * @param response current servlet response - * @param command form object with request parameters bound onto it - * @return the prepared model and view, or {@code null} - * @throws Exception in case of errors - * @see #isCancelRequest(javax.servlet.http.HttpServletRequest) - * @see #onCancel(Object) - * @see #setCancelView - */ - protected ModelAndView onCancel(HttpServletRequest request, HttpServletResponse response, Object command) - throws Exception { - - return onCancel(command); - } - - /** - * Simple {@code onCancel} version. Called by the default implementation - * of the {@code onCancel} version with all parameters. - *

Default implementation returns eturns the configured {@code cancelView}. - * Subclasses may override this method to build a custom {@link ModelAndView ModelAndView} - * that may contain model parameters used in the cancel view. - *

If you simply want to move the user to a new view and you don't want to add - * additional model parameters, use {@link #setCancelView(String)} rather than - * overriding an {@code onCancel} method. - * @param command form object with request parameters bound onto it - * @return the prepared model and view, or {@code null} - * @throws Exception in case of errors - * @see #onCancel(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, Object) - * @see #setCancelView - */ - protected ModelAndView onCancel(Object command) throws Exception { - return new ModelAndView(getCancelView()); - } - -} diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/SimpleFormController.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/SimpleFormController.java deleted file mode 100644 index 030c2dca2c..0000000000 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/SimpleFormController.java +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright 2002-2012 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.Map; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.validation.BindException; -import org.springframework.validation.Errors; -import org.springframework.web.servlet.ModelAndView; - -/** - *

Concrete FormController implementation that provides configurable - * form and success views, and an onSubmit chain for convenient overriding. - * Automatically resubmits to the form view in case of validation errors, - * and renders the success view in case of a valid submission.

- * - *

The workflow of this Controller does not differ much from the one described - * in the {@link AbstractFormController AbstractFormController}. The difference - * is that you do not need to implement {@link #showForm showForm} and - * {@link #processFormSubmission processFormSubmission}: A form view and a - * success view can be configured declaratively.

- * - *

Workflow - * (in addition to the superclass):
- *

    - *
  1. Call to {@link #processFormSubmission processFormSubmission} which inspects - * the {@link org.springframework.validation.Errors Errors} object to see if - * any errors have occurred during binding and validation.
  2. - *
  3. If errors occured, the controller will return the configured formView, - * showing the form again (possibly rendering according error messages).
  4. - *
  5. If {@link #isFormChangeRequest isFormChangeRequest} is overridden and returns - * true for the given request, the controller will return the formView too. - * In that case, the controller will also suppress validation. Before returning the formView, - * the controller will invoke {@link #onFormChange}, giving sub-classes a chance - * to make modification to the command object. - * This is intended for requests that change the structure of the form, - * which should not cause validation and show the form in any case.
  6. - *
  7. If no errors occurred, the controller will call - * {@link #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException) onSubmit} - * using all parameters, which in case of the default implementation delegates to - * {@link #onSubmit(Object, BindException) onSubmit} with just the command object. - * The default implementation of the latter method will return the configured - * {@code successView}. Consider implementing {@link #doSubmitAction} doSubmitAction - * for simply performing a submit action and rendering the success view.
  8. - *
- *

- * - *

The submit behavior can be customized by overriding one of the - * {@link #onSubmit onSubmit} methods. Submit actions can also perform - * custom validation if necessary (typically database-driven checks), calling - * {@link #showForm(HttpServletRequest, HttpServletResponse, BindException) showForm} - * in case of validation errors to show the form view again.

- * - *

Exposed configuration properties - * (and those defined by superclass):
- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
namedefaultdescription
formViewnullIndicates what view to use when the user asks for a new form - * or when validation errors have occurred on form submission.
successViewnullIndicates what view to use when successful form submissions have - * occurred. Such a success view could e.g. display a submission summary. - * More sophisticated actions can be implemented by overriding one of - * the {@link #onSubmit(Object) onSubmit()} methods.
- *

- * - * @author Juergen Hoeller - * @author Rob Harrop - * @since 05.05.2003 - * @deprecated as of Spring 3.0, in favor of annotated controllers - */ -@Deprecated -public class SimpleFormController extends AbstractFormController { - - private String formView; - - private String successView; - - - /** - * Create a new SimpleFormController. - *

Subclasses should set the following properties, either in the constructor - * or via a BeanFactory: commandName, commandClass, sessionForm, formView, - * successView. Note that commandClass doesn't need to be set when overriding - * {@code formBackingObject}, as this determines the class anyway. - * @see #setCommandClass - * @see #setCommandName - * @see #setSessionForm - * @see #setFormView - * @see #setSuccessView - * @see #formBackingObject - */ - public SimpleFormController() { - // AbstractFormController sets default cache seconds to 0. - super(); - } - - /** - * Set the name of the view that should be used for form display. - */ - public final void setFormView(String formView) { - this.formView = formView; - } - - /** - * Return the name of the view that should be used for form display. - */ - public final String getFormView() { - return this.formView; - } - - /** - * Set the name of the view that should be shown on successful submit. - */ - public final void setSuccessView(String successView) { - this.successView = successView; - } - - /** - * Return the name of the view that should be shown on successful submit. - */ - public final String getSuccessView() { - return this.successView; - } - - - /** - * This implementation shows the configured form view, delegating to the analogous - * {@link #showForm(HttpServletRequest, HttpServletResponse, BindException, Map)} - * variant with a "controlModel" argument. - *

Can be called within - * {@link #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException)} - * implementations, to redirect back to the form in case of custom validation errors - * (errors not determined by the validator). - *

Can be overridden in subclasses to show a custom view, writing directly - * to the response or preparing the response before rendering a view. - *

If calling showForm with a custom control model in subclasses, it's preferable - * to override the analogous showForm version with a controlModel argument - * (which will handle both standard form showing and custom form showing then). - * @see #setFormView - * @see #showForm(HttpServletRequest, HttpServletResponse, BindException, Map) - */ - @Override - protected ModelAndView showForm( - HttpServletRequest request, HttpServletResponse response, BindException errors) - throws Exception { - - return showForm(request, response, errors, null); - } - - /** - * This implementation shows the configured form view. - *

Can be called within - * {@link #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException)} - * implementations, to redirect back to the form in case of custom validation errors - * (errors not determined by the validator). - *

Can be overridden in subclasses to show a custom view, writing directly - * to the response or preparing the response before rendering a view. - * @param request current HTTP request - * @param errors validation errors holder - * @param controlModel model map containing controller-specific control data - * (e.g. current page in wizard-style controllers or special error message) - * @return the prepared form view - * @throws Exception in case of invalid state or arguments - * @see #setFormView - */ - protected ModelAndView showForm( - HttpServletRequest request, HttpServletResponse response, BindException errors, Map controlModel) - throws Exception { - - return showForm(request, errors, getFormView(), controlModel); - } - - /** - * Create a reference data map for the given request and command, - * consisting of bean name/bean instance pairs as expected by ModelAndView. - *

The default implementation delegates to {@link #referenceData(HttpServletRequest)}. - * Subclasses can override this to set reference data used in the view. - * @param request current HTTP request - * @param command form object with request parameters bound onto it - * @param errors validation errors holder - * @return a Map with reference data entries, or {@code null} if none - * @throws Exception in case of invalid state or arguments - * @see ModelAndView - */ - @Override - protected Map referenceData(HttpServletRequest request, Object command, Errors errors) throws Exception { - return referenceData(request); - } - - /** - * Create a reference data map for the given request. - * Called by the {@link #referenceData(HttpServletRequest, Object, Errors)} - * variant with all parameters. - *

The default implementation returns {@code null}. - * Subclasses can override this to set reference data used in the view. - * @param request current HTTP request - * @return a Map with reference data entries, or {@code null} if none - * @throws Exception in case of invalid state or arguments - * @see #referenceData(HttpServletRequest, Object, Errors) - * @see ModelAndView - */ - protected Map referenceData(HttpServletRequest request) throws Exception { - return null; - } - - - /** - * This implementation calls - * {@link #showForm(HttpServletRequest, HttpServletResponse, BindException)} - * in case of errors, and delegates to the full - * {@link #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException)}'s - * variant else. - *

This can only be overridden to check for an action that should be executed - * without respect to binding errors, like a cancel action. To just handle successful - * submissions without binding errors, override one of the {@code onSubmit} - * methods or {@link #doSubmitAction}. - * @see #showForm(HttpServletRequest, HttpServletResponse, BindException) - * @see #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException) - * @see #onSubmit(Object, BindException) - * @see #onSubmit(Object) - * @see #doSubmitAction(Object) - */ - @Override - protected ModelAndView processFormSubmission( - HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) - throws Exception { - - if (errors.hasErrors()) { - if (logger.isDebugEnabled()) { - logger.debug("Data binding errors: " + errors.getErrorCount()); - } - return showForm(request, response, errors); - } - else if (isFormChangeRequest(request, command)) { - logger.debug("Detected form change request -> routing request to onFormChange"); - onFormChange(request, response, command, errors); - return showForm(request, response, errors); - } - else { - logger.debug("No errors -> processing submit"); - return onSubmit(request, response, command, errors); - } - } - - /** - * This implementation delegates to {@link #isFormChangeRequest(HttpServletRequest, Object)}: - * A form change request changes the appearance of the form and should not get - * validated but just show the new form. - * @see #isFormChangeRequest - */ - @Override - protected boolean suppressValidation(HttpServletRequest request, Object command) { - return isFormChangeRequest(request, command); - } - - /** - * Determine whether the given request is a form change request. - * A form change request changes the appearance of the form - * and should always show the new form, without validation. - *

Gets called by {@link #suppressValidation} and {@link #processFormSubmission}. - * Consequently, this single method determines to suppress validation - * and to show the form view in any case. - *

The default implementation delegates to - * {@link #isFormChangeRequest(javax.servlet.http.HttpServletRequest)}. - * @param request current HTTP request - * @param command form object with request parameters bound onto it - * @return whether the given request is a form change request - * @see #suppressValidation - * @see #processFormSubmission - */ - protected boolean isFormChangeRequest(HttpServletRequest request, Object command) { - return isFormChangeRequest(request); - } - - /** - * Simpler {@code isFormChangeRequest} variant, called by the full - * variant {@link #isFormChangeRequest(HttpServletRequest, Object)}. - *

The default implementation returns {@code false}. - * @param request current HTTP request - * @return whether the given request is a form change request - * @see #suppressValidation - * @see #processFormSubmission - */ - protected boolean isFormChangeRequest(HttpServletRequest request) { - return false; - } - - /** - * Called during form submission if - * {@link #isFormChangeRequest(javax.servlet.http.HttpServletRequest)} - * returns {@code true}. Allows subclasses to implement custom logic - * to modify the command object to directly modify data in the form. - *

The default implementation delegates to - * {@link #onFormChange(HttpServletRequest, HttpServletResponse, Object, BindException)}. - * @param request current servlet request - * @param response current servlet response - * @param command form object with request parameters bound onto it - * @param errors validation errors holder, allowing for additional - * custom validation - * @throws Exception in case of errors - * @see #isFormChangeRequest(HttpServletRequest) - * @see #onFormChange(HttpServletRequest, HttpServletResponse, Object) - */ - protected void onFormChange( - HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) - throws Exception { - - onFormChange(request, response, command); - } - - /** - * Simpler {@code onFormChange} variant, called by the full variant - * {@link #onFormChange(HttpServletRequest, HttpServletResponse, Object, BindException)}. - *

The default implementation is empty. - * @param request current servlet request - * @param response current servlet response - * @param command form object with request parameters bound onto it - * @throws Exception in case of errors - * @see #onFormChange(HttpServletRequest, HttpServletResponse, Object, BindException) - */ - protected void onFormChange(HttpServletRequest request, HttpServletResponse response, Object command) - throws Exception { - } - - - /** - * Submit callback with all parameters. Called in case of submit without errors - * reported by the registered validator, or on every submit if no validator. - *

The default implementation delegates to {@link #onSubmit(Object, BindException)}. - * For simply performing a submit action and rendering the specified success - * view, consider implementing {@link #doSubmitAction} rather than an - * {@code onSubmit} variant. - *

Subclasses can override this to provide custom submission handling like storing - * the object to the database. Implementations can also perform custom validation and - * call showForm to return to the form. Do not implement multiple onSubmit - * methods: In that case, just this method will be called by the controller. - *

Call {@code errors.getModel()} to populate the ModelAndView model - * with the command and the Errors instance, under the specified command name, - * as expected by the "spring:bind" tag. - * @param request current servlet request - * @param response current servlet response - * @param command form object with request parameters bound onto it - * @param errors Errors instance without errors (subclass can add errors if it wants to) - * @return the prepared model and view, or {@code null} - * @throws Exception in case of errors - * @see #onSubmit(Object, BindException) - * @see #doSubmitAction - * @see #showForm - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - */ - protected ModelAndView onSubmit( - HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) - throws Exception { - - return onSubmit(command, errors); - } - - /** - * Simpler {@code onSubmit} variant. - * Called by the default implementation of the - * {@link #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException)} - * variant with all parameters. - *

The default implementation calls {@link #onSubmit(Object)}, using the - * returned ModelAndView if actually implemented in a subclass. Else, the - * default behavior will apply: rendering the success view with the command - * and Errors instance as model. - *

Subclasses can override this to provide custom submission handling that - * does not need request and response. - *

Call {@code errors.getModel()} to populate the ModelAndView model - * with the command and the Errors instance, under the specified command name, - * as expected by the "spring:bind" tag. - * @param command form object with request parameters bound onto it - * @param errors Errors instance without errors - * @return the prepared model and view - * @throws Exception in case of errors - * @see #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException) - * @see #onSubmit(Object) - * @see #setSuccessView - * @see org.springframework.validation.Errors - * @see org.springframework.validation.BindException#getModel - */ - protected ModelAndView onSubmit(Object command, BindException errors) throws Exception { - ModelAndView mv = onSubmit(command); - if (mv != null) { - // simplest onSubmit variant implemented in custom subclass - return mv; - } - else { - // default behavior: render success view - if (getSuccessView() == null) { - throw new ServletException("successView isn't set"); - } - return new ModelAndView(getSuccessView(), errors.getModel()); - } - } - - /** - * Simplest {@code onSubmit} variant. Called by the default implementation - * of the {@link #onSubmit(Object, BindException)} variant. - *

This implementation calls {@link #doSubmitAction(Object)} and returns - * {@code null} as ModelAndView, making the calling {@code onSubmit} - * method perform its default rendering of the success view. - *

Subclasses can override this to provide custom submission handling - * that just depends on the command object. It's preferable to use either - * {@link #onSubmit(Object, BindException)} or {@link #doSubmitAction(Object)}, - * though: Use the former when you want to build your own ModelAndView; use the - * latter when you want to perform an action and forward to the successView. - * @param command form object with request parameters bound onto it - * @return the prepared model and view, or {@code null} for default - * (that is, rendering the configured "successView") - * @throws Exception in case of errors - * @see #onSubmit(Object, BindException) - * @see #doSubmitAction - * @see #setSuccessView - */ - protected ModelAndView onSubmit(Object command) throws Exception { - doSubmitAction(command); - return null; - } - - /** - * Template method for submit actions. Called by the default implementation - * of the simplest {@link #onSubmit(Object)} variant. - *

This is the preferred submit callback to implement if you want to - * perform an action (like storing changes to the database) and then render - * the success view with the command and Errors instance as model. - * You don't need to care about the success ModelAndView here. - * @param command form object with request parameters bound onto it - * @throws Exception in case of errors - * @see #onSubmit(Object) - * @see #setSuccessView - */ - protected void doSubmitAction(Object command) throws Exception { - } - -} diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/ComplexWebApplicationContext.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/ComplexWebApplicationContext.java index b5b4f0206f..e9b5a1a9ad 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/ComplexWebApplicationContext.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/ComplexWebApplicationContext.java @@ -60,7 +60,6 @@ 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; @@ -111,7 +110,7 @@ public class ComplexWebApplicationContext extends StaticWebApplicationContext { pvs = new MutablePropertyValues(); pvs.add( - "mappings", "/form.do=formHandler\n/head.do=headController\n" + + "mappings", "/head.do=headController\n" + "body.do=bodyController\n/noview*=noviewController\n/noview/simple*=noviewController"); pvs.add("order", "1"); registerSingleton("handlerMapping", SimpleUrlHandlerMapping.class, pvs); @@ -130,11 +129,6 @@ public class ComplexWebApplicationContext extends StaticWebApplicationContext { pvs.add("suffix", ".jsp"); registerSingleton("viewResolver2", InternalResourceViewResolver.class, pvs); - pvs = new MutablePropertyValues(); - pvs.add("commandClass", "org.springframework.tests.sample.beans.TestBean"); - pvs.add("formView", "form"); - registerSingleton("formHandler", SimpleFormController.class, pvs); - pvs = new MutablePropertyValues(); pvs.add("viewName", "form"); registerSingleton("viewHandler", ParameterizableViewController.class, pvs); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java index d5ed530e58..8628ac92a4 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java @@ -18,7 +18,6 @@ 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; @@ -31,7 +30,6 @@ import junit.framework.TestCase; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyValue; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.DummyEnvironment; import org.springframework.mock.web.test.MockHttpServletRequest; @@ -39,7 +37,6 @@ import org.springframework.mock.web.test.MockHttpServletResponse; import org.springframework.mock.web.test.MockServletConfig; import org.springframework.mock.web.test.MockServletContext; import org.springframework.tests.sample.beans.TestBean; -import org.springframework.web.bind.EscapedErrors; import org.springframework.web.context.ConfigurableWebEnvironment; import org.springframework.web.context.ServletConfigAwareBean; import org.springframework.web.context.ServletContextAwareBean; @@ -51,11 +48,8 @@ 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; @@ -155,44 +149,6 @@ public class DispatcherServletTests extends TestCase { 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"); @@ -227,51 +183,6 @@ public class DispatcherServletTests extends TestCase { 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); @@ -568,7 +479,6 @@ public class DispatcherServletTests extends TestCase { 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 { @@ -641,7 +551,6 @@ public class DispatcherServletTests extends TestCase { 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")); @@ -663,12 +572,10 @@ public class DispatcherServletTests extends TestCase { 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 { @@ -685,12 +592,10 @@ public class DispatcherServletTests extends TestCase { 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 { diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/SimpleWebApplicationContext.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/SimpleWebApplicationContext.java index ce525f937d..3855b6cd57 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/SimpleWebApplicationContext.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/SimpleWebApplicationContext.java @@ -34,7 +34,6 @@ 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.support.RequestContextUtils; import org.springframework.web.servlet.theme.AbstractThemeResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver; @@ -52,7 +51,6 @@ public class SimpleWebApplicationContext extends StaticWebApplicationContext { MutablePropertyValues pvs = new MutablePropertyValues(); pvs.add("commandClass", "org.springframework.tests.sample.beans.TestBean"); pvs.add("formView", "form"); - registerSingleton("/form.do", SimpleFormController.class, pvs); registerSingleton("/locale.do", LocaleChecker.class); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/CancellableFormControllerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/CancellableFormControllerTests.java deleted file mode 100644 index ff3ebd962f..0000000000 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/CancellableFormControllerTests.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2002-2013 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.tests.sample.beans.TestBean; -import org.springframework.mock.web.test.MockHttpServletRequest; -import org.springframework.mock.web.test.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() { - @Override - 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; - - @Override - public boolean supports(Class clazz) { - return TestBean.class.isAssignableFrom(clazz); - } - @Override - 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/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/CommandControllerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/CommandControllerTests.java deleted file mode 100644 index da2da2e174..0000000000 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/CommandControllerTests.java +++ /dev/null @@ -1,522 +0,0 @@ -/* - * Copyright 2002-2013 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.tests.sample.beans.TestBean; -import org.springframework.beans.propertyeditors.CustomDateEditor; -import org.springframework.beans.propertyeditors.CustomNumberEditor; -import org.springframework.mock.web.test.MockHttpServletRequest; -import org.springframework.mock.web.test.MockHttpServletResponse; -import org.springframework.mock.web.test.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("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("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 { - @Override - 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() { - @Override - 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() { - @Override - 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() { - @Override - 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("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() { - @Override - 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() { - @Override - 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() { - @Override - 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() { - @Override - 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() { - @Override - 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() { - @Override - protected Object getCommand(HttpServletRequest request) throws Exception { - return new TestBean("original", 99); - } - @Override - 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"); - } - - @Override - 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/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/FormControllerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/FormControllerTests.java deleted file mode 100644 index 3c40caacd6..0000000000 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/FormControllerTests.java +++ /dev/null @@ -1,661 +0,0 @@ -/* - * Copyright 2002-2013 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.tests.sample.beans.IndexedTestBean; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.context.support.StaticApplicationContext; -import org.springframework.mock.web.test.MockHttpServletRequest; -import org.springframework.mock.web.test.MockHttpServletResponse; -import org.springframework.mock.web.test.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 - */ -@Deprecated -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() { - @Override - 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() { - @Override - 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() { - @Override - protected boolean isFormChangeRequest(HttpServletRequest request) { - return (request.getParameter("formChange") != null); - } - - @Override - 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"; - - @Override - public boolean supports(Class clazz) { return true; } - - @Override - 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"; - - @Override - public boolean supports(Class clazz) { return true; } - - @Override - 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); - } - - @Override - protected Object formBackingObject(HttpServletRequest request) throws ServletException { - TestBean person = new TestBean(); - person.setAge(DEFAULT_AGE); - return person; - } - - @Override - protected boolean isFormChangeRequest(HttpServletRequest request) { - return (request.getParameter("formChange") != null); - } - } - - - private static class TestControllerWithCustomOnSubmit extends TestController { - - @Override - 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); - } - - @Override - 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 { - - @Override - protected ModelAndView processFormSubmission - (HttpServletRequest req, HttpServletResponse resp, Object command, BindException errors) throws Exception { - ModelAndView mav = new ModelAndView(); - mav.addObject("command", command); - return mav; - } - - @Override - 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/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/WizardFormControllerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/WizardFormControllerTests.java deleted file mode 100644 index 1d37caff85..0000000000 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/WizardFormControllerTests.java +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright 2002-2013 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.tests.sample.beans.TestBean; -import org.springframework.mock.web.test.MockHttpServletRequest; -import org.springframework.mock.web.test.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 - */ -@Deprecated -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() { - @Override - protected String getFormSessionAttributeName() { - return "myFormAttr"; - } - @Override - 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() { - @Override - protected String getFormSessionAttributeName(HttpServletRequest request) { - return "myFormAttr" + request.getParameter("formAttr"); - } - @Override - 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"}); - } - - @Override - protected Map referenceData(HttpServletRequest request, int page) throws Exception { - assertEquals(new Integer(page), request.getAttribute("target")); - return super.referenceData(request, page); - } - - @Override - protected boolean suppressValidation(HttpServletRequest request, Object command) { - return (request.getParameter("formChange") != null); - } - - @Override - 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"); - } - } - - @Override - 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); - } - - @Override - 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/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/mapping/BuyForm.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/mapping/BuyForm.java index 00f6ea145c..a37e89bcad 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/mapping/BuyForm.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/mapping/BuyForm.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -16,12 +16,17 @@ package org.springframework.web.servlet.mvc.mapping; -import org.springframework.web.servlet.mvc.SimpleFormController; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; -/** - * @author Rob Harrop - */ -@Deprecated -public class BuyForm extends SimpleFormController { +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.Controller; + +public class BuyForm implements Controller { + + @Override + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { + return null; + } }