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

org.wicketstuff.webflow.controller.SpringWebFlowFacade Maven / Gradle / Ivy

There is a newer version: 1.4.21
Show newest version
/**
 * 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.
 *
 * Contributed by United Services Automotive Association (USAA)
 */
/* ***************************************************************************
 * File: SpringWebFlowFacade
 *****************************************************************************/
package org.wicketstuff.webflow.controller;

import org.apache.wicket.Component;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.protocol.http.WebRequest;
import org.apache.wicket.protocol.http.WebResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.webflow.context.ExternalContextHolder;
import org.springframework.webflow.core.FlowException;
import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.engine.NoMatchingTransitionException;
import org.springframework.webflow.engine.ViewState;
import org.springframework.webflow.execution.FlowExecution;
import org.springframework.webflow.execution.FlowExecutionKey;
import org.springframework.webflow.execution.repository.FlowExecutionLock;
import org.springframework.webflow.execution.repository.FlowExecutionRepository;
import org.springframework.webflow.execution.repository.FlowExecutionRestorationFailureException;
import org.springframework.webflow.executor.FlowExecutionResult;
import org.springframework.webflow.executor.FlowExecutor;
import org.springframework.webflow.executor.FlowExecutorImpl;
import org.wicketstuff.webflow.IPageFlowContainer;
import org.wicketstuff.webflow.PageFlowConstants;
import org.wicketstuff.webflow.WicketSpringWebFlowException;
import org.wicketstuff.webflow.context.PageFlowExternalContext;
import org.wicketstuff.webflow.session.PageFlowSession;
import org.wicketstuff.webflow.view.WicketView;


/**
 * Facade class that fronts all calls from Wicket Infrastructure to Spring Web Flow.
 *
 * This facade provides methods for the following:
 * 		To launch a new application flow.
 * 		To resume an existing application flow.
 * 		To validate whether a flow execution key is valid.
 * 		To retrieve the view state class corresponding to a flow execution key.
 * 		To retrieve the flow instance corresponding to a flow execution key.
 *
 * @author Clint Checketts, Florian Braun, Doug Hall, Subramanian Murali
 * @version $Id: $
 */
public class SpringWebFlowFacade 
{
	private static final Logger LOG = LoggerFactory.getLogger(SpringWebFlowFacade.class); 
	
	//Flow Executor Instance
	FlowExecutor flowExecutor;
	
	//Wicket External Context instance
	PageFlowExternalContext context;
	
	/**
	 * Constructor that accepts the flow executor and page flow external context as arguments.
	 *
	 * @param flowExecutor - FlowExecutor instance to be used by this facade to communicate with Spring Web Flow.
	 * @param context - Page Flow External Context to be used by this facade to communicate with Spring Web Flow.
	 */
	public SpringWebFlowFacade(FlowExecutor flowExecutor, PageFlowExternalContext context)
	{
		this.flowExecutor = flowExecutor;
		this.context = context;
	}
	
	/**
	 * Constructor that retrieves and initializes the flow executor and page flow external context  by itself.
	 */
	public SpringWebFlowFacade()
	{
		WebApplication application = WebApplication.get();

		//Retrieve the Page Flow App Session instance
		PageFlowSession pageFlowSession = PageFlowSession.get();
		
		if(application instanceof IPageFlowContainer)
		{
			//Retrieve the flow executor instance
			this.flowExecutor = ((IPageFlowContainer) application).getFlowExecutor();
			
			//Construct a new page flow external context
			this.context = new PageFlowExternalContext(application.getServletContext(),
				((WebRequest)((RequestCycle)RequestCycle.get()).getRequest()).getHttpServletRequest(), 
				((WebResponse)((RequestCycle)RequestCycle.get()).getResponse()).getHttpServletResponse(), 
				pageFlowSession);			
		}
		else
		{
			throw new WicketRuntimeException("Application must implement the interface "+IPageFlowContainer.class.getName());
		}
	}	
	
	
	
	/**
	 * Method that launches a new web flow execution for the input flow id and returns the launched
	 * view state.
	 *
	 * @param flowId - Flow Id for which the web flow execution needs to be launched.
	 * @return String - Launched view state.
	 */
	public String launchWebFlowExecution(String flowId)
	{
		//Variable that stores the launched view state
		String launchedViewState = null;
		
		if(flowId != null)
		{
			try
			{
				//Launch the Web Flow Execution
				FlowExecutionResult result = flowExecutor.launchExecution(flowId, null, context);

				//Retrieve the launched view state
				launchedViewState = result.getPausedKey();
			}
						catch(FlowException flowException)
			{
				throw new WicketSpringWebFlowException("Unable to start flow",flowException);
			}
		}
		
		return launchedViewState;
	}
	
	/**
	 * Method that resumes an existing flow execution for the input view state and returns the transitioned
	 * view state.
	 *
	 * @param viewState - View state from which the application flow needs to be resumed..
	 * @return String - Transitioned view state.
	 */
	public String resumeWebFlowExecution(String viewState)
	{
		//Variable that stores the transitioned view state
		String transitionedViewState = null;
		
		if(viewState != null)
		{
			try
			{
				//Resume the execution in Spring Web Flow
				FlowExecutionResult result = flowExecutor.resumeExecution(viewState, context);
				
				if(result.isEnded())
				{
					transitionedViewState = PageFlowConstants.PAGE_FLOW_FINAL_STATE_DONE;
				}
				else
				{
					transitionedViewState = result.getPausedKey();		
				}	
			}
			catch(FlowExecutionRestorationFailureException flowException)
			{
				LOG.error("A Flow Exception occured in Spring Web Flow while resuming the application flow from the input view state" +
					viewState, flowException);
			}
			catch(NoMatchingTransitionException transitionEx){
				throw new WicketSpringWebFlowException("Invalid view transition",transitionEx);
			}
			catch(FlowException flowException)
			{
				if(viewState.equals(PageFlowConstants.PAGE_FLOW_FINAL_STATE_DONE)){
					throw new WicketSpringWebFlowException("Flow completed. Unable to return to flow.",flowException);
				} else {
					throw new WicketSpringWebFlowException("Invalid view transition",flowException);
				}
			}
		}
		
		return transitionedViewState;
	}	
	
	/**
	 * Method that checks if the input flow execution key is valid.
	 *
	 * @param inputKey - Input Flow Execution Key that needs to be checked if it is valid.
	 * @return boolean - boolean that represents whether the input flow execution key is valid.
	 */
	public boolean isFlowExecutionKeyValid(String inputKey)
	{
		//boolean that indicates if the input flow execution key is valid
		boolean isValid = false;
		
		//Set the ExternalContext
		ExternalContextHolder.setExternalContext(context);

		//Retrieve the Flow Execution Repository
		FlowExecutionRepository repository = ((FlowExecutorImpl)flowExecutor).getExecutionRepository();
		
		try 
		{
			//Parse the Flow Execution Key
			FlowExecutionKey flowExecutionKey = repository.parseFlowExecutionKey(inputKey);

			//Retrieve the Flow Execution Lock
			FlowExecutionLock lock = repository.getLock(flowExecutionKey);
			//Set the isValid to true as we are successfully able to retrieve a lock for the input flow execution key
			if(lock != null)
			{
				isValid = true;
			}
		}
		catch(Exception exception)
		{
			LOG.debug("A Flow Exception occured in Spring Web Flow while determining whether the input flow execution key is valid: " +
					inputKey, exception);
		}
		finally
		{
			//Reset the external context
			ExternalContextHolder.setExternalContext(null);
		}
		
		return isValid;
	}
	
	/**
	 * Method that returns the view state class corresponding to the input flow execution key from Spring Web Flow.
	 *
	 * @param inputFlowExecutionKey - Flow execution key for which the view state class name needs to be determined
	 * 					              from Spring Web Flow.
	 * @return Class - View state class for the input flow execution key.
	 */
	public Class getViewStateClass(String inputFlowExecutionKey)
	{
		//Variable that holds the view state class
		Class viewStateClass = null;
		
		//Set the ExternalContext
		ExternalContextHolder.setExternalContext(context);

		//Retrieve the Flow Execution Repository
		FlowExecutionRepository repository = ((FlowExecutorImpl)flowExecutor).getExecutionRepository();
		
		//Parse the Flow Execution Key
		FlowExecutionKey flowExecutionKey = repository.parseFlowExecutionKey(inputFlowExecutionKey);
		
		try 
		{
			//Retrieve the Flow Execution instance corresponding to the flow execution key
			FlowExecution flowExecution = repository.getFlowExecution(flowExecutionKey);
			
			//Retrieve the view state from the retrieved flow execution instance
			ViewState viewState = (ViewState) flowExecution.getActiveSession().getState();

			//Retrieve the view state class name
			viewStateClass= ((WicketView) viewState.getViewFactory().getView(null)).getViewId();
			

		}
		catch (FlowExecutionRestorationFailureException flowRestorationException) 
		{
			//TODO throw our own runtime exception here that pushes the right message up the feedback panel
			LOG.error("A problem occurred restoring the flow execution with key '" + viewStateClass+"'",
				flowRestorationException);
		}
		
		catch(Exception exception)
		{
			LOG.error("An exception occurred while trying to retrieve the view state " +
					"class for the input flow execution key from Spring Web Flow: " + flowExecutionKey,
				exception);
		}
		finally
		{
			//Reset the external context
			ExternalContextHolder.setExternalContext(null);
		}
		
		return viewStateClass;
	}
	
	/**
	 * Method that returns the flow instance corresponding to the input flow execution key from Spring Web Flow.
	 *
	 * @param inputFlowExecutionKey - Flow execution key for which the view state class name needs to be determined
	 * 					              from Spring Web Flow.
	 * @return Flow - Flow instance for the input flow execution key.
	 */
	public Flow getFlow(String inputFlowExecutionKey)
	{
		//Set the ExternalContext
		ExternalContextHolder.setExternalContext(context);

		//Retrieve the Flow Execution Repository
		FlowExecutionRepository repository = ((FlowExecutorImpl)flowExecutor).getExecutionRepository();
		//Flow instance that needs to be returned
		Flow flow = null;
		
		try 
		{
			//Parse the Flow Execution Key
			FlowExecutionKey flowExecutionKey = repository.parseFlowExecutionKey(inputFlowExecutionKey);
			
			//Retrieve the Flow Execution instance corresponding to the flow execution key
			FlowExecution flowExecution = repository.getFlowExecution(flowExecutionKey);
			
			//Retrieve the view state from the retrieved flow execution instance
			ViewState viewState = (ViewState) flowExecution.getActiveSession().getState();
			
			//Retrieve the flow instance corresponding to the flow execution key
			flow = viewState.getFlow();
		}
		catch(Exception exception)
		{
			LOG.error("An exception occurred while trying to retrieve the view state class for the input flow execution key " +
				"from Spring Web Flow " + inputFlowExecutionKey,
				exception);
		}
		finally
		{
			//Reset the external context
			ExternalContextHolder.setExternalContext(null);
		}
		
		return flow;
	}	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy