I have finally found a way (not really clean) to achieve my goal. Hereunder the code. I will post an enhancement ticket on JIRA to ask for giving access to those informations through the exposed Web Flow API. Sample use in the next post.
Code:
package org.springframework.webflow.config;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import org.springframework.util.Assert;
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
import org.springframework.webflow.engine.model.registry.AccessibleFlowModelRegistryAdapter;
import org.springframework.webflow.engine.model.registry.FlowModelHolder;
import org.springframework.webflow.engine.model.registry.FlowModelRegistry;
import org.springframework.webflow.engine.model.registry.FlowModelRegistryImpl;
/**
* <p>
* This class is a hook to give accessibility to the package visible class
* {@link DefaultFlowRegistry}, base implementation of the flow registry, which
* transitively give access to the {@link FlowModelRegistry}.
* </p>
*
* <p>
* The final goal is to retrieve {@link FlowModelHolder} thanks to the
* {@link FlowModelRegistry} with the flow id.
* </p>
*
* <p>
* The typical use is based on {@link AccessibleFlowModelRegistryAdapter},
* Spring bean that call this class to retrieve the {@link FlowModelRegistry}.
* See the documentation of this class for a sample use case.
* </p>
*
* @see <a href="http://forum.springsource.org/showthread.php?p=334261">Spring
* forum related post</a>
* @see AccessibleFlowModelRegistryAdapter
*/
public class AccessibleFlowDefinitionRegistryAdapter extends DefaultFlowRegistry {
/**
* The official Web Flow flows registry.
*/
@Inject
private FlowDefinitionRegistry flowRegistry;
/**
* Checks to detect a modification of implementation either of
* {@link FlowDefinitionRegistry}, or of {@link FlowModelRegistry}.
*/
@PostConstruct
public void postConstruct() {
Assert.notNull(flowRegistry, "flowRegistry bean has not been injected.");
Assert.isInstanceOf(DefaultFlowRegistry.class, flowRegistry,
"The implementation class of FlowDefinitionRegistry doesn't match the expected one (DefaultFlowRegistry). "
+ "Check if a version upgrade of Spring Web Flow hasn't modified the underlying implementation.");
Assert.notNull(((DefaultFlowRegistry) flowRegistry).getFlowModelRegistry(), "No FlowModelRegistry found inside flowRegistry bean."
+ "Check if a version upgrade of Spring Web Flow hasn't modified the underlying implementation.");
Assert.isInstanceOf(FlowModelRegistryImpl.class, ((DefaultFlowRegistry) flowRegistry).getFlowModelRegistry(),
"The implementation class of FlowModelRegistry doesn't match the expected one (FlowModelRegistryImpl). "
+ "Check if a version upgrade of Spring Web Flow hasn't modified the underlying implementation");
}
/**
* Retrieve the {@link FlowModelRegistry} associated to the default
* {@link FlowDefinitionRegistry}.
*
* @return the {@link FlowModelRegistry}
*/
@Override
public FlowModelRegistry getFlowModelRegistry() {
return ((DefaultFlowRegistry) flowRegistry).getFlowModelRegistry();
}
}
Code:
package org.springframework.webflow.engine.model.registry;
import java.lang.reflect.Method;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.webflow.config.AccessibleFlowDefinitionRegistryAdapter;
/**
* <p>
* This class is a hook to give accessibility to the {@link FlowModelRegistry},
* and more specifically to its private methode
* {@link FlowModelRegistry#getFlowModelHolder(String)}. It is based on another
* hook through the class {@link AccessibleFlowDefinitionRegistryAdapter}.
* </p>
*
* <p>
* The final goal is to retrieve {@link FlowModelHolder} thanks to the
* {@link FlowModelRegistry} with the flow id.
* </p>
*
* <h1>Sample use</h1>
*
* <h2>Spring configuration file</h2>
* <code><pre><bean class="org.springframework.webflow.engine.model.registry.AccessibleFlowModelRegistryAdapter" primary="false" /></pre></code>
*
* <h2>Concrete use</h2>
* <p>
* <code><pre>@Inject
private AccessibleFlowModelRegistryAdapter flowModelRegistry;
RequestContext requestContext = RequestContextHolder.getRequestContext();
String flowId = requestContext.getActiveFlow().getId();
FlowModelHolder flowModelHolder = flowModelRegistry.getFlowModelHolder(flowId);</pre></code>
*
* <p>
* This class implements {@link BeanFactoryPostProcessor} and
* {@link ApplicationContextAware} interfaces because it's responsible for
* registering and retrieveing the
* {@link AccessibleFlowDefinitionRegistryAdapter}.
* </p>
*
* @see <a href="http://forum.springsource.org/showthread.php?p=334261">Spring
* forum related post</a>
* @see AccessibleFlowDefinitionRegistryAdapter
*/
public class AccessibleFlowModelRegistryAdapter extends FlowModelRegistryImpl implements BeanFactoryPostProcessor, ApplicationContextAware {
/**
* The {@link ApplicationContext} setted by Spring when the bean is
* initialized thanks to the implementation {@link ApplicationContextAware}.
*/
private ApplicationContext applicationContext;
/**
* <p>
* Key method which is the main goal of all this hook. It give the ability
* to retrieve a {@link FlowModelHolder} associated to a flow from its
* flowId. This methode retrieve the {@link FlowModelHolder} from the
* underlying {@link FlowModelRegistry}.
* </p>
*
* <p>
* This method give access to the normally inaccessible private
* {@link #getFlowModelHolder(String)} of {@link FlowModelRegistryImpl}
* through some reflection.
* </p>
*
* @param id
* the flowId for which we want to retrieve the
* {@link FlowModelHolder}
* @return the {@link FlowModelHolder} of the specified flow or
* <code>null</code> if there is no {@link FlowModelHolder}
* associated to this flowId
*/
public FlowModelHolder getFlowModelHolder(String id) {
Method getFlowModelHolderMethod = ReflectionUtils.findMethod(FlowModelRegistryImpl.class, "getFlowModelHolder", String.class);
Assert.notNull(getFlowModelHolderMethod, "La méthode getFlowModelHolder(String id) n'a pas été trouvée sur la classe FlowModelRegistryImpl."
+ "Vérifier si une montée de version de Spring Web Flow n'aurait pas modifié l'implémentation sous-jacente.");
ReflectionUtils.makeAccessible(getFlowModelHolderMethod);
FlowModelHolder flowModelHolder = (FlowModelHolder) ReflectionUtils.invokeMethod(getFlowModelHolderMethod, getFlowRegistry()
.getFlowModelRegistry(), id);
return flowModelHolder;
}
/**
* {@inheritDoc}
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* Getter to retrieve the {@link AccessibleFlowDefinitionRegistryAdapter}
* bean. This bean is not injected because its definition is registered by
* this self class (through the implementation of
* {@link BeanFactoryPostProcessor}) and injecting a bean in the bean
* registering it doesn't work. So we retrieve it through
* {@link ApplicationContext#getBean(String, Class)}.
*
* @return the {@link AccessibleFlowDefinitionRegistryAdapter}
*/
private AccessibleFlowDefinitionRegistryAdapter getFlowRegistry() {
return applicationContext.getBean(getAccessibleFlowDefinitionRegistryAdapterName(), AccessibleFlowDefinitionRegistryAdapter.class);
}
/**
* The implentation of {@link BeanFactoryPostProcessor} preserve from
* declaring the two hook beans (
* {@link AccessibleFlowDefinitionRegistryAdapter} and
* {@link AccessibleFlowModelRegistryAdapter}) in the XML configuration.
*
* {@inheritDoc}
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
BeanDefinition flowDefinitionRegistryBean = new RootBeanDefinition(AccessibleFlowDefinitionRegistryAdapter.class);
flowDefinitionRegistryBean.setPrimary(false);
registry.registerBeanDefinition(getAccessibleFlowDefinitionRegistryAdapterName(), flowDefinitionRegistryBean);
}
/**
* Retrieve a camel case unique identifier of the
* {@link AccessibleFlowDefinitionRegistryAdapter} bean derived from the
* className.
*
* @return the unique identifier of the
* {@link AccessibleFlowDefinitionRegistryAdapter} bean
*/
private String getAccessibleFlowDefinitionRegistryAdapterName() {
String className = AccessibleFlowDefinitionRegistryAdapter.class.getName();
return className.substring(0, 1).toLowerCase() + className.substring(1);
}
}