Wednesday, November 26, 2008

Migrating from Spring Webflow 1 to Webflow 2

...was relatively painless. At least in the very small app that I'm currently working on as a helper application for dealing with one of our partners' systems. The flow definition migration assistant that comes with Webflow 2 is a huge help. There are, however, a few things to take note of when it comes to differences between Webflow 1 and Webflow 2. They are significantly different beasts to say the least :



  • My configuration went from this (in Webflow 1) :



    <flow:registry id="flowRegistry">
    <flow:location path="/WEB-INF/flows/**/*-flow.xml"/>
    </flow:registry>

    <flow:executor id="flowExecutor" registry-ref="flowRegistry">
    <!--flow:execution-listeners>
    <flow:listener ref="webflowDebugListener"/>
    </flow:execution-listeners-->
    </flow:executor>

    <!--bean id="webflowDebugListener" class="org.springframework.webflow.execution.DebuggingListener"/-->

    <bean name="flowController" class="org.springframework.webflow.executor.mvc.FlowController">
    <property name="flowExecutor" ref="flowExecutor" />
    <property name="argumentHandler">
    <bean class="org.springframework.webflow.executor.support.RequestParameterFlowExecutorArgumentHandler" />
    </property>
    </bean>


    To this (in Webflow 2) :



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

    <webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
    <webflow:flow-execution-listeners>
    <!-- webflow:listener ref="webflowDebugListener"/ -->
    <webflow:listener ref="securityFlowExecutionListener"/>
    </webflow:flow-execution-listeners>
    </webflow:flow-executor>

    <bean id="securityFlowExecutionListener" class="org.springframework.webflow.security.SecurityFlowExecutionListener" />

    <webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="viewFactoryCreator" conversion-service="webflowConversionService"/>

    <bean id="webflowConversionService" class="com.mypackage.modules.springframework.webflow2.ConversionServiceFactoryBean">
    <property name="editorMappings">
    <map>
    <entry key="java.util.Calendar"><idref bean="sqlDateCalendarEditor"/></entry>
    </map>
    </property>
    </bean>

    <bean id="viewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
    <property name="viewResolvers">
    <list>
    <ref local="xmlViewResolver"/>
    <ref local="decoratedJstlViewResolver"/>
    <ref local="urlBasedViewResolver"/>
    </list>
    </property>
    </bean>

    <bean id="webflowDebugListener" class="org.springframework.webflow.execution.DebuggingListener"/>

    <bean name="flowController" class="org.springframework.webflow.mvc.servlet.FlowController">
    <property name="flowExecutor" ref="flowExecutor" />
    <property name="flowUrlHandler">
    <bean class="org.springframework.webflow.context.servlet.DefaultFlowUrlHandler" />
    </property>
    </bean>


    Now, you may be asking yourself, "Why would there be more configuration in Spring Webflow 2 ? Doesn't Spring generally improve on things like configuration syntax between major versions ? The answer is, of course, yes. However, there are a number of new features that come with Webflow 2 that need to be configured, hence the extra beans for configuration. Note also, that the syntax has changed. I direct your attention to the added 'flow-' prefixes on element names of the previously existing Webflow elements.




  • Webflow 2 has much better, much closer integration with Spring Security, hence the need for SecurityFlowExecutionListener listed above. I haven't had a chance to play around with the new integration between Spring Security 2 and Spring Webflow 2, but I'm quickly getting there.


  • Thanks to the built in model binding and validation that comes with Spring Webflow 2, there's much less syntax for views that simply bind to a model object on transitions. Instead of having to add in FormActions and adding action elements to the view-state you want them applied to, you can now simply specify a model name for the 'model' attribute of the view state, and Webflow 2 will automatically bind the form object for you (which leads us into our next point). Of course, the Spring developers maintained their usual style of keeping things as configurable as possible, so you can not only choose not to bind the model object for particular state transitions, but you can disable validation as well, using the new 'bind' and 'validate' attributes of Webflow 2 'transition' elements.


  • Because Webflow 2 can now do binding and validation for us right in the flow definition without having to define FormAction beans in our Spring ApplicationContext, Webflow 2 comes with its own updates to the spring-binding framework, hence the need for the 'webflowConversionService' bean in the configuration above. Now, you're probably saying to yourself right now, "Well what the fuck am I supposed to do with the custom PropertyEditors I wrote for my objects when dealing with Spring / Webflow 1 ?". Don't worry, all is not lost. There's a PropertyEditorConverter class that adapts PropertyEditor implementations to the new Webflow 2 Converter interface. You can use this to interface your editors with Webflow 2, and in fact that's what I did.


  • Webflow 1 left it up to the Spring framework to resolve and render views. Some people found this inconvenient, so Webflow 2 now allows you to have Webflow directly resolve and render views itself. However, since I'm already using the Spring framework and don't need Webflow's abstraction away from the underlaying framework, I chose to keep the Webflow 1 style of resolution and view rendering, hence the need for the 'viewFactoryCreator' bean above.



Once all the new configuration was done and out of the way, it was simply a matter of upgrading my existing flows to the new Webflow 2 syntax, which was almost entirely taken care of by the migrator that comes with Webflow 2. Previously, I used the 'var' element heavily to make use of beans in my Spring ApplicationContext, but the 'var' element has since had its usage completely reworked for Webflow 2, so I'm going to have to refactor a couple of my flows and change my style of design with Webflow 2.

One other feature that I'm learning about as I write this post is the Webflow 2 PersistenceContext. It's a solution for the use case where you want to be able to load objects from a database, and only allow a single user to be able to access them at once, ie you wouldn't want multiple people logging into a database and being able to access data on a particular user at the same time and potentially overwrite each others' changes. I'll post more about that later.

No comments: