Split off AutowiringPhaseListener.
This commit is contained in:
@@ -14,7 +14,7 @@ Package org.springframework.webflow.action
|
||||
Package org.springframework.webflow.executor
|
||||
* Statics on FlowFacesUtils are now public: they're supposed to be well known names.
|
||||
* FlowPhaseListener.cleanupResources() is now protected.
|
||||
* Added AutowiringFlowExecutionListener (SWF-746).
|
||||
* Added AutowiringSupport, AutowiringFlowExecutionListener and AutowiringPhaseListener (SWF-746).
|
||||
* In a JSF 1.2 environment, SWF will now correctly maintain the "java.faces.ViewState" parameter accross flow
|
||||
execution redirects (SWF-445).
|
||||
* FlowPhaseListener now maintains FacesMessages accross a flow execution redirect by temporarily storing them in
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.springframework.webflow.executor.jsf;
|
||||
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.event.PhaseEvent;
|
||||
import javax.faces.event.PhaseId;
|
||||
import javax.faces.event.PhaseListener;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.webflow.execution.ScopeType;
|
||||
import org.springframework.webflow.executor.support.AutowiringSupport;
|
||||
|
||||
/**
|
||||
* JSF phase listener that that can be combined with the {@link FlowPhaseListener} to automatically autowire objects in
|
||||
* the flow execution scopes every time a flow execution is restored. In faces-config.xml it should be declared <i>after</i>
|
||||
* the FlowPhaseListener to make sure the FlowPhaseListener first restores the flow execution before this listener tries
|
||||
* to autowire objects inside the flow execution.
|
||||
* <p>
|
||||
* This listener is particularly useful when you are storing stateful objects inside the flow execution that have
|
||||
* dependencies on other objects, typically singleton service objects managed by Spring in an application context. Since
|
||||
* Web Flow serializes the contents of flash and flow scope inbetween requests, those dependencies should be marked as
|
||||
* transient to avoid serializing the referenced objects (services). As a consequence however, those dependencies are
|
||||
* lost when the flow execution is restored. This listener makes it possible to rewire any required depencencies every
|
||||
* time the flow execution is restored.
|
||||
* <p>
|
||||
* By default, the listener will use autowiring by name. This behaviour can be changed by setting the "autowireMode"
|
||||
* property to the appropriate value.
|
||||
* <p>
|
||||
* Dependency checking is turned off by default: if no matching service layer bean can be found, the setter in question
|
||||
* will simply not get invoked. To enforce matching service layer beans, set the "dependencyCheck" property to true.
|
||||
* <p>
|
||||
* Autowiring will be attempted for all objects stored in flash, flow and conversation scope. Override the
|
||||
* {@link #shouldBeAutowired(ScopeType, String, Object)} method if you want to limit autowiring to specific objects.
|
||||
* <p>
|
||||
* Autowiring is done using {@link AutowireCapableBeanFactory#autowireBeanProperties(Object, int, boolean)}. If you
|
||||
* require special autowiring behaviour, consider overriding the {@link #autowire(ScopeType, String, Object)} method.
|
||||
* <p>
|
||||
* This phase listener will use the root web application context as {@link AutowireCapableBeanFactory}.
|
||||
*
|
||||
* @see FlowPhaseListener
|
||||
* @see WebApplicationContextUtils#getWebApplicationContext(ServletContext)
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public class AutowiringPhaseListener extends AutowiringSupport implements PhaseListener {
|
||||
|
||||
protected AutowireCapableBeanFactory getBeanFactory() {
|
||||
return WebApplicationContextUtils.getWebApplicationContext(
|
||||
(ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext())
|
||||
.getAutowireCapableBeanFactory();
|
||||
}
|
||||
|
||||
public PhaseId getPhaseId() {
|
||||
return PhaseId.RESTORE_VIEW;
|
||||
}
|
||||
|
||||
public void beforePhase(PhaseEvent event) {
|
||||
FacesContext context = event.getFacesContext();
|
||||
if (FlowExecutionHolderUtils.isFlowExecutionRestored(context)) {
|
||||
autowire(FlowExecutionHolderUtils.getCurrentFlowExecution(context));
|
||||
}
|
||||
}
|
||||
|
||||
public void afterPhase(PhaseEvent event) {
|
||||
// nothing to do after the phase
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,21 @@
|
||||
package org.springframework.webflow.executor.support;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.webflow.core.collection.AttributeMap;
|
||||
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
import org.springframework.webflow.definition.FlowDefinition;
|
||||
import org.springframework.webflow.definition.StateDefinition;
|
||||
import org.springframework.webflow.execution.EnterStateVetoException;
|
||||
import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.FlowExecutionException;
|
||||
import org.springframework.webflow.execution.FlowExecutionListener;
|
||||
import org.springframework.webflow.execution.FlowExecutionListenerAdapter;
|
||||
import org.springframework.webflow.execution.FlowSession;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.ScopeType;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
|
||||
/**
|
||||
* Flow execution listener that will autowire objects found in the flow execution scopes when a flow execution
|
||||
@@ -25,12 +29,12 @@ import org.springframework.webflow.execution.ScopeType;
|
||||
* time the flow execution resumes.
|
||||
* <p>
|
||||
* By default, the listener will use autowiring by name. This behaviour can be changed by setting the "autowireMode"
|
||||
* property to the approriate value.
|
||||
* property to the appropriate value.
|
||||
* <p>
|
||||
* Dependency checking is turned off by default: If no matching service layer bean can be found, the setter in question
|
||||
* Dependency checking is turned off by default: if no matching service layer bean can be found, the setter in question
|
||||
* will simply not get invoked. To enforce matching service layer beans, set the "dependencyCheck" property to true.
|
||||
* <p>
|
||||
* Autowiring will be attempted for all objects stored in any of the flow execution scopes. Override the
|
||||
* Autowiring will be attempted for all objects stored in flash, flow and conversation scope. Override the
|
||||
* {@link #shouldBeAutowired(ScopeType, String, Object)} method if you want to limit autowiring to specific objects.
|
||||
* <p>
|
||||
* Autowiring is done using {@link AutowireCapableBeanFactory#autowireBeanProperties(Object, int, boolean)}. If you
|
||||
@@ -45,112 +49,61 @@ import org.springframework.webflow.execution.ScopeType;
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public class AutowiringFlowExecutionListener extends FlowExecutionListenerAdapter implements ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* The autowiring mode to use.
|
||||
*/
|
||||
private int autowireMode = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
|
||||
|
||||
/**
|
||||
* The dependency check setting to use.
|
||||
*/
|
||||
private boolean dependencyCheck = false;
|
||||
public class AutowiringFlowExecutionListener extends AutowiringSupport implements ApplicationContextAware,
|
||||
FlowExecutionListener {
|
||||
|
||||
/**
|
||||
* The bean factory we will delegate autowiring to.
|
||||
*/
|
||||
private AutowireCapableBeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* Returns the configured autowiring mode. The default is autowiring by name.
|
||||
*/
|
||||
public int getAutowireMode() {
|
||||
return autowireMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the autowiring mode to use, either by name or by type. Defaults to autowiring by name.
|
||||
* @see AutowireCapableBeanFactory#AUTOWIRE_BY_NAME
|
||||
* @see AutowireCapableBeanFactory#AUTOWIRE_BY_TYPE
|
||||
* @see AutowireCapableBeanFactory#AUTOWIRE_NO
|
||||
*/
|
||||
public void setAutowireMode(int autowireMode) {
|
||||
this.autowireMode = autowireMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured dependency check setting. Defaults to false.
|
||||
*/
|
||||
public boolean getDependencyCheck() {
|
||||
return dependencyCheck;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to perform a dependency check for object references in the instance being autowired. Defaults to
|
||||
* false.
|
||||
* @see AutowireCapableBeanFactory#autowireBeanProperties(Object, int, boolean)
|
||||
*/
|
||||
public void setDependencyCheck(boolean dependencyCheck) {
|
||||
this.dependencyCheck = dependencyCheck;
|
||||
protected AutowireCapableBeanFactory getBeanFactory() {
|
||||
return beanFactory;
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.beanFactory = applicationContext.getAutowireCapableBeanFactory();
|
||||
}
|
||||
|
||||
// implementing FlowExecutionListener
|
||||
|
||||
public void requestSubmitted(RequestContext context) {
|
||||
}
|
||||
|
||||
public void requestProcessed(RequestContext context) {
|
||||
}
|
||||
|
||||
public void sessionStarting(RequestContext context, FlowDefinition definition, MutableAttributeMap input) {
|
||||
}
|
||||
|
||||
public void sessionCreated(RequestContext context, FlowSession session) {
|
||||
}
|
||||
|
||||
public void sessionStarted(RequestContext context, FlowSession session) {
|
||||
}
|
||||
|
||||
public void eventSignaled(RequestContext context, Event event) {
|
||||
}
|
||||
|
||||
public void stateEntering(RequestContext context, StateDefinition state) throws EnterStateVetoException {
|
||||
}
|
||||
|
||||
public void stateEntered(RequestContext context, StateDefinition previousState, StateDefinition newState) {
|
||||
}
|
||||
|
||||
public void resumed(RequestContext context) {
|
||||
// autowire request scope, which is not tied to the flow session
|
||||
autowire(ScopeType.REQUEST, context.getRequestScope());
|
||||
|
||||
// autowire flash and flow scope for all flow sessions in the flow execution
|
||||
FlowSession flowSession = context.getFlowExecutionContext().getActiveSession();
|
||||
while (flowSession != null) {
|
||||
autowire(ScopeType.FLASH, flowSession.getFlashMap());
|
||||
autowire(ScopeType.FLOW, flowSession.getScope());
|
||||
|
||||
flowSession = flowSession.getParent();
|
||||
}
|
||||
|
||||
// autowire conversation scope, which is not tied to the flow session
|
||||
autowire(ScopeType.CONVERSATION, context.getConversationScope());
|
||||
autowire(context.getFlowExecutionContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Autowire all objects in given flow execution scope.
|
||||
*/
|
||||
private void autowire(ScopeType scopeType, MutableAttributeMap scope) {
|
||||
for (Iterator keys = scope.asMap().keySet().iterator(); keys.hasNext();) {
|
||||
String key = (String) keys.next();
|
||||
Object value = scope.get(key);
|
||||
if (shouldBeAutowired(scopeType, key, value)) {
|
||||
autowire(scopeType, key, value);
|
||||
}
|
||||
}
|
||||
public void paused(RequestContext context, ViewSelection selectedView) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether or not given value, indexed using given key in specified flow execution scope, should be
|
||||
* autowired. The default implementation simply returns true, i.e. it tries to autowire all objects found in the
|
||||
* flow execution scopes.
|
||||
* <p>
|
||||
* Subclasses can override this method if they want to limit autowiring to a particular scope or to particular
|
||||
* objects, for instance objects implementing a paritcular marker interface, having a certain marker annotation or
|
||||
* objects whose class name follows some naming convention.
|
||||
*/
|
||||
protected boolean shouldBeAutowired(ScopeType scopeType, String key, Object value) {
|
||||
return true;
|
||||
public void sessionEnding(RequestContext context, FlowSession session, MutableAttributeMap output) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Autowire given value indexed using given key in specified flow execution scope. By default, this method will
|
||||
* simply call {@link AutowireCapableBeanFactory#autowireBeanProperties(Object, int, boolean)} using the configured
|
||||
* {@link #setAutowireMode(int) autowiring mode} and {@link #setDependencyCheck(boolean) dependency check} settings.
|
||||
* <p>
|
||||
* Subclasses can override this method when special autowiring is required, for instance using any of the other
|
||||
* method offered by {@link AutowireCapableBeanFactory}.
|
||||
*/
|
||||
protected void autowire(ScopeType scopeType, String key, Object value) {
|
||||
beanFactory.autowireBeanProperties(value, autowireMode, dependencyCheck);
|
||||
public void sessionEnded(RequestContext context, FlowSession session, AttributeMap output) {
|
||||
}
|
||||
|
||||
public void exceptionThrown(RequestContext context, FlowExecutionException exception) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package org.springframework.webflow.executor.support;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
import org.springframework.webflow.execution.FlowExecutionContext;
|
||||
import org.springframework.webflow.execution.FlowSession;
|
||||
import org.springframework.webflow.execution.ScopeType;
|
||||
|
||||
/**
|
||||
* Abstract support class for classes that can autowire objects found in one of flow execution scopes.
|
||||
* <p>
|
||||
* Subclasses are required to implement the {@link #getBeanFactory()} hook method, returning the
|
||||
* {@link AutowireCapableBeanFactory} to use for autowiring.
|
||||
*
|
||||
* @see AutowireCapableBeanFactory
|
||||
*
|
||||
* @since 1.0.6
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public abstract class AutowiringSupport {
|
||||
|
||||
/**
|
||||
* The autowiring mode to use.
|
||||
*/
|
||||
private int autowireMode = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
|
||||
|
||||
/**
|
||||
* The dependency check setting to use.
|
||||
*/
|
||||
private boolean dependencyCheck = false;
|
||||
|
||||
/**
|
||||
* Returns the configured autowiring mode. The default is autowiring by name.
|
||||
*/
|
||||
public int getAutowireMode() {
|
||||
return autowireMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the autowiring mode to use, either by name or by type. Defaults to autowiring by name.
|
||||
* @see AutowireCapableBeanFactory#AUTOWIRE_BY_NAME
|
||||
* @see AutowireCapableBeanFactory#AUTOWIRE_BY_TYPE
|
||||
* @see AutowireCapableBeanFactory#AUTOWIRE_NO
|
||||
*/
|
||||
public void setAutowireMode(int autowireMode) {
|
||||
this.autowireMode = autowireMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured dependency check setting. Defaults to false.
|
||||
*/
|
||||
public boolean getDependencyCheck() {
|
||||
return dependencyCheck;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to perform a dependency check for object references in the instance being autowired. Defaults to
|
||||
* false.
|
||||
* @see AutowireCapableBeanFactory#autowireBeanProperties(Object, int, boolean)
|
||||
*/
|
||||
public void setDependencyCheck(boolean dependencyCheck) {
|
||||
this.dependencyCheck = dependencyCheck;
|
||||
}
|
||||
|
||||
/**
|
||||
* Autowire all objects in flash, flow and conversation scope for given flow execution.
|
||||
* @see #autowire(ScopeType, MutableAttributeMap)
|
||||
*/
|
||||
public void autowire(FlowExecutionContext flowExecutionContext) {
|
||||
// no need to autowire request scope since that will be setup from scratch in this request
|
||||
|
||||
// autowire flash and flow scope for all flow sessions in the flow execution
|
||||
FlowSession flowSession = flowExecutionContext.getActiveSession();
|
||||
while (flowSession != null) {
|
||||
autowire(ScopeType.FLASH, flowSession.getFlashMap());
|
||||
autowire(ScopeType.FLOW, flowSession.getScope());
|
||||
|
||||
flowSession = flowSession.getParent();
|
||||
}
|
||||
|
||||
// autowire conversation scope, which is not tied to the flow session
|
||||
autowire(ScopeType.CONVERSATION, flowExecutionContext.getConversationScope());
|
||||
}
|
||||
|
||||
/**
|
||||
* Autowire all objects in given flow execution scope.
|
||||
* <p>
|
||||
* Will invoke {@link #shouldBeAutowired(ScopeType, String, Object)} to determine whether or not an object should be
|
||||
* autowirded and {@link #autowire(ScopeType, String, Object)} to actually autowire it.
|
||||
*/
|
||||
protected void autowire(ScopeType scopeType, MutableAttributeMap scope) {
|
||||
for (Iterator keys = scope.asMap().keySet().iterator(); keys.hasNext();) {
|
||||
String key = (String) keys.next();
|
||||
Object value = scope.get(key);
|
||||
if (shouldBeAutowired(scopeType, key, value)) {
|
||||
autowire(scopeType, key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether or not given value, indexed using given key in specified flow execution scope, should be
|
||||
* autowired. The default implementation simply returns true, i.e. it tries to autowire all objects found in the
|
||||
* flow execution scopes.
|
||||
* <p>
|
||||
* Subclasses can override this method if they want to limit autowiring to a particular scope or to particular
|
||||
* objects, for instance objects implementing a paritcular marker interface, having a certain marker annotation or
|
||||
* objects whose class name follows some naming convention.
|
||||
*/
|
||||
protected boolean shouldBeAutowired(ScopeType scopeType, String key, Object value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Autowire given value indexed using given key in specified flow execution scope. By default, this method will
|
||||
* simply call {@link AutowireCapableBeanFactory#autowireBeanProperties(Object, int, boolean)} using the configured
|
||||
* {@link #setAutowireMode(int) autowiring mode} and {@link #setDependencyCheck(boolean) dependency check} settings.
|
||||
* <p>
|
||||
* Subclasses can override this method when special autowiring is required, for instance using any of the other
|
||||
* method offered by {@link AutowireCapableBeanFactory}.
|
||||
*/
|
||||
protected void autowire(ScopeType scopeType, String key, Object value) {
|
||||
getBeanFactory().autowireBeanProperties(value, autowireMode, dependencyCheck);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AutowireCapableBeanFactory} that will be used for autowiring.
|
||||
* <p>
|
||||
* Subclasses are required to implement this hook method.
|
||||
*/
|
||||
protected abstract AutowireCapableBeanFactory getBeanFactory();
|
||||
}
|
||||
Reference in New Issue
Block a user