Building Shale JavaOne Demo
If you have read my recent blog entries, then you will probably have begun to see pattern in each of these entries. I have been devoting my precious time to building early Shale products. (Mabye that's a little sad. I suppose it is. Let's try to find some bigger theme next week. I've heard rumours about the "Java World Peace" JSR. I think I will work on that next week.)
Today is not going to be any different. Yesterday I blogged about the use cases web application found in the Shale source code repository. Today, I'm going to build the other Shale demo that has been around for a while: this is the demo used by David Geary and Craig McLanahan at JavaOne.
The original source code of the demo can be downloaded from www.jsfcentral.com. Unfortunately, it doesn't come with a prebuild war file, but the intent of this blog entry is to change that.
What did we just download?
The jar file that is provided by jsfcentral.com contains all of the sources and an Apache Ant build.xml file. Unfortunately it doesn't ship all of the required libraries, so if you really want to build the demo using Ant, then you should 1) download a lot of stuff manually and 2) modify a hurendous number of properties. Does that sound boring? In that case, you may want to choose to use Maven instead. (In fact, I don't leave you much of a choice. The remainder of this page assumes that you prefer to go the Maven way as well.)
The Way of the Maven
The demo obviously doesn't come with all of the different Maven files, but I composed a zip file that you can unzip in the root directory of the unzipped demo jar. After unzipping it, you can move into the "Shale Demo" directory, and build the war file like this:
maven [-Dmaven.proxy.port=... -Dmaven.proxy.host=...] clean war
I didn't actually bother to find out if there would be a way to deploy the war file automatically. I think the build script has something on board, but since you will probably run the application on Jakarta Tomcat 5.*, you can also copy it in the $CATALINA_HOME/webapps directory. You can download the complete WAR file here.
What Did Just Happen?
Basically, if you would have done it yourself, then you would have run into a couple of things that you would have to solve yourself. Let's find out what they are:
Dependencies
First of all, you would have been required to resolve all of the dependencies. In this case, all of the dependencies have been explicitly listed in the project.xml file. The only exception to this rule is the tiles-core.jar file, residing in the lib/ directory. Although that file is listed as a dependency in the project.xml file, it's location is overridden in the project.properties file. If you ever feel the need to build it to a more recent version of Tiles, then this is the thing you should be aware of.
Make War
The next problem is to recreate the war in Maven. You don't really need to know this, but it might be interesting to know a little more if you feel like adding a couple of new files to the war. In that case, you should check out maven.xml. This file contains a postGoal war:webapp, copying all of the files that could not be pinpointed by the war plugin to the relevant build directory. (This includes almost all of the static resources, since the directory structure of the demo war is quite different than the Maven project model.)
Shale Dependencies
Since Maven is trying to dig up the jar file on which the project depends automatically, it will also try to resolve some Shale specific libraries. These libraries do not yet exist in the Maven ibiblio directory. The easy way out is to build the Shale libraries yourself as well. (Return to one of my previous blog entries to figure out how.)
MyFaces vs. JSF RI
This one is particularly tricky. You can use the JSF RI application to build the demo application, but you can't use the RI to run the application. (Huh?!) If you would use the JSR RI, then you would find out immediately that the sample application is trying to access a variable called users that it cannot find. The trouble is that the sample application is using the Shale Spring enhancements and tries to load the bean from the bean definition in applicationContext.xml. In this case, the JSF RI breaks its own specification, causing the DelegatingVariableResolver to fail. As a result, the JSF implementation simply reverts to the default configuration mechanisms (faces-config.xml) and this file does not define a bean called users.
Find Bug
If you have done all of the above, everything seems just fine. That is, it displays the page that I expected. Aparently, this is applications exists with the sole purpose to create users. So let's give it a try. The application takes me to a number of screens without any problems. Just when you thing that everything is fine, and hit the "Finish" button to complete the registration sequence, it fails with an exception...
java.lang.IllegalArgumentException: Position[dialogName=Create Account,stateName=Create User],outcome=finish org.apache.shale.dialog.faces.DialogNavigationHandler.transition(DialogNavigationHandler.java:484) org.apache.shale.dialog.faces.DialogNavigationHandler.action(DialogNavigationHandler.java:236) org.apache.shale.dialog.faces.DialogNavigationHandler.preprocess(DialogNavigationHandler.java:353) org.apache.shale.dialog.faces.DialogNavigationHandler.postprocess(DialogNavigationHandler.java:326) org.apache.shale.dialog.faces.DialogNavigationHandler.handleNavigation(DialogNavigationHandler.java:207) org.apache.myfaces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:84)
Looking at the source code, it appears that the application is running into problems when trying to find the next transition, based on the outcome of the processing the previous action. (Line 479).
479 Transition transition = state.findTransition(outcome);
480 if (transition == null) {
481 transition = state.getDialog().findTransition(outcome);
482 }
483 if (transition == null) {
484 throw new IllegalArgumentException
485 (status.peek().toString() + ",outcome=" + outcome);
486 }
So it can't find a transition for the incoming outcome value. That is, after completion of the accountPage.finish() method, it wants to go somewhere else. That's funny. If you look at the code of the dialog-config.xml file, there isn't any definition of a potential transition at all. And the "Create User" state has not been defined to be an endstate. As a result, Shale gets so confused that it falls apart.
...
<action name="Create User"
method="#{accountPage.finish}">
</action>
...
The solution, (and really the only solution I could think of) is to add the transition. It appears that the accountPage.finish() operation returns "finish" in case of success. So the solution is to simply change the dialog-config.xml file as mentioned below. The zip file with Maven artifacts also contains a patched version of the dialog-config.xml file, that looks like this:
...
<action name="Create User"
method="#{accountPage.finish}">
<transition outcome="finish"
target="Exit"/>
</action>
...
JSF
Shale
Maven
( Sep 15 2005, 03:42:25 PM CEST )
Permalink
Comments [1]


