Hacking on GraphHopper - a Java road routing engine. Peter has posted 62 posts at DZone. You can read more from them at their website. View Full User Profile

Spring Rich Client - Part 2

07.03.2008
| 14642 views |
  • submit to reddit

Let us do some more basics with the “Spring Rich Client” 1.0.0 (SpringRC). Although it is time to give an overview of the entire architecture I won’t do this here, because I am a newbie with Spring and SpringRC. So we will just look into the steps how we get things running.

Startup

First of all we want to include a license prompt on the very first startup. If it is in pure text format surround the license with <pre>licenseText</pre>, save it to the classpath as /path/license.txt and do the following:

  • Add the source code into LifecycleAdvisor
        private final Log logger = LogFactory.getLog(getClass());
        private static final String SHOW_WIZARD_KEY = "setupWizard.show";
        private Settings settings;
        @Override
        public void onPreStartup() {
            boolean showDialog = true;
            if (settings.contains(SHOW_WIZARD_KEY)) {
                showDialog = settings.getBoolean(SHOW_WIZARD_KEY);
            }
            if (showDialog && getApplication().getApplicationContext().containsBean("setupWizard")) {
                SetupWizard setupWizard = (SetupWizard) getApplication().getApplicationContext().getBean(
                        "setupWizard", SetupWizard.class);
                setupWizard.execute();
                settings.setBoolean(SHOW_WIZARD_KEY, false);
                try {
                    settings.save();
                } catch (IOException ex) {
                    logger.error("Can't save state.", ex);
                }    }    }
        public void setSettings(Settings set) {
            settings = set;
        }
  • Add the following text into the application-context.xml
    <bean id="setupWizard" class="org.springframework.richclient.application.setup.SetupWizard">
        <property name="licenseTextLocation" value="/path/license.txt" />
    </bean>
    <bean id="xmlInternalSettings"
          class="org.springframework.richclient.settings.xml.XmlSettingsFactory"
          factory-bean="settingsManager"
          factory-method="getInternalSettings">
    </bean>
    <bean id="settingsManager" class="org.springframework.richclient.settings.SettingsManager">
            <property name="settingsFactory">
                <bean class="org.springframework.richclient.settings.xml.XmlSettingsFactory"/>
            </property>
    </bean>

    And insert <property name=”settings” ref=”xmlInternalSettings” /> into the lifecycleAdvisor bean’s property list.

  • As last step you have to fill in the message text for this wizard into the message.properties file:
    setup.intro.welcomeTo = Welcome to
    setup.intro.title = TimeFinder!
    setup.intro.description = TimeFinder in one of its future releases will help you with automatic and manual timetabling.
    setup.cancel.title=Cancel Setup
    setup.cancel.message = Do you really want to exit the application?
    acceptLicenseCommand.label=I &accept the terms of this license agreement
    doNotAcceptLicenseCommand.label=I do ¬ accept the terms of this license agreement
    setup.license.title=License agreement
    setup.license.description=Please read the following license agreement carefully

The most of the xml code above is necessary to inject a new instance of Settings which will be created from the SettingsManager.

… Break …

Does anybody of you know, how I can do this in Java, not in ugly xml? Well, I could create the factory directly in the LifecycleAdvisor, but how can I do this dependency injection in Java (with Spring)?

… Okay, let us go further …

This settings object is then accessible within the LifecycleAdvisor because of the setSettings method and is necessary to save, if this wizard should be prompted on the next startup again. The xml-settings will be written to currentPath/settings/internal.settings.xml.
The used SetupWizard extends from AbstractWizard. This abstract class could be used for any other wizards: just add one or more AbstractWizardPages to the wizard and see this documentation. Here is the result:


Another cool feature is to show a progressbar on the splashscreen. This was very easy: add (or replace the existing) bean to the startup-context.xml file:

<bean id="splashScreen" class="org.springframework.richclient.application.splash.ProgressSplashScreen" scope="prototype">
        <property name="imageResourcePath" value="/de/peterk/springr/ui/images/splash-screen.png" />
        <property name="showProgressLabel" value="true" />
</bean>

Now I did an ugly hack. I want to change the colors of the progressbar. But only on the progressbar on startup, so we have to revert the following code:

Color myYellow = new Color(255, 225, 100);
Color myGreen = new Color(120, 208, 60);
UIManager.put("ProgressBar.selectionForeground", myYellow);
UIManager.put("ProgressBar.selectionBackground", myGreen);
UIManager.put("ProgressBar.foreground", myGreen);
UIManager.put("ProgressBar.background", myYellow);
UIManager.put("ProgressBar.border", new LineBorderUIResource(myYellow));

To revert these changes, please look into the method LifecycleAdvisor.onPreWindowOpen (see the resources section, I will not post it here - it is too stupid ;-))

Here is the result:

Published at DZone with permission of its author, Peter Karussell.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Geertjan Wielenga replied on Thu, 2008/07/03 - 2:28am

Thanks again for this info, I'm learning a lot from it. However, I want to comment on this paragraph:

The most important point for me is that SpringRC is ‘only’ a sweat jar collection and not a layer between me and Swing. This is one of the reasons I cannot use NetBeans RCP: with NetBeans you have to learn new stuff (from ground up) and you should forget nearly all things you learned for Swing. Okay, someone will argue that you can even use Swing directly (like JOptionPane.showMessage) but this is not the recommended way of doing things within NetBeans RCP.

 

I like Spring RCP a lot (and am working on a second part to "Getting Started with Spring RCP", which should be published on Javalobby either today or tomorrow), but to say that with NetBeans RCP you "have to learn new stuff (from ground up) and you should forget nearly all things you learned for Swing", is simply untrue. It is 100% false, in fact. You can use Swing as much as you like. Yes, you can use JOptionPanes, though NetBeans RCP offers its own alternatives, you are right about that. However, similarly, with Spring RCP you can continue using the standard Swing dialogs, even though Spring RCP has its own alternatives that it recommends you use. That's great isn't it, both offer additional Swing components. Not bad in either case. I must say that I'm spending the same amount of time learning Spring RCP as I did when I started learning NetBeans RCP.

The real difference between them is that NetBeans RCP is modular, letting you create applications that can be extended via plugins, while Spring RCP doesn't let you do that. Nothing wrong with that. It only means that NetBeans RCP is more suited to very large applications than Spring RCP is. It would be completely impossible, for example, to have created NetBeans IDE on top of Spring RCP. (Plus, I can create my own independent plugins for any application based on top of NetBeans RCP... but how would I create a plugin for the application you are building in this series of articles? And how would you install that plugin into your application?) Since NetBeans RCP is modular, it was perfect for NetBeans IDE, since the IDE is created by many different people in an extremely distributed environment, so that a modular approach fits very well with the distributed workplaces, as well as resulting in very clean code (i.e., no spaghetti code across modules). Therefore, I believe Spring RCP is closer in intention to JSR-296 than it is to NetBeans RCP (actually, it is called "NetBeans Platform") and Eclipse RCP.

Peter Karussell replied on Thu, 2008/07/03 - 5:34am

Hi Geerjan!

[quote]

but to say that with NetBeans RCP you "have to learn new stuff (from ground up) and you should forget nearly all things you learned for Swing", is simply untrue. It is 100% false, in fact.

[/quote]

Hmmh, yes. But as I was using NetBeans RCP 5

I was lost in the new API (no books were published). And I had the feeling that I should use the API to get no bugs etc.

Sorry, I should have marked it with my personal feeling. Not as a fact. I am very sorry about this, because I love NetBeans and I don't want bash against it.

[quote]

I must say that I'm spending the same amount of time learning Spring RCP as I did when I started learning NetBeans RCP.

[/quote]

My personal experience :-) was completely different here. Very quick results with Spring RC and no bugs. With NetBeans I got some strange bugs that I even didn't see in the IDE.

I must say that I all my experiences are possible out of date like my example:

http://genvlin.berlios.de

Please see the Media Zone to try it and the Download Zone to test it and to get an idea of what I mean.

Harris Goldstone replied on Thu, 2008/07/03 - 6:52am

So apps created on the Spring RCP are not pluggable?

Steven Baker replied on Thu, 2008/07/03 - 5:37pm

sometimes i miss when people hard coded things...

it was a simplier time...

Geertjan Wielenga replied on Fri, 2008/07/04 - 2:18am

Peter, the stuff on http://genvlin.berlios.de/ looks very interesting. I will take a look at it.

Richard Osbaldeston replied on Fri, 2008/07/04 - 9:07am

Does Spring RCP have support for a multiple-document interface? (think MS Word >2003). I mean can I have more than one instance of my application and it's classes running in the same JVM. Just wondering how it resolves which action 'belongs' to which application instance in this kind of scenario. Pet question as JSR296 fell sort on this as it also had a similar  getApplication()/getApplicationcontext() as a singleton.

Peter Karussell replied on Fri, 2008/07/04 - 3:42pm

[quote] Does Spring RCP have support for a multiple-document interface? [/quote]

Yes. You can duplicate the application.

[quote] Just wondering how it resolves which action 'belongs' to which application instance in this kind of scenario.[/quote]

Yes, thats right. Not an easy task. I will ask the developers.

[quote] sometimes i miss when people hard coded things... it was a simplier time... [/quote]

... for the developer, but not for the user, I think.

[quote] So apps created on the Spring RCP are not pluggable? [/quote]

What do you mean with "pluggable"?

Harris Goldstone replied on Fri, 2008/07/04 - 3:52pm in response to: Peter Karussell

[quote=peathal][quote]

So apps created on the Spring RCP are not pluggable? [/quote]

 

What do you mean with "pluggable"? 

[/quote]

 

I mean can I create a plugin for an app created on top of Spring RCP? Many modern apps are pluggable and I was wondering if there is some way that that is possible with Spring RCP.

Peter Karussell replied on Fri, 2008/07/04 - 4:05pm

[quote]I mean can I create a plugin for an app created on top of Spring RCP? Many modern apps are pluggable and I was wondering if there is some way that that is possible with Spring RCP.[/quote]

no, I don't think this is possible. Actually there is a discussion about this for the upcoming spring desktop:

http://www.nabble.com/Re%3A--Spring-Desktop--ideas-for-the-Desktop-version-p18229540.html

 

Peter De Bruycker replied on Mon, 2008/07/07 - 6:25am in response to: Peter Karussell

As one of the developers of Spring RCP, I have the following remarks:

  1. Spring RCP applications CAN be pluggable. Spring RCP doesn't include a plugin architecture, but you can use existing solutions for that (OSGI, JPF, roll your own, ...)
  2. There is support for custom progress bar creation in Spring RCP: create a subclass of ProgressSplashScreen, override the getProgressBar method, set your custom colors there, and after creation of the progressbar, revert the changes made to the uimanager:
<code> 
public class CustomProgressSplashScreen extends ProgressSplashScreen {

    @Override
    protected JProgressBar getProgressBar() {
        // colors
        Color backupForeground = UIManager.getColor("ProgressBar.selectionForeground");
        Color backupBackground = UIManager.getColor("ProgressBar.selectionBackground");
        
        Color myYellow = new Color(255, 225, 100);
        Color myGreen = new Color(120, 208, 60);

        UIManager.put("ProgressBar.selectionForeground", myYellow);
        UIManager.put("ProgressBar.selectionBackground", myGreen);

        // create the progressbar
        JProgressBar progressBar = new JProgressBar();
        progressBar.setForeground(myGreen);
        progressBar.setBackground(myYellow);
        progressBar.setBorder(BorderFactory.createLineBorder(myYellow));

        // restore the default colors
        UIManager.put("ProgressBar.selectionForeground", backupForeground);
        UIManager.put("ProgressBar.selectionBackground", backupBackground);
        
        return progressBar;
    }
}
</code> 
This way, you keep all the dirty stuff in one class. 

Hope this helps,

Peter

Peter Karussell replied on Sat, 2008/07/12 - 6:36pm

@peterdb Thanks a lot! This helps a lot.

@richard I asked the question on the dev list. Here is the answer of Jan [*].

This means for evey new instance the xml file is parsed again and all components are newly created.

Regards, Peter. 

 

[*] 

I'll give it a shot:

As a first, I have to inform you that the application that is started
with Spring RCP is a Singleton. So one application per VM. This includes
it's ApplicationServices which are retrieved by the
ApplicationServiceLocator Singleton.

Secondly: there are solutions for MDI in the form of docking frameworks.
Look into the docking module to find out more. This might be what you're
referring to?

As a third: there can be multiple windows per application. As a
consequence of this, the current commands are defined in a separate
context file. This file is re-read when creating a new window in order
to have the correct parent window injected if the command needs to be
window-aware. This allows to have multiple windows, sharing the same
resources, running on one vm and opening different views/dialgs etc...

Thus looking upon this, yes you can do MDI, but no you cannot have
multiple instances running on the same VM. In most cases, the latter
isn't a problem.

Peter Karussell replied on Sat, 2008/07/12 - 6:52pm

Hi peter, I tried it one slight change is necessary to create the progressbar:

JProgressBar progressBar = super.getProgressBar(); 

Peter De Bruycker replied on Mon, 2008/07/14 - 6:24am

Peter,

I updated the code, so you don't have to override the getProgessBar method, but the createProgressBar method.

Thanks for your feedback!

regards,

Peter

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.