001: /*
002: * Copyright 2002-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.web.portlet.mvc;
018:
019: import javax.portlet.ActionRequest;
020: import javax.portlet.ActionResponse;
021: import javax.portlet.RenderRequest;
022: import javax.portlet.RenderResponse;
023:
024: import org.springframework.validation.BindException;
025: import org.springframework.web.portlet.ModelAndView;
026: import org.springframework.web.portlet.bind.PortletRequestDataBinder;
027:
028: /**
029: * <p>Abstract base class for custom command controllers. Autopopulates a
030: * command bean from the request. For command validation, a validator
031: * (property inherited from BaseCommandController) can be used.</p>
032: *
033: * <p>This command controller should preferrable not be used to handle form
034: * submission, because functionality for forms is more offered in more
035: * detail by the {@link org.springframework.web.portlet.mvc.AbstractFormController
036: * AbstractFormController} and its corresponding implementations.</p>
037: *
038: * <p><b><a name="config">Exposed configuration properties</a>
039: * (<a href="BaseCommandController.html#config">and those defined by superclass</a>):</b><br>
040: * <i>none</i> (so only those available in superclass).</p>
041: *
042: * <p><b><a name="workflow">Workflow
043: * (<a name="BaseCommandController.html#workflow">and that defined by superclass</a>):</b><br>
044: *
045: * @author John A. Lewis
046: * @author Juergen Hoeller
047: * @since 2.0
048: * @see #setCommandClass
049: * @see #setCommandName
050: * @see #setValidator
051: */
052: public abstract class AbstractCommandController extends
053: BaseCommandController {
054:
055: /**
056: * This render parameter is used to indicate forward to the render phase
057: * that a valid command (and errors) object is in the session.
058: */
059: private static final String COMMAND_IN_SESSION_PARAMETER = "command-in-session";
060:
061: private static final String TRUE = Boolean.TRUE.toString();
062:
063: /**
064: * Create a new AbstractCommandController.
065: */
066: public AbstractCommandController() {
067: }
068:
069: /**
070: * Create a new AbstractCommandController.
071: * @param commandClass class of the command bean
072: */
073: public AbstractCommandController(Class commandClass) {
074: setCommandClass(commandClass);
075: }
076:
077: /**
078: * Create a new AbstractCommandController.
079: * @param commandClass class of the command bean
080: * @param commandName name of the command bean
081: */
082: public AbstractCommandController(Class commandClass,
083: String commandName) {
084: setCommandClass(commandClass);
085: setCommandName(commandName);
086: }
087:
088: protected final void handleActionRequestInternal(
089: ActionRequest request, ActionResponse response)
090: throws Exception {
091:
092: // Create the command object.
093: Object command = getCommand(request);
094:
095: // Compute the errors object.
096: PortletRequestDataBinder binder = bindAndValidate(request,
097: command);
098: BindException errors = new BindException(binder
099: .getBindingResult());
100:
101: // Actually handle the action.
102: handleAction(request, response, command, errors);
103:
104: // Pass the command and errors forward to the render phase.
105: setRenderCommandAndErrors(request, command, errors);
106: setCommandInSession(response);
107: }
108:
109: protected final ModelAndView handleRenderRequestInternal(
110: RenderRequest request, RenderResponse response)
111: throws Exception {
112:
113: Object command = null;
114: BindException errors = null;
115:
116: // get the command and errors objects from the session, if they exist
117: if (isCommandInSession(request)) {
118: logger
119: .debug("Render phase obtaining command and errors objects from session");
120: command = getRenderCommand(request);
121: errors = getRenderErrors(request);
122: } else {
123: logger
124: .debug("Render phase creating new command and errors objects");
125: }
126:
127: // If no command object was in the session, create a new one.
128: if (command == null) {
129: command = getCommand(request);
130: }
131:
132: // If no errors object was in the session, compute a new one.
133: if (errors == null) {
134: PortletRequestDataBinder binder = bindAndValidate(request,
135: command);
136: errors = new BindException(binder.getBindingResult());
137: }
138:
139: return handleRender(request, response, command, errors);
140: }
141:
142: /**
143: * Template method for request handling, providing a populated and validated instance
144: * of the command class, and an Errors object containing binding and validation errors.
145: * <p>Call <code>errors.getModel()</code> to populate the ModelAndView model
146: * with the command and the Errors instance, under the specified command name,
147: * as expected by the "spring:bind" tag.
148: * @param request current action request
149: * @param response current action response
150: * @param command the populated command object
151: * @param errors validation errors holder
152: * @see org.springframework.validation.Errors
153: * @see org.springframework.validation.BindException#getModel
154: */
155: protected abstract void handleAction(ActionRequest request,
156: ActionResponse response, Object command,
157: BindException errors) throws Exception;
158:
159: /**
160: * Template method for render request handling, providing a populated and validated instance
161: * of the command class, and an Errors object containing binding and validation errors.
162: * <p>Call <code>errors.getModel()</code> to populate the ModelAndView model
163: * with the command and the Errors instance, under the specified command name,
164: * as expected by the "spring:bind" tag.
165: * @param request current render request
166: * @param response current render response
167: * @param command the populated command object
168: * @param errors validation errors holder
169: * @return a ModelAndView to render, or null if handled directly
170: * @see org.springframework.validation.Errors
171: * @see org.springframework.validation.BindException#getModel
172: */
173: protected abstract ModelAndView handleRender(RenderRequest request,
174: RenderResponse response, Object command,
175: BindException errors) throws Exception;
176:
177: /**
178: * Return the name of the render parameter that indicates there
179: * is a valid command (and errors) object in the session.
180: * @return the name of the render parameter
181: * @see javax.portlet.RenderRequest#getParameter
182: */
183: protected String getCommandInSessionParameterName() {
184: return COMMAND_IN_SESSION_PARAMETER;
185: }
186:
187: /**
188: * Set the action response parameter that indicates there is a
189: * command (and errors) object in the session for the render phase.
190: * @param response the current action response
191: * @see #getCommandInSessionParameterName
192: * @see #isCommandInSession
193: */
194: protected final void setCommandInSession(ActionResponse response) {
195: if (logger.isDebugEnabled()) {
196: logger
197: .debug("Setting render parameter ["
198: + getCommandInSessionParameterName()
199: + "] to indicate a valid command (and errors) object are in the session");
200: }
201: try {
202: response.setRenderParameter(
203: getCommandInSessionParameterName(), TRUE);
204: } catch (IllegalStateException ex) {
205: // Ignore in case sendRedirect was already set.
206: }
207: }
208:
209: /**
210: * Determine if there is a valid command (and errors) object in the
211: * session for this render request.
212: * @param request current render request
213: * @return if there is a valid command object in the session
214: * @see #getCommandInSessionParameterName
215: * @see #setCommandInSession
216: */
217: protected final boolean isCommandInSession(RenderRequest request) {
218: return TRUE.equals(request
219: .getParameter(getCommandInSessionParameterName()));
220: }
221:
222: }
|