/*
* Copyright 2005-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.strecks.controller;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.Globals;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.config.ModuleConfig;
import org.strecks.builder.Bootstrapper;
import org.strecks.builder.Builder;
import org.strecks.context.ActionContext;
import org.strecks.context.ActionContextFactory;
import org.strecks.form.controller.BindingForm;
import org.strecks.form.controller.ValidForm;
import org.strecks.form.handler.FormWrapper;
import org.strecks.form.handler.FormPopulateSource;
import org.strecks.form.handler.FormValidationHandler;
import org.strecks.preprocess.RequestPreprocessor;
/**
* Implementation of <code>RequestProcessor</code> subclass for adding extension specific
* functionality using hooks provided by <code>BaseRequestProcessor</code>
* @author Phil Zoio
*
*/
public class ControllerRequestProcessor extends BaseRequestProcessor
{
private ServletContext servletContext;
private ControllerProcessorDelegate delegate;
private FormWrapper formHandler;
private ActionCreator actionCreator;
private ActionContextFactory actionContextFactory;
private FormValidationHandler formValidationHandler;
private FormPopulateSource formPopulateSource;
private RequestPreprocessor requestPreprocessor;
/**
* Performs extension-specific configuration tasks
*/
@Override
protected void postInit(ActionServlet servlet, ModuleConfig config)
{
setServletContext(servlet.getServletContext());
Bootstrapper bootstrapper = new Bootstrapper();
bootstrapper.bootStrap();
Builder builder = bootstrapper.getBuilder();
builder.build(config.getPrefix());
setDelegate(builder.getControllerDelegate());
setFormHandler(builder.getFormHandler());
setActionCreator(builder.getActionCreator());
setActionContextFactory(builder.getActionContextFactory());
setFormValidationHandler(builder.getFormValidationHandler());
setFormPopulationSource(builder.getFormPopulateSource());
setRequestPreprocessor(builder.getRequestPreprocessor());
}
/**
* Removes <code>Globals.ERROR_KEY</code> from session and adds as a request attribute. This
* allows errors to support redirect after post. The errors are added to the session
*/
@Override
protected void preProcessCachedMessages(HttpServletRequest request)
{
requestPreprocessor.preprocessRequest(request);
}
/**
* Provides overriding behaviour of <code>ControllerRequestProcessor</code> for
* <code>processActionForm()</code>
* @return
*/
@Override
protected ActionForm postProcessActionForm(HttpServletRequest request, HttpServletResponse response, ActionForm form)
{
if (form != null)
{
form = formHandler.wrapForm(form, request);
}
if (form instanceof BindingForm)
{
formHandler.handleBindingForm((BindingForm) form, request);
if (form instanceof ValidForm)
{
formHandler.handleValidForm((ValidForm) form, request);
}
}
return form;
}
@Override
protected ActionForm prePopulate(ActionForm form, HttpServletRequest request)
{
return formPopulateSource.prePopulate(form, request);
}
@Override
protected void postValidate(HttpServletRequest request, ActionMapping mapping, boolean validate)
{
formValidationHandler.postValidate(request, mapping, validate);
}
@Override
protected ActionForm preValidate(ActionForm form, HttpServletRequest request)
{
return formValidationHandler.preValidate(request, form);
}
@SuppressWarnings("unchecked")
@Override
protected Action extendedProcessActionCreate(HttpServletRequest request, HttpServletResponse response,
ActionMapping actionMapping) throws IOException
{
String className = actionMapping.getType();
Action action = null;
boolean isNew = false;
synchronized (actions)
{
action = (Action) actions.get(className);
if (action == null)
{
try
{
// load the action class
Class clazz = Class.forName(className);
// delegate action creation to ActionCreator
action = actionCreator.createAction(clazz);
action.setServlet(this.servlet);
isNew = true;
}
catch (Exception e)
{
log.error(getInternal().getMessage("actionCreate", actionMapping.getPath()), e);
// this is not ideal but is just a copy from the Struts superclass method
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, getInternal().getMessage(
"actionCreate", actionMapping.getPath()));
return null;
}
}
if (isNew)
{
actions.put(className, action);
}
}
return action;
}
/**
* Handles request processing. If <code>Action</code> is instance of
* <code>ControllerAction</code> then control is passed on to the delegate. Otherwise,
* standard Struts action processing is carried out.<br>
* <br>
* Before execution, any configured <code>BeforeInterceptor</code>s are executed. Any
* exception thrown by these are handled by the Struts-configured exception handler. For
* example, if the second of three <code>BeforeInterceptor</code>s throws an exception, then
* the third will not be executed, and neither will the action's execute method or any
* <code>AfterInterceptors</code><br>
* <br>
* <code>AfterInterceptors</code>, by contrast will either all be executed or none executed.
* If an exception is thrown by any <code>AfterInterceptor</code>, it will be logged and
* ignored afterwards.
*/
@Override
protected ActionForward extendedProcessActionPerform(HttpServletRequest request, HttpServletResponse response,
Action action, ActionForm form, ActionMapping mapping) throws IOException, ServletException
{
ActionContext actionContext = actionContextFactory.createActionContext(request, response, servletContext, form,
mapping);
ActionForward forward = null;
try
{
if (action instanceof ControllerAction)
{
// execute strecks specific processActionPerform
forward = delegate.handleActionPerform((ControllerAction) action, actionContext);
}
else
{
// execute regular Struts actions
forward = action.execute(mapping, form, request, response);
}
}
catch (Exception e)
{
request.setAttribute(Globals.EXCEPTION_KEY, e);
return (processException(request, response, e, form, mapping));
}
return forward;
}
/*
* ********************************************* package level setters and getters
* *************************************
*/
void setServletContext(ServletContext servletContext)
{
this.servletContext = servletContext;
}
void setActionCreator(ActionCreator actionCreator)
{
this.actionCreator = actionCreator;
}
void setDelegate(ControllerProcessorDelegate delegate)
{
this.delegate = delegate;
}
void setFormHandler(FormWrapper formHandler)
{
this.formHandler = formHandler;
}
void setFormValidationHandler(FormValidationHandler formValidationHandler)
{
this.formValidationHandler = formValidationHandler;
}
void setFormPopulationSource(FormPopulateSource formPopulateSource)
{
this.formPopulateSource = formPopulateSource;
}
void setRequestPreprocessor(RequestPreprocessor requestPreprocessor)
{
this.requestPreprocessor = requestPreprocessor;
}
void setActionContextFactory(ActionContextFactory actionContextFactory)
{
this.actionContextFactory = actionContextFactory;
}
ActionCreator getActionCreator()
{
return actionCreator;
}
ControllerProcessorDelegate getDelegate()
{
return delegate;
}
boolean hasAction(String className)
{
return actions.get(className) != null;
}
}