All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.webflow.executor.struts.FlowAction Maven / Gradle / Ivy

There is a newer version: 1.0.6
Show newest version
/*
 * Copyright 2002-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.springframework.webflow.executor.struts;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.springframework.validation.Errors;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.struts.ActionSupport;
import org.springframework.web.struts.DelegatingActionProxy;
import org.springframework.web.struts.SpringBindingActionForm;
import org.springframework.web.util.WebUtils;
import org.springframework.webflow.action.FormObjectAccessor;
import org.springframework.webflow.context.ExternalContext;
import org.springframework.webflow.execution.support.ApplicationView;
import org.springframework.webflow.execution.support.ExternalRedirect;
import org.springframework.webflow.execution.support.FlowDefinitionRedirect;
import org.springframework.webflow.executor.FlowExecutor;
import org.springframework.webflow.executor.ResponseInstruction;
import org.springframework.webflow.executor.support.FlowExecutorArgumentHandler;
import org.springframework.webflow.executor.support.FlowRequestHandler;
import org.springframework.webflow.executor.support.RequestParameterFlowExecutorArgumentHandler;

/**
 * Point of integration between Struts and Spring Web Flow: a Struts Action that
 * acts a front controller entry point into the web flow system. A single
 * FlowAction may launch any new FlowExecution. In addition, a single Flow
 * Action may signal events in any existing/restored FlowExecutions.
 * 

* Requests are managed by and delegated to a {@link FlowExecutor}, which this * class delegates to using a {@link FlowRequestHandler} (allowing reuse of * common front flow controller logic in other environments). Consult the * JavaDoc of those classes for more information on how requests are processed. *

*

  • By default, to have this controller launch a new flow execution * (conversation), have the client send a * {@link FlowExecutorArgumentHandler#getFlowIdArgumentName()} request * parameter indicating the flow definition to launch. *
  • To have this controller participate in an existing flow execution * (conversation), have the client send a * {@link FlowExecutorArgumentHandler#getFlowExecutionKeyArgumentName()} * request parameter identifying the conversation to participate in. *

    * On each request received by this action, a {@link StrutsExternalContext} * object is created as input to the web flow system. This external source event * provides access to the action form, action mapping, and other Struts-specific * constructs. *

    * This class also is aware of the {@link SpringBindingActionForm} adapter, * which adapts Spring's data binding infrastructure (based on POJO binding, a * standard Errors interface, and property editor type conversion) to the Struts * action form model. This option gives backend web-tier developers full support * for POJO-based binding with minimal hassel, while still providing consistency * to view developers who already have a lot of experience with Struts for * markup and request dispatching. *

    * Below is an example struts-config.xml configuration for a * FlowAction: * *

     *     <action path="/userRegistration"
     *         type="org.springframework.webflow.executor.struts.FlowAction"
     *         name="springBindingActionForm" scope="request">
     *     </action>
     * 
    * * This example maps the logical request URL /userRegistration.do * as a Flow controller (FlowAction). It is expected that flows * to launch be provided in a dynamic fashion by the views (allowing this single * FlowAction to manage any number of flow executions). A Spring * binding action form instance is set in request scope, acting as an adapter * enabling POJO-based binding and validation with Spring. *

    * Other notes regarding Struts/Spring Web Flow integration: *

      *
    • Logical view names returned when ViewStates and * EndStates are entered are mapped to physical view templates * using standard Struts action forwards (typically global forwards).
    • *
    • Use of the SpringBindingActionForm requires no special * setup in struts-config.xml: simply declare a form bean in * request scope of the class * org.springframework.web.struts.SpringBindingActionForm and use * it with your FlowAction.
    • *
    • This class depends on a {@link FlowExecutor} instance to be configured. * If relying on Spring's {@link DelegatingActionProxy} (which is recommended), * a FlowExecutor reference can simply be injected using standard Spring * dependency injection techniques. If you are not using the proxy-based * approach, this class will attempt a root context lookup on initialization, * first querying for a bean of instance {@link FlowExecutor} named * {@link #FLOW_EXECUTOR_BEAN_NAME}.
    • *
    • The * {@link org.springframework.webflow.executor.support.FlowExecutorArgumentHandler} * used by the FlowAction can be configured in the root context using a bean of * name {@link #FLOW_EXECUTOR_ARGUMENT_HANDLER_BEAN_NAME}. If not explicitly * specified it will default to a normal * {@link org.springframework.webflow.executor.support.RequestParameterFlowExecutorArgumentHandler} * with standard configuration.
    • *
    *

    * The benefits here are considerable: developers now have a powerful web flow * capability integrated with Struts, with a consistent-approach to POJO-based * binding and validation that addresses the proliferation of * ActionForm classes found in traditional Struts-based apps. * * @see org.springframework.webflow.executor.FlowExecutor * @see org.springframework.webflow.executor.support.FlowRequestHandler * @see org.springframework.web.struts.SpringBindingActionForm * @see org.springframework.web.struts.DelegatingActionProxy * * @author Keith Donald * @author Erwin Vervaet */ public class FlowAction extends ActionSupport { /** * The flow executor will be retreived from the application context using * this bean name if no executor is explicitly set. ("flowExecutor") */ protected static final String FLOW_EXECUTOR_BEAN_NAME = "flowExecutor"; /** * The flow executor argument handler will be retreived from the * application context using this bean name if no argument handler is * explicitly set. ("argumentHandler") */ protected static final String FLOW_EXECUTOR_ARGUMENT_HANDLER_BEAN_NAME = "argumentHandler"; /** * The service responsible for launching and signaling Struts-originating * events in flow executions. */ private FlowExecutor flowExecutor; /** * Delegate to handle flow executor arguments. */ private FlowExecutorArgumentHandler argumentHandler; /** * Returns the flow executor used by this controller. * @return the flow executor */ public FlowExecutor getFlowExecutor() { return flowExecutor; } /** * Configures the flow executor implementation to use. Required. * @param flowExecutor the fully configured flow executor */ public void setFlowExecutor(FlowExecutor flowExecutor) { this.flowExecutor = flowExecutor; } /** * Returns the flow executor argument handler used by this controller. * @return the argument handler */ public FlowExecutorArgumentHandler getArgumentHandler() { return argumentHandler; } /** * Sets the flow executor argument handler to use. * @param argumentHandler the fully configured argument handler */ public void setArgumentHandler(FlowExecutorArgumentHandler argumentHandler) { this.argumentHandler = argumentHandler; } protected void onInit() { WebApplicationContext context = getWebApplicationContext(); if (getFlowExecutor() == null) { if (context.containsBean(FLOW_EXECUTOR_BEAN_NAME)) { setFlowExecutor((FlowExecutor)context.getBean(FLOW_EXECUTOR_BEAN_NAME, FlowExecutor.class)); } else { throw new IllegalStateException("No '" + FLOW_EXECUTOR_BEAN_NAME + "' bean definition could be found; to use Spring Web Flow with Struts you must " + "configure this FlowAction with a FlowExecutor"); } } if (getArgumentHandler() == null) { if (context.containsBean(FLOW_EXECUTOR_ARGUMENT_HANDLER_BEAN_NAME)) { setArgumentHandler((FlowExecutorArgumentHandler)context.getBean( FLOW_EXECUTOR_ARGUMENT_HANDLER_BEAN_NAME, FlowExecutorArgumentHandler.class)); } else { // default argumentHandler = new RequestParameterFlowExecutorArgumentHandler(); } } } public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ExternalContext context = new StrutsExternalContext(mapping, form, getServletContext(), request, response); ResponseInstruction responseInstruction = createRequestHandler().handleFlowRequest(context); return toActionForward(responseInstruction, mapping, form, request, response, context); } /** * Factory method that creates a new helper for processing a request into * this flow controller. * @return the controller helper */ protected FlowRequestHandler createRequestHandler() { return new FlowRequestHandler(getFlowExecutor(), getArgumentHandler()); } /** * Return a Struts ActionForward given a ResponseInstruction. Adds all * attributes from the ResponseInstruction as request attributes. */ protected ActionForward toActionForward(ResponseInstruction response, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse httpResponse, ExternalContext context) throws Exception { if (response.isApplicationView()) { // forward to a view as part of an active conversation ApplicationView forward = (ApplicationView)response.getViewSelection(); Map model = new HashMap(forward.getModel()); argumentHandler.exposeFlowExecutionContext( response.getFlowExecutionKey(), response.getFlowExecutionContext(), model); WebUtils.exposeRequestAttributes(request, model); if (form instanceof SpringBindingActionForm) { SpringBindingActionForm bindingForm = (SpringBindingActionForm)form; // expose the form object and associated errors as the // "current form object" in the request Errors currentErrors = (Errors)model.get(FormObjectAccessor.getCurrentFormErrorsName()); bindingForm.expose(currentErrors, request); } return findForward(forward, mapping); } else if (response.isFlowExecutionRedirect()) { // redirect to active flow execution URL String flowExecutionUrl = argumentHandler.createFlowExecutionUrl( response.getFlowExecutionKey(), response.getFlowExecutionContext(), context); return createRedirectForward(flowExecutionUrl, httpResponse); } else if (response.isFlowDefinitionRedirect()) { // restart the flow by redirecting to flow launch URL String flowUrl = argumentHandler.createFlowDefinitionUrl((FlowDefinitionRedirect)response.getViewSelection(), context); return createRedirectForward(flowUrl, httpResponse); } else if (response.isExternalRedirect()) { // redirect to external URL String externalUrl = argumentHandler.createExternalUrl((ExternalRedirect)response.getViewSelection(), response.getFlowExecutionKey(), context); return createRedirectForward(externalUrl, httpResponse); } else if (response.isNull()) { // no response to issue return null; } else { throw new IllegalArgumentException("Don't know how to handle response instruction " + response); } } /** * Handles a redirect. This implementation simply calls sendRedirect on the * response object. * @param url the url to redirect to * @param response the http response * @return the redirect forward, this implementation returns null * @throws Exception an excpetion occured processing the redirect * @see HttpServletResponse#sendRedirect(java.lang.String) */ protected ActionForward createRedirectForward(String url, HttpServletResponse response) throws Exception { response.sendRedirect(url); return null; } /** * Find an action forward for given application view. If no suitable forward * is found in the action mapping using the view name as a key, this method * will create a new action forward using the view name. * @param forward the application view to find a forward for * @param mapping the action mapping to use * @return the action forward, never null */ protected ActionForward findForward(ApplicationView forward, ActionMapping mapping) { // note that this method is always creating a new ActionForward to make // sure that the redirect flag is false -- redirect is controlled by SWF // itself, not Struts ActionForward actionForward = mapping.findForward(forward.getViewName()); if (actionForward != null) { // the 1.2.1 copy constructor would ideally be better to // use, but it is not Struts 1.1 compatible actionForward = new ActionForward(actionForward.getName(), actionForward.getPath(), false); } else { actionForward = new ActionForward(forward.getViewName(), false); } return actionForward; } }





  • © 2015 - 2024 Weber Informatics LLC | Privacy Policy