By the way...

This content is now pretty old: check the homepage for the latest.

Ok. Today, it's time to look under the hood.

Firstly, I decided to move the petclinic application to its own directory and clean up the paths a bit so that they reflected the usual way I organise java applications. Also, I wanted this to be a standalone application and therefore I needed to remove some of the relative paths in project.properties so that we didn't need the Rich Client source around to compile and run it. Finally, to satisfy my TDD cravings, I added junit test build targets in and created a dummy test to ensure junit was up and running.

After fixing a number of little build.xml bugs, I got the project compiling again in its own directory. So far, so good. Right, time to look at how this all works.

A look at the build.xml shows that the petclinic-standalone.jar we ran in the first session uses PetClinicStandalone.java as its entry point, so let's start with that:

public class PetClinicStandalone {
    public static void main(String[] args) {
        try {
            String rootContextDirectoryClassPath = "/org/springframework/richclient/samples/petclinic/ctx";
            String startupContextPath = rootContextDirectoryClassPath + "/common/richclient-startup-context.xml";
            String richclientApplicationContextPath = rootContextDirectoryClassPath
                    + "/common/richclient-application-context.xml";
            String businessLayerContextPath = rootContextDirectoryClassPath + "/common/business-layer-context.xml";
            String securityContextPath = rootContextDirectoryClassPath + "/standalone/security-context.xml";
            new ApplicationLauncher(startupContextPath, new String[] { richclientApplicationContextPath,
                    businessLayerContextPath, securityContextPath });
        } catch (Exception e) {
            System.exit(1);
        }
}

Ok, that looks straightforward. We hard code a number of paths to what look like XML files of spring beans, and pass them into an "ApplicationLauncher". They're split into two groups: the "startup context file", and an array of "the other context files".

The startup context

I'm guessing a "startup context file" contains special beans to help with the startup of the application. A quick look at ApplicationLauncher.java confirms this; the javadoc for the constructor reads:

Launch the application using the spring application context
at the provided paths for configuration. The startup context
path is loaded first to allow for quick loading of the
application splash screen.

Excellent. That must be what stuck that frog picture on my screen in session one. Let's have a look at the richclient-startup-context.xml file:

  <beans>
    <bean id="splashScreen" class="org.springframework.richclient.application.SplashScreen" singleton="false">
      <property name="imageResourcePath">
        <value>/images/splash-screen.jpg</value>
      </property>
    </bean>
  </beans>

A little more digging in the code shows that that "splashScreen" bean is actually a hard coded bean name in the ApplicationLauncher, so I guess if you want a splash screen in your application, just do exactly as the sample does.

At this point a strong temptation to vandalise splash-screen.jpg with a cheeky "Hello, world!" came over me (that would satisfy my brief for this session in one go, right?). But we wouldn't learn much from that, and I feel like I'm on a roll here.

Right, what about those other application context files? More looking through ApplicationLauncher.java shows me that they're piped into a good ol' ClassPathXmlApplicationContext, familiar to Spring aficionados the world over. One application context is created from all the files: I guess they're split up into different files so different variants of Petclinic (I'm thinking client/server here) can mix and match different beans as they wish.

Let's look at each of these files in turn:

security-layer-context.xml

This file contains a bunch of familiar looking ACEGI Security beans. I'm not going into the details of setting up ACEGI security - being a totally non-invasive security architecture, if you don't want it you shouldn't have to worry about it. At least, that's true for 'regular' Spring, and I'm guessing that it'll be the same here too.

business-layer-context.xml

This is familiar territory for anyone using spring for web applications. We find a data source (petclinic uses HSQL to store its data), a transaction manager, and a DAO in the form of a "clinic" bean. No suprises here.

richclient-application-context.xml

That leaves us with richclient-application-context.xml, which is all new. I have to say at this point I baulked slightly at the sheer number of new beans to learn. But hey, somebody wrote it, so someone must understand it, right? Therefore it must be possible to figure it out...

With that in mind, let's start with the first three beans:

<p>
  <bean id="application"
    class="org.springframework.richclient.application.Application">
    <constructor-arg index="0">
      <ref bean="applicationDescriptor"/>
    </constructor-arg>
    <constructor-arg index="1">
      <ref bean="petclinicLifecycleAdvisor"/>
    </constructor-arg>
  </bean></p>
  <p>
  <bean id="applicationDescriptor" class="org.springframework.richclient.application.support.DefaultApplicationDescriptor">
    <property name="version">
      <value>1.0</value>
    </property>
    <property name="buildId">
      <value>20041025001</value>
    </property>
  </bean>
  </p>
  <p>
    <bean id="petclinicLifecycleAdvisor"
    class="org.springframework.richclient.samples.petclinic.PetClinicLifecycleAdvisor">
<property name="windowCommandBarDefinitions">
      <value>org/springframework/richclient/samples/petclinic/ui/commands-context.xml</value>
    </property>
<property name="startingPageId">
      <value>ownerManagerView</value>
    </property>
  </bean></p>

From looking at ApplicationLauncher, "application" is a "magic name" for a bean - that is, the framework looks specifically for a bean called "application" in one of its XML files. It's set up with two other beans - applicationDescriptor and a lifecycle advisor. ApplicationDescriptor looks very straightforward - a version and a build number. I'm guessing that goes in the title, and perhaps an automated "Help - About" screen later on (here's hoping, anyway :).

The lifecycle advisor looks a little more involved. It appears to be configured with another xml file, which I'll look at in a bit, and a "starting page id" which refers to an "owner manager view". Looking at ApplicationLauncher (again), it appears that on launch a window is opened with this "owner manager view" page displayed first. After that, onPostStartup() is called on the lifecycle advisor.

From this it looks like the lifecycle advisor is used here as the application flow manager. The two methods overridden for the petclinic application look like they create the Setup Wizard and the login screen. I guess that there are many things one could add to this to perform custom actions at various points within the application.

Look and Feel

At this point I notice that the JGoodies support I raved about earlier is neatly encapsulated in one bean:

  <bean id="lookAndFeelConfigurer"
    class="org.springframework.richclient.application.config.JGoodiesLooksConfigurer">
<property name="popupDropShadowEnabled" value="false" />
<property name="theme">
      <bean class="com.jgoodies.looks.plastic.theme.ExperienceBlue"/>
    </property>
  </bean>

Searching through the Rich Client codebase turns up another magic bean name in ApplicationServices.java:

public static final String LOOK_AND_FEEL_CONFIGURER_BEAN_ID = "lookAndFeelConfigurer";

There's a whole lot of other magic bean names in there - if you are wondering what to name a bean, that's a good place to start looking!

Changing the Setup Wizard

Most of the rest of the beans I think I'll have to leave for this session, save the last one - the "setupWizard":

  <bean id="setupWizard"
    class="org.springframework.richclient.application.setup.SetupWizard">
<property name="licenseTextLocation">
      <value>/org/springframework/richclient/samples/petclinic/license.html</value>
    </property>
  </bean>

If I can modify the wizard to show a "Hello, World!" page, then I'll be happy.

Looking at the code for SetupWizard, I notice that it adds a SetupIntroWizardPage object. This object references a number of messages, including "setup.intro.description". Hah! I remembered that richclient-application-context.xml had some references to "message source" type beans, but rather than work all that stuff out at this stage, I cheat and search the whole source tree for "setup.intro.description". This turns up a reference in petclinic/ui/messages.properties:

setup.intro.description=The petclinic sample application demonstrates the base capabilities of Spring's Rich Client Project, built on standard J2SE Swing.

Right, time to fulfill the brief:

setup.intro.description=Hello, world! This page shows that I can trivially change a text file and by making text appear differently, I can impress my peers without really knowing what I'm doing.

A quick recompile, and here's the result:

It's not that impressive, I grant you. But at least it shows that if a Rich Client application is written correctly, you can leverage Spring's built in message support. This is vital for things like localisation.

Summary

A quick summary of what we've learnt in this session:

  • To launch a Spring Richclient Application, you use some boilerplate code in a standard main() method to initialise an ApplicationLauncher with some Spring beans XML files.
  • You may include an optional startup XML file containing one specially named bean for a splash screen.
  • Many Rich Client specific beans in the XML files are specially named and are probably required to be present. This means I'll most likely copy the Rich Client specific file and modify it, rather than creating from scratch.
  • Look and feel configuration is trivially handled through a specially named bean in the XML configuration files.
  • The setup wizard shipped with the Rich Client framework uses standard spring messaging by default, allowing us to trivially customise the text.

Next session, we'll look at some those of the other beans in richclient-application-context.xml and work out what on earth they're for. Stay tuned.