Code:
/*
* MPSC-Spring - A library of common code to use with the Spring framework
*
* Copyright 2005 Matt Parker
*
* 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 uk.co.mpcontracting.modules.spring.controller;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.propertyeditors.CustomBooleanEditor;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import org.springframework.web.servlet.view.RedirectView;
import uk.co.mpcontracting.modules.spring.model.AbstractControlModel;
import uk.co.mpcontracting.modules.spring.model.ControlModel;
public abstract class AbstractFormController extends SimpleFormController
{
private static Log log = LogFactory.getLog(AbstractFormController.class);
private static final String DEFAULT_MESSAGE = "error.standard.defaultMessage";
protected abstract ControlModel process(HttpServletRequest request, HttpServletResponse response, Object command,
Errors errors) throws Exception;
private static ThreadLocal formBackingObjectStore = new ThreadLocal();
private String failureView;
public final void setFailureView(String failureView)
{
this.failureView = failureView;
}
protected final String getFailureView()
{
return (failureView);
}
protected final int getMaxIndex(HttpServletRequest request, String property)
{
int maxIndex = -1;
for (Enumeration parameters = request.getParameterNames(); parameters.hasMoreElements();)
{
String parameterName = (String)parameters.nextElement();
if (parameterName.startsWith(property))
{
int startIndex = parameterName.indexOf("[");
int endIndex = parameterName.indexOf("]");
if ((startIndex == -1) || (endIndex == -1))
{
log.error("Non-indexed property - " + property);
return (-1);
}
int index = Integer.parseInt(parameterName.substring((startIndex + 1), endIndex));
if (index > maxIndex)
{
maxIndex = index;
}
}
}
return (maxIndex);
}
protected final Object getFormBackingObject(HttpServletRequest request) throws Exception
{
Object formBackingObject = request.getSession().getAttribute(getFormSessionAttributeName(request));
if (formBackingObject == null)
{
formBackingObject = formBackingObjectStore.get();
}
if (formBackingObject == null)
{
throw new ServletException("Unable to find form backing object either in session or local store");
}
return (formBackingObject);
}
protected ModelAndView processFormSubmission(HttpServletRequest request, HttpServletResponse response,
Object command, BindException errors) throws Exception
{
if (errors.hasErrors() || isFormChangeRequest(request))
{
if (log.isDebugEnabled())
{
log.debug("Data binding errors - " + errors.getErrorCount());
}
ControlModel controlModel = getControlModel(request);
if (controlModel != null)
{
return (showForm(request, response, errors, controlModel.getControlModelMap()));
}
else
{
return (showForm(request, response, errors, null));
}
}
else
{
if (log.isDebugEnabled())
{
log.debug("No errors - processing submit");
}
return (onSubmit(request, response, command, errors));
}
}
public ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command,
BindException errors) throws Exception
{
ControlModel controlModel = process(request, response, command, errors);
if (errors.hasErrors())
{
if (failureView != null)
{
ModelAndView modelAndView = getModelAndView(failureView, getControlModel(request));
modelAndView.addAllObjects(errors.getModel());
return (modelAndView);
}
else
{
ControlModel storedControlModel = getControlModel(request);
if (storedControlModel != null)
{
return (showForm(request, response, errors, storedControlModel.getControlModelMap()));
}
else
{
return (showForm(request, response, errors, null));
}
}
}
else
{
return (getModelAndView(getSuccessView(), controlModel));
}
}
private ModelAndView getModelAndView(String viewName, ControlModel controlModel) throws Exception
{
ModelAndView modelAndView;
if (viewName.indexOf('.') > -1)
{
// This is a redirect URL
modelAndView = new ModelAndView(new RedirectView(viewName, true));
}
else
{
// This is a view name
modelAndView = new ModelAndView(viewName);
}
if (controlModel != null)
{
Map internalMap = controlModel.getControlModelMap();
if (internalMap != null)
{
modelAndView.addAllObjects(controlModel.getControlModelMap());
}
}
return (modelAndView);
}
Object createFormBackingObject(HttpServletRequest request) throws Exception
{
if (log.isDebugEnabled())
{
log.debug("Creating form backing object");
}
// Clear out any existing commands that may still exist in the session
request.getSession().removeAttribute(getFormSessionAttributeName(request));
Object formBackingObject = formBackingObject(request);
request.setAttribute(getCommandName(), formBackingObject);
return (formBackingObject);
}
protected final Object formBackingObject(HttpServletRequest request) throws Exception
{
Object formBackingObject = createCommand();
populateFormBackingObject(formBackingObject);
// Store in a thread local for possible later retrieval
formBackingObjectStore.set(formBackingObject);
return (formBackingObject);
}
protected void populateFormBackingObject(Object formBackingObject)
{
// Nothing - override in subclass if required
}
protected ControlModel getControlModel(HttpServletRequest request) throws Exception
{
return (AbstractControlModel.retrieveControlModel(request));
}
protected final void initBinder(HttpServletRequest request, ServletRequestDataBinder binder)
throws Exception
{
binder.registerCustomEditor(Boolean.class, new CustomBooleanEditor(true));
binder.registerCustomEditor(Double.class, new CustomNumberEditor(Double.class, true));
binder.registerCustomEditor(Integer.class, new CustomNumberEditor(Integer.class, true));
initCustomBinder(request, binder);
}
protected void initCustomBinder(HttpServletRequest request, ServletRequestDataBinder binder)
throws Exception
{
// Nothing - override in subclass if required
}
}
There are references to other classes that I've written, but hopefully it gives you some ideas on how to extend the standard classes. I've had to remove my JavaDoc comments and some methods to get it inside the 10000 character posting limit.