Written by Roy van Rijn (royvanrijn.com) on
Dec 15, 2009 15:25:15
Splitting up Spring Web Flow & Facelets into JARs
In our current project we want to have multiple Spring Web Flow-flows in one WAR-file. But we also want the flows and pages to be inside seperate JAR files, making the application a bit more managable and modulair.
This sounds straightforward but it took quite a bit of code and time…
First I created a single WAR-project with all the basic Spring, JSF and Facelet configuration. Like any Spring Web Flow (SWF) project we have a project-servlet.xml.
The first thing I did was changing our flowRegistry:
The classpath*: allows SWF to search the whole classpath for flow-directories containing a flow definition.
In our case it would be: /flows/module1/module1-flow.xml
When you try to run this, and access a page we got the following exception:
For some reason Spring Web Flow doesn’t want to load the facelet. After browsing around Spring’s forums I came across some solutions. They didn’t do the trick, only when combining several methods I got it working for Spring Web Flow 2.0.7.
This is how I did it, we need to tell Facelets to use our custom ClassPathResourceResolver:
The resolver itself is basic but does the job:
This will help Facelets to translate a given path to a java.net.URL using the current classloader.
Spring Web Flow is currently giving us a FileSystemResource, and this doesn’t work because we want to load the pages with our classloader. For this we have the following wrapper:
To force Spring to use this Resource instead of FileSystemResource we use a post processor:
When the FlowDefinitionRegistry is created we provide it with a new ResourceLoader. When the resources are requested by Spring Web Flow we create our own CustomClassPathContextResource. This consists of our current location plus the defined location (viewId).
To register this post processor add it to your project-servlet.xml:
How to use it
In our project we have the following flow(s) defined in a seperate JAR:
/flows/module1/module1-flow.xml
And our pages are in the same directory:
/flows/module1/page1.xhtml
/flows/module1/page2.xhtml
etc…
In the flow we can now use the following view-id’s:
Its also possible to have pages in other places, you can define the views as relative paths. For example: ”../../shared_pages/page2.xhtml” turns into “/shared_pages/page2.xhtml” ”../pages/page3.xhtml” turns into “/flows/pages/page3.xhtml”
The only problem we still have using this method is the deployment with RAD/Eclipse WTP and Facelets auto-refresh. For some reason after deploying our application locks the files in the bin-directory. Eclipse then can’t delete this directory and fails to publish. Ending in one big #fail. But a simple clean, clean, republish, clean, rebuild, restart, shout, scream, cry, rebuild and republish will solve this.
The big advantage is the fact that the flows and pages are now defined in their own JAR files, making releases and sharing classes (like shared services/shared menu’s etc) much easier.