Monday 15 October 2012

What does webflow:flow-registry tag do?

I have been studying the spring webflow's example project, booking faces, these days.

In webflow-config.xml, the definition of flowRegistry is as follows.


<webflow:flow-registry id="flowRegistry" flow-builder-services="facesFlowBuilderServices" base-path="/WEB-INF/flows">
    <webflow:flow-location-pattern value="/**/*-flow.xml" />
</webflow:flow-registry>


<faces:flow-builder-services id="facesFlowBuilderServices" development="true" />

The webflow namespace has long been baffling me. Is flowRegistry a bean? If it is, then why is it not defined in a typical way like

<bean id="flowRegistry" class="....">
    ...
</bean>

However, I have been too slack to find the answer. Now the addition of flow-builder-services="facesFlowBuilderServices" makes it more complex. Is this facesFlowBuilderServices a bean? If it is, why does it look so out of place?

All of a sudden, I just feel obliged to investigate the problem thoroughly.

I put a break point at DefaultListableBeanFactory.java @Line 564.

Here is the code from Line 562-564

List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

The variable beanNames holds, not surprisingly, all the bean names.

The variable bd contains the bean definition, which is derived from the application context xml.

When the program hits the break point, it's easily seen that both flowRegistry and facesFlowBuilderServices are among the bean names.

I keep pressing F8 until the variable beanName becomes flowRegistry.

I inspect the variable bd.

beanClass = org.springframework.webflow.config.FlowRegistryFactoryBean

Expand propertyValues -> propertyValueList -> elementData -> [0]

name = flowBuilderServices
value = <facesFlowBuilderServices>

Collapse [0] and expand [1]

name = basePath
value = /WEB-INF/flows

Collapse [1] and expand [3]

name = flowLocationPatterns
value = [/**/*-flow.xml]

OK, it is clear to see that the webflow:flow-registry tag defines the flowRegistry bean. If we wanted, we could define the bean in the traditional way, which is less succinct:

<bean id="flowRegistry" class="org.springframework.webflow.config.FlowRegistryFactoryBean">
    <property name="flowBuilderServices" ref="facesFlowBuilderServices" />
    <property name="basePath" value=" /WEB-INF/flows" />
    <property name="flowLocationPatterns" value="/**/*-flow.xml" />
</bean>

Let's do an experiment by taking out the flow-builder-services="facesFlowBuilderServices" bit off the flowRegistry bean definition and see if the flowBuilderServices will be null or some default value will be provided.

Repeat the same process, we will find

name = flowBuilderServices
value = <org.springframework.webflow.engine.builder.support.FlowBuilderServices#0>

A default value is provided.

We can employ the same approach to find out the difference between the default flowBuilderServices and facesFlowBuilderServices.

The class for both beans is org.springframework.webflow.engine.builder.support.FlowBuilderServices

The property viewFactoryCreator of the default flowBuilderServices is an instance of org.springframework.webflow.mvc.builder.MvcViewFactoryCreator.

The property viewFactoryCreator of the facesFlowBuilderServices is an instance of org.springframework.faces.webflow.JsfViewFactoryCreator.

One of the differences between MvcViewFactoryCreator and JsfViewFactoryCreator is that MvcViewFactoryCreator appends the extension '.jsp' to the view while JsfViewFactoryCreator  appends the extension '.xhtml' to the view.

Let's recapitulate the main points.
  • The <webflow:flow-registry> tag defines a flowRegistry bean.
  • The <faces:flow-builder-services> tag defines a facesFlowBuilderServices bean.
  • When flow-builder-services="facesFlowBuilderServices" is omitted, a default flowBuilderServices instance will be created. 

2 comments: