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):
- *
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):
- *
| name | - *default | - *description | - *
| bindOnNewForm | - *false | - *Indicates whether to bind portlet request parameters when - * creating a new form. Otherwise, the parameters will only be - * bound on form submission attempts. | - *
| sessionForm | - *false | - *Indicates 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). | - *
| redirectAction | - *false | - *Specifies 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. | - *
| renderParameters | - *null | - *An 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 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: Populating using request parameters and PropertyEditors: 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): Exposed configuration properties
- * (and those defined by superclass):
- * 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.
- * 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.
- * 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.
- *
- *
- *
- *
- * name
- * default
- * description
- *
- *
- * commandName
- * command
- * the name to use when binding the instantiated command class
- * to the request
- *
- *
- * commandClass
- * null
- * the 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.
- *
- *
- * validators
- * null
- * Array 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.
- *
- *
- * validator
- * null
- * Short-form property for setting only one Validator bean (usually passed in
- * using a <ref bean="beanId"/> property.
- *
- *
- * validateOnBinding
- * true
- * Indicates 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):
- *
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):
- *
| name | - *default | - *description | - *
| formView | - *null | - *Indicates what view to use when the user asks for a new form - * or when validation errors have occurred on form submission. | - *
| successView | - *null | - *Indicates 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. | - *
| name | - *default | - *description | - *
| bindOnNewForm | - *false | - *Indicates whether to bind servlet request parameters when - * creating a new form. Otherwise, the parameters will only be - * bound on form submission attempts. | - *
| sessionForm | - *false | - *Indicates 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). | - *
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 - * | default | - *description | - *
| commandName | - *command | - *the name to use when binding the instantiated command class - * to the request | - *
| commandClass | - *null | - *the 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. | - *
| validators | - *null | - *Array 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. | - *
| validator | - *null | - *Short-form property for setting only one Validator bean (usually passed in - * using a <ref bean="beanId"/> property. | - *
| validateOnBinding | - *true | - *Indicates whether or not to validate the command object after the - * object has been populated with request parameters. | - *
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):
- *
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):
- *
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):
- *
| name | - *default | - *description | - *
| formView | - *null | - *Indicates what view to use when the user asks for a new form - * or when validation errors have occurred on form submission. | - *
| successView | - *null | - *Indicates 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. | - *