A practical introduction

helpflightInternet and Web Development

Nov 10, 2013 (3 years and 9 months ago)

112 views




Spring
Rich
Client


A

practical
introduction

An
introduction to the Spring Rich Client framework

Lieven DOCLO


2

CONTENTS

Introduction

................................
................................
................................
................................
................................
........................

5

Overview

................................
................................
................................
................................
................................
.........................

5

Getting our hands dirty

................................
................................
................................
................................
................................
...

5

The Spring Rich Client framework, a quick dissection

................................
................................
................................
........................

8

Anatomy of a rich client application

................................
................................
................................
................................
...............

8

Application windows

................................
................................
................................
................................
................................
.......

8

Views

................................
................................
................................
................................
................................
...............................

9

Commands

................................
................................
................................
................................
................................
......................

9

Messages and icons

................................
................................
................................
................................
................................
......

11

Ot
her components

................................
................................
................................
................................
................................
........

11

Applications

................................
................................
................................
................................
................................
......................

12

Application lifecycle

................................
................................
................................
................................
................................
......

12

Hooking in
to a lifecycle

................................
................................
................................
................................
................................
.

12

Application

................................
................................
................................
................................
................................
....................

12

Example: Adding login functionality to the application

................................
................................
................................
................

12

Other possible uses

................................
................................
................................
................................
................................
.......

13

Playing with the statusbar

................................
................................
................................
................................
............................

13

El
aborate example: Adding multiple toolbars to the screen

................................
................................
................................
........

14

Commands

................................
................................
................................
................................
................................
........................

17

Why the abstraction

................................
................................
................................
................................
................................
.....

17

How to create a simple command

................................
................................
................................
................................
................

17

Configure a programmatically created command

................................
................................
................................
........................

17

Changing the command to a visual component

................................
................................
................................
...........................

17

Command internationalization and images

................................
................................
................................
................................
..

18

Grouping commands

................................
................................
................................
................................
................................
.....

18

Building a command group in a Spring context

................................
................................
................................
............................

18

Getting a Spring configured command in code

................................
................................
................................
............................

19

Views

................................
................................
................................
................................
................................
................................
.

20

What is a view

................................
................................
................................
................................
................................
...............

20

View descriptors

................................
................................
................................
................................
................................
...........

20

Creating views

................................
................................
................................
................................
................................
...............

20


3

Creating a view descriptor for a view

................................
................................
................................
................................
...........

21

Showing the view in the application

................................
................................
................................
................................
.............

21

Binding and forms

................................
................................
................................
................................
................................
.............

22

Formmodels and valuemodels

................................
................................
................................
................................
......................

22

What is a valuemodel

................................
................................
................................
................................
...............................

22

What is a formmodel

................................
................................
................................
................................
................................

22

The default formmodel

................................
................................
................................
................................
.............................

22

Buffering

................................
................................
................................
................................
................................
...................

22

Read
-
only manipulation

................................
................................
................................
................................
............................

23

Validation

................................
................................
................................
................................
................................
..................

23

Creating formmodels

................................
................................
................................
................................
................................

23

Binding

................................
................................
................................
................................
................................
..........................

24

What is binding

................................
................................
................................
................................
................................
.........

24

How does binding work and what does it do

................................
................................
................................
...........................

24

Binders

................................
................................
................................
................................
................................
......................

24

Binder examples
................................
................................
................................
................................
................................
........

24

Creating your ow
n binder

................................
................................
................................
................................
.........................

24

Forms

................................
................................
................................
................................
................................
............................

26

What is a form
................................
................................
................................
................................
................................
...........

26

Creating a form

................................
................................
................................
................................
................................
.........

26

Form builders

................................
................................
................................
................................
................................
............

28

Binder selection

................................
................................
................................
................................
................................
........

28

Internationalization
................................
................................
................................
................................
................................
...

29

Adding forms to forms, aka child forms

................................
................................
................................
................................
....

29

Form validation

................................
................................
................................
................................
................................
.........

29

Form component interceptors

................................
................................
................................
................................
......................

30

Intr
oduction

................................
................................
................................
................................
................................
..............

30

Creating your own interceptor

................................
................................
................................
................................
.................

30

Configuration

................................
................................
................................
................................
................................
............

30

Built
-
in interceptors

................................
................................
................................
................................
................................
..

3
1

Validation

................................
................................
................................
................................
................................
..........................

34

Why validation

................................
................................
................................
................................
................................
..............

34


4

Validation choices

................................
................................
................................
................................
................................
.........

34

Rule validation

................................
................................
................................
................................
................................
..............

34

Using the rule framework

................................
................................
................................
................................
.........................

34

Constraints

................................
................................
................................
................................
................................
................

34

Validation triggers

................................
................................
................................
................................
................................
.....

35

Dependent properties

................................
................................
................................
................................
...............................

35

Hibernate validator integration

................................
................................
................................
................................
....................

35

Valang validation framework integration

................................
................................
................................
................................
.....

35

integrating your own validation framework

................................
................................
................................
................................
.

35

Exception handling

................................
................................
................................
................................
................................
............

36

Avoiding try
-
catch constructs

................................
................................
................................
................................
.......................

36

Registering an exception handler

................................
................................
................................
................................
.................

36

Build
-
in exception handlers

................................
................................
................................
................................
..........................

37

Log silently

................................
................................
................................
................................
................................
................

37

Show a message dialog

................................
................................
................................
................................
.............................

37

Hibernate validation exception handling

................................
................................
................................
................................
..

38

Custom exception handlers

................................
................................
................................
................................
......................

38

Using the right exception
handler for the right exception

................................
................................
................................
...........

38

Simple delegation

................................
................................
................................
................................
................................
.....

39

Unwrapping exceptions

................................
................................
................................
................................
............................

39

Security

................................
................................
................................
................................
................................
.............................

41

Integrating security in a GUI application
................................
................................
................................
................................
.......

41

Spring Security integration

................................
................................
................................
................................
...........................

41

Turn
ing on security awareness of the GUI

................................
................................
................................
................................
....

41

Securing commands

................................
................................
................................
................................
................................
......

42

Wizards

................................
................................
................................
................................
................................
.............................

43

Why use wizards

................................
................................
................................
................................
................................
...........

43

Creating a wizard

................................
................................
................................
................................
................................
..........

43

Showing a wiza
rd

................................
................................
................................
................................
................................
..........

43





5

I
NTRODUCTION

O
VERVIEW

Rich clients are becoming increasingly more popular nowadays. A quick search through Google on “rich client framework java”
return over 200.000 results.

These frameworks can be divided into 2 distinct categories:


The Swing or SWT based frameworks, design
ed for out
-
of
-
browser applications
, to be used with technologies like Java
Webstart.


The Rich Internet Application (RIA) frameworks, designed for providing
a rich client experience within the confines of a
web browser (such as Mozilla or Internet Explorer)
.

Today, RIA frameworks make up the bulk of the rich client frameworks on the market today. Among these you’ll find names like
Flex, Google Web Toolkit, Ice Faces, … Their popularity is mainly caused by the ease of deployment: no installation is needed
,
al
most every user already has a Web browser.

For Swing (or SWT) based application, the landscape is a bit different. There are only a handful of complete frameworks on th
e
market:


Eclipse RCP, the platform on which the Eclipse IDE has been built


Netbeans RCP
, the platform on which the Netbeans IDE has been built

These frameworks are complete platforms, which have proven themselves through their respective IDE’s to showcase their
possibilities.

However, these possibilities come at a steep cost. With Eclipse R
CP, for example, you’ll be straying of the known Swing path and
enter the world of SWT, and both don’t play well together. With Netbeans RCP, you’re mostly confined to the Netbeans IDE to
do your development (that is, if you want to develop quickly).

Both
platforms can be quite cumbersome and come with a complete baggage package bundled. It’s complexity can be
overwhelming for a standard Swing developer and does not always promote effective, good programming style.

The Spring Rich Client framework does not
promote itself as a complete platform. Instead, it provides developer a clear and easy
way to build enterprise
-
class application
s
, without straying too far from the standard, well
-
known path, whilst ensuring enough
flexibility to cope with the difficult is
sues coupled to the development of enterprise applications.
Built on the strong foundations
of the Spring Framework, it combines the best practices advocated by the Spring Framework with an component
-
based
abstraction on top of Swing to ease development of

Swing rich client application
s
.

This introduction will try to cover as much ground as possible to let you hit the ground running when starting with a Spring
Rich
Client application.

GETTING
OUR

HANDS DIRTY

We’ll start off the introduction with a concise e
xample of a Spring Rich Client application.

As with all Spring applications, Spring beans need to be configured within the container. Currently in Spring Rich Client, on
ly XML
based configuration has been tested, although with the new Spring 2.5 release an
d it’s component
-
scanning abilities, it should
be possible to narrow your configuration down to the essentials. This is something that will possibly be improved in future
releases.

<?xml version="1.0" encoding="UTF
-
8"?>

<beans xmlns="http://www.springframe
work.org/schema/beans"


xmlns:xsi="http://www.w3.org/2001/XMLSchema
-
instance"


xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring
-
beans
-
2.0.xsd">




<bean id="application" class="org.spring
framework.richclient.application.Application">


6


<constructor
-
arg index="0" ref="applicationDescriptor" />


<constructor
-
arg index="1" ref="lifecycleAdvisor" />


</bean>



<bean id="lifecycleAdvisor"



class="org.springframework.richclient.samples.simple.app.SimpleLifecycleAdvisor">


<property name="windowCommandBarDefinitions"


value="org/springframework/richclient/samples/simple/ui/commands
-
context.xml" />


<property name="startingPageId" va
lue="initialView" />


<property name="windowCommandManagerBeanName" value="windowCommandManager" />


<property name="menubarBeanName" value="menuBar" />


<property name="toolbarBeanName" value="toolBar" />


</bean>


<bean id="initialView"




class="org.springframework.richclient.application.support.DefaultViewDescriptor">


<property name="viewClass" value="org.springframework.richclient.samples.simple.ui.InitialView" />


<property name="viewProperties">


<map>


<entry key="f
irstMessage" value="firstMessage.text" />


<entry key="descriptionTextPath"


value="org/springframework/richclient/samples/simple/ui/initialViewText.html" />


</map>


</property>


</bean
>



<bean id="serviceLocator"


class="or
g.springframework.richclient.application.ApplicationServicesLocator">


<property name="applicationServices" ref="applicationServices" />


</bean>



<bean id="applicationServices"


class="org.springframework.richclient.application.suppor
t.DefaultApplicationServices" />



<bean id="applicationEventMulticaster"


class="org.springframework.context.event.SimpleApplicationEventMulticaster" />



<bean id="applicationDescriptor"


class="org.springframework.richclient.application.support
.DefaultApplicationDescriptor">


<property name="version" value="1.0" />


</bean>



<bean id="applicationObjectConfigurer" depends
-
on="serviceLocator"


class="org.springframework.richclient.application.config.DefaultApplicationObjectConfigurer">


</bean>



<bean id="lookAndFeelConfigurer"


class="org.springframework.richclient.application.config.JGoodiesLooksConfigurer">


<property name="popupDropShadowEnabled" value="false" />


<property name="theme">


<bean class="com.jgoodies.look
s.plastic.theme.ExperienceBlue" />


</property>


</bean>



<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">


<property name="basenames">


<list>


<value>org.springframework.richclient.sam
ples.simple.ui.messages</value>


<value>org.springframework.richclient.application.messages</value>


</list>


</property>


</bean>



<bean id="imageResourcesFactory" class="org.springframework.context.support.ResourceMapFactoryBean">


<
property name="locations">


<list>



<value>classpath:org/springframework/richclient/image/images.properties</value>



<value>classpath:org/springframework/richclient/samples/simple/ui/images.properties</value>


</list>


<
/property>


</bean>



7


<bean id="imageSource" class="org.springframework.richclient.image.DefaultImageSource">


<constructor
-
arg index="0" ref="imageResourcesFactory" />


<property name="bro
kenImageIndicator"


Value="/org/springframework/richc
lient/images/alert/error_obj.gif" />


</bean>



<bean id="formComponentInterceptorFactory"


class="org.springframework.richclient.form.builder.support.ChainedInterceptorFactory">


<property name="interceptorFactories">


<list>


<bean



class="org.springframework.richclient.form.builder.support.ColorValidationInterceptorFactory">


<property name="errorColor" value="255,245,245" />


</bean>


<bean class="org.springframework.richclient.form.builder.support.Ove
rlayValidationInterceptorFactory" />


<bean class="org.springframework.richclient.text.TextComponentPopupInterceptorFactory" />


<bean class="org.springframework.richclient.list.ComboBoxAutoCompletionInterceptorFactory" />


</list>


<
/property>


</bean>



<bean id="rulesSource"


class="org.springframework.richclient.samples.simple.domain.SimpleValidationRulesSource" />



<bean id="conversionService"


class="org.springframework.richclient.application.DefaultConversionServiceFactoryBean">


<property name="formatterFactory">


<bean class="org.springframework.richclient.samples.simple.ui.SimpleAppFormatterFactory" />


</property>


</bean>

</bea
ns>


This sample is in fact on of the Spring Rich Client samples included in the sources
, some minor adjustments not taken into
account
. When running the simple project, the output will look something like this:






8

THE SPRING RICH C
LIENT FRAMEWORK,
A

QUI
CK DISSECTION

A
NATOMY OF A RICH CLI
ENT APPLICATION

A Swing rich client in its basic form is quite simple:


An application consists of a application windows, which in most cases contains:


The main content pane


One

or more navigational structures, such as a menu bar or a toolbar


A statusbar to show all sorts of messages to the user

These can be augmented with global search fields, help functions or other components that an application might require.

A
PPLICATION WIND
OWS

An application window is the foundation on which every rich client is built. Without an application window, you don’t have a
place to put the components that make up your screens.

In Spring Rich Client, the application window is represented by the Appl
icationWindow class.
The application window builds the
visual window component and shows it to the user.

Application windows are not created individually in Spring Rich Client. A factory pattern, called ApplicationWindowFactory
handles instantiation of an
application window. This way windows are created in a clear and uniform way throughout the
application, without bothering the developer.

In our hands
-
dirty example, you will not find this factory. Spring Rich Client does not need to have a ApplicationWindo
wFactory
defined. If it is not configured, Spring Rich Client will fall back on a default implementation within the framework, consist
ing of a
simple view area

with a menubar, statusbar and toolbar
.

You can, however, define your own application factory. To

do this,
you just need to implement an ApplicationWindowFactory
and define a bean in your application context with your new class. Spring Rich Client will pick up the class and use it inste
ad of
the default implementation.

The above mechanism,
also known
as service location, is widely used throughout Spring Rich Client, to facilitate configuration
for the developers.


Navigation

Content

Status bar


9

You can for example create an application window factory that leaves out the toolbar, but creates a outlook
-
like bar or task
-
pane oriented n
avigation on the left side instead.

V
IEWS

Application windows are containers for views. A view can be seen as an individual window repre
senting a specific state within
the application.

Views are the main view area of your applications and will contain the

bulk of the user interaction, unless you’ve chosen for a
dialog
-
based approach. You can for example have a flow of views representing a process within your application, or a view
containing a table which, when double
-
clicked, shows a detail of the selecte
d item.

In our first example, a view shows a HTML file together with a message from a resource bundle.

Implementing a view is quite simple. When viewing the example view, you’ll see this:

public class InitialView extends AbstractView {



// omitted for br
evity...




/**



* Create the actual UI control for this view. It will be placed into the wi
ndow according to the layout of


*
the page holding this view.



*/


protected JComponent createControl() {



// In this view, we're just going to use
standard Swing to place a



// few controls.




// The location of the text to display has been set as a Resource in the



// property descriptionTextPath. So, use that resource to obtain a URL



// and set that as the page for the text pane.




JTextPane
textPane = new JTextPane();



JScrollPane spDescription = getComponentFactory().createScrollPane(textPane);



try {




textPane.setPage(getDescriptionTextPath().getURL());



}



catch (IOException e) {




throw new RuntimeException("Unable to load descript
ion URL", e);



}




JLabel lblMessage = getComponentFactory().createLabel(getFirstMessage());



lblMessage.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));




JPanel panel = getComponentFactory().createPanel(new BorderLayout());



panel.add(spDescr
iption);



panel.add(lblMessage, BorderLayout.SOUTH);




return panel;


}

}


AbstractView mandates that you implement the createControl method. This method can deliver any JComponent to show its
contents. In most cases,

this will be some sort of container or panel.

C
OMMANDS

The entire menu bar system (and derived navigational structures) are command based. In essence, this means you’ll never make
a JMenu or JMenuItem manually again. Ever.
Simply put, you’ll create a comm
and, which contains code that needs to be
executed (for example, change a view or print the current selected item). Spring Rich Client will handle the creation of the
visual
components and couple the command behavior to the visual component’s behavior.


10

In

Spring Rich Client, the command context is a separate context that needs to be defined in the main application context
lifecycle.

In our example, the command context looks like this:

<?xml version="1.0" encoding="UTF
-
8"?>

<beans xmlns="http://www.springfr
amework.org/schema/beans"


xmlns:xsi="http://www.w3.org/2001/XMLSchema
-
instance"


xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring
-
beans
-
2.0.xsd">



<bean id="windowCommandManager"


cl
ass="org.springframework.richclient.application.support.ApplicationWindowCommandManager">


</bean>



<bean id="menuBar" class="org.springframework.richclient.command.CommandGroupFactoryBean">


<property name="members">


<list>


<ref bean="
fileMenu" />


<ref bean="windowMenu" />


<ref bean="helpMenu" />


</list>


</property>


</bean>



<bean id="toolBar" class="org.springframework.richclient.command.CommandGroupFactoryBean">


<property name="members">


<list
/
>



</property>


</bean>



<bean id="fileMenu" class="org.springframework.richclient.command.CommandGroupFactoryBean">


<property name="members">


<list>


<bean class="org.springframework.richclient.command.support.ExitCommand" />



</list>


</property>


</bean>



<bean id="windowMenu" class="org.springframework.richclient.command.CommandGroupFactoryBean">


<property name="members">


<list>


<bean class="org.springframework.richclient.command.support.NewWindowCo
mmand" />


<value>separator</value>


<bean class="org.springframework.richclient.command.support.ShowViewMenu" />


</list>


</property>


</bean>



<bean id="helpMenu" class="org.springframework.richclient.command.CommandGroupFactory
Bean">


<property name="members">


<list>


<ref bean="helpContentsCommand" />


<value>separator</value>


<ref bean="aboutCommand" />


</list>


</property>


</bean>



<
bean id="helpContentsCommand" class="org.springframework.richclient.command.support.HelpContentsCommand">


<property name="helpSetPath" value="help/simple.hs" />


</bean>



<bean id="aboutCommand" class="org.springframework.richclient.command.support.
AboutCommand" />

</beans>


As you can see, no S
wing
-
like components are being used to create the menu.


11



M
ESSAGES AND ICONS

Internationalizing your application can be quite an important part of your work, and sometimes also one of the most time
-
consuming
too.

Spring Rich Client supports internationalization through resource bundles defined in the application context (see the
messageSource bean). For example, Spring Rich Client provides a mechanism to set the title of your application through the
applicati
on descriptor. If you set the key applicationDescriptor.title to some value, that value will show up as the title of your
application.

Messages are found through MessageSource implementation, for which the resource bundle implementation is perhaps the
most

widely used.

The same is true for application icons and images in general. The key applicationDescriptor.icon sets the application’s icon.

Like
messages, the images are found through a ImageSource, which contains property files with the keys and the image
s that go with
the keys, and the location where the images can be found (in the jar for example, or somewhere else).

O
THER COMPONENTS

Spring Rich Client also contains other components to make rich client programming easier. A form framework that handles e
asy
form creation, undo functionality and validation. Exception handling to show visually attractive messages when your applicati
on
goes down the drain.
A wizard framework to make data input for the not
-
so
-
tech
-
savvy users simpler and much more.

We’ll disc
uss these into detail later.




12

A
PPLICATIONS

A
PPLICATION
LIFECYCLE

The lifecycle in a Spring Rich Client application is what it says it is. It’s the behavior of the application through the tim
e when it is
running. What the application should do at startup,

what it needs to show, how it should behave when it’s being closed… these
are all aspects of the application lifecycle.

In Spring Rich Client, an ApplicationLifecycleAdvisor

manages the lifecycle of the application. In our example, the lifecycle
advisor handles the creation of the command context, what view should be showed initially, what command bean should be
used for the menu, etc…

H
OOKING INTO A LIFECY
CLE

In the applicat
ion lifecycle you can intervene on points within sta
rtup, shutdown or other events such as opening a window.
These hooks are present in the ApplicationLifecycleAdvisor and can for example be used to ask data needed before startup.


You could also stop an a
pplication from exiting (by asking a confirmation for example).

A
PPLICATION

An application in Spring Rich Client is comprised of 2 things: a lifecycle advisor (how it should behave) and a descriptor (w
hat it
should do).

The Application class is also the cl
ass that starts the actual application: it calls the startup hooks, and shows the initial window
and view.

EXAMPLE: A
DDING LOGIN FUNCTION
ALITY TO THE APPLICA
TION

Logging into an application is quite common behavior. You’ll probably want to show the login
dialog before showing your
application window (you might want to personalize the application window based on who has logged in).

In Spring Rich Client, this means after the commands have been created (which is one step before the window gets created and
sh
owed). In this example, we’ll let a imaginary LoginHandler class check whether we can login or not. For the record, basic lo
gin
functionality has been included into Spring Rich Client,
but this would bring us out of scope for this example. We’ll discuss t
he
security features later.

Assuming our handler will show a login screen and handle the login logic, we only need to hook it into the application lifecy
cle
advisor:

public class LoginLifecycleAdvisor extends DefaultApplicationLifecycleAdvisor

{


privat
e LoginHandler handler;



public void setHandler(final LoginHandler handler)


{


this.handler = handler;


}



public void onCommandsCreated(final ApplicationWindow window)


{


super.onCommandsCreated(window);


handler.do
Login();


}

}



13

As you can see, this is quite easy. Off course you’d want to know when a user is already logged in and just creates a new
application window (which also triggers this method), so it doesn’t show this login window again, something like
holding a
security context within your application.

O
THER POSSIBLE USES

Lifecycle advisor subclassing can also be handy in other aspects. Any Spring Rich Client application knows which lifecycle ad
visor
is used for its execution. You can ask this by callin
g

Application.instance().getLifecycleAdvisor()

You could for example create an application window factory that delivers different application window applications based on
which lifecycle advisor was used:

public class DefaultApplicationWindowFactory imple
ments ApplicationWindowFactory

{


private static final Log logger = LogFactory.getLog(DefaultApplicationWindowFactory.class);



public ApplicationWindow createApplicationWindow()


{


ApplicationLifecycleAdvisor lifecycleAdvisor = Applicatio
n.instance().getLifecycleAdvisor();


if (lifecycleAdvisor instanceof OutlookNavigatorApplicationLifecycleAdvisor)


{


return OutlookNavigatorApplicationWindowFactory.create();


}


else if (lifecycleAdvisor instanceof

TaskPaneNavigatorApplicationLifecycleAdvisor)


{


return TaskPaneNavigatorApplicationWindowFactory.create();


}


return new DefaultApplicationWindow();


}



static class TaskPaneNavigatorApplicationWindowFactory


{


public static ApplicationWindow create(boolean onlyOneExpanded)


{


...


}


}



static class OutlookNavigatorApplicationWindowFactory


{


public static ApplicationWindow create()


{


...


}


}

}

PLAYING WITH THE STA
TUSBAR

Changing the status
bar can be done by calling the statusbar through the lifecycle advisor:

Application.instance().getLifecycleAdvisor().getStatusBar();

Again, if you’re creating your own lifecycle advisor, you’re able to override this method and perhaps supply your own status
bar
implementation.

The standard status bar supports:


Displaying messages, normal messages as well as errors


Containing a progress

monitor to track long
-
running processing (and cancelling them)

Your status bar may hold a clock, the current logged in user, the connected server, …


14

ELABORATE EXAMPLE: A
DDING MULTIPLE TOOLB
ARS TO THE SCREEN

In this example we’ll add multiple toolbar suppo
rt in Spring Rich Client.

Management of the

standard

toolbar is done in three places:


The application lifecycle advisor manages the bean name of the toolbar


The application window puts the actual toolbar on screen


The application window configurer

manages the visibility of the toolbar

For this example, I’ll create the first two (and an factory for the application window).

First, we’re going to extends the default lifecycle advisor with the ability to enter multiple toolbars, while maintaining ba
ckw
ards
compatibility.

public class CustomApplicationLifecycleAdvisor extends DefaultApplicationLifecycleAdvisor

{


private List toolBarBeanNames;



public void setToolBarBeanNames(List toolBarBeanNames)


{


this.toolBarBeanNames = toolBarBean
Names;


}



public void setToolbarBeanName(String toolbarBeanName)


{


toolBarBeanNames = new ArrayList();


toolBarBeanNames.add(toolbarBeanName);


}



public CommandGroup[] getToolBarCommandGroups()


{


if(toolBarBea
nNames == null || toolBarBeanNames.size() == 0)


{


return new CommandGroup[] { new CommandGroup() };


}


else


{


CommandGroup[] groups = new CommandGroup[toolBarBeanNames.size()];


for (int i = 0; i < toolBarBeanNames.size(); i++)


{


groups[i] = getCommandGroup(toolBarBeanNames.get(i).toString());


}


return groups;


}


}

}

Next, we’re going to create an applicati
on window that is able to show the multiple toolbars

public class MultipleToolbarApplicationWindow extends DefaultApplicationWindow

{


private CommandGroup[] toolBarCommandGroups;



protected void init()


{


super.init();


if(getAdvisor() instanceof CustomApplicationLifecycleAdvisor)


{


this.toolBarCommandGroups = ((CustomApplicationLifecycleAdvisor) getAdvisor()).getToolBarCommandGroups();


}


else


{


this.toolBarC
ommandGroups = new CommandGroup[] {getAdvisor().getToolBarCommandGroup()};


}


}


protected JComponent createToolBarControl() {


15


JPanel panel = new JPanel();


panel.setLayout(new GridLayout(toolBarCommandGroups.length, 1));



for (int i = 0; i < toolBarCommandGroups.length; i++)


{


CommandGroup toolBarCommandGroup = toolBarCommandGroups[i];


JComponent toolBar = toolBarCommandGroup.createToolBar();


toolBarCommandGroup.setVisible( getWind
owConfigurer().getShowToolBar() );


panel.add(toolBar);



}


return panel;


}

}
Finally, a factory to create the new application window

public class MultipleToolbarApplicationWindowFactory implements ApplicationWindowFactory

{


public ApplicationWindow createApplicationWindow()


{


return new MultipleToolba
rApplicationWindow();


}

}

Now, to configure the multiple toolbars, here are the beans you need to configure. First the application lifecycle in the mai
n
application context


<
bean id="lifecycleAdvisor" class="org.springframework.richclient.test.CustomApplicationLifecycleAdvisor">


<property name="windowCommandBarDefinitions" value="ui/commands
-
context.xml" />


<property name="startingPageId" value="initialView" />


<pr
operty name="windowCommandManagerBeanName" value="windowCommandManager" />


<property name="menubarBeanName" value="menuBar" />


<property name="toolBarBeanNames">


<list>


<value>toolBar</value>


<value>toolBarCopy</value>


<
/list>


</property>


</bean>

Y
ou
also need to define the application window factory in your context, so it

ll use that one.

<bean id="app
WindowFactory"
c
lass="org.springframework.richclient.test.MultipleToolbarApplicationWindowFactory"/>

And then the toolbars in the command context


<bean id="toolBar" class="org.springframework.richclient.command.CommandGroupFactoryBean">


<property name="members">


<list>


<value>newCommand</value>


<value>saveCommand</value>


<value>printCommand</value>


<value>separator</value>


<value>propertiesCommand</value>


</list>


</property>


</bean>



<bean id="toolBarCopy" class="org.springframework.richclient.command.Command
GroupFactoryBean">


<property name="members">


<list>


<value>newCommand</value>


<value>saveCommand</value>


<value>printCommand</value>


<value>separator</value>


<value>propertiesCommand</value>


</list>


</property>


</bean>


16

That’s all there is to it. I’ve started from a project created with the maven archetype, so
you can try it out if you want. The result
will be something like this




17

C
OMMANDS

W
HY THE ABSTRACTION

Creating an abstraction over an act
ion
-
based operation is quite logical when you think about it. You have behavior, which can be
visually represented in different ways in Swing: a menu, a button or even just a clickable label.

Managing this behavior can be cumbersome if you need to maintain

it, especially when certain behavior is to be represented
many times and in different ways.

H
OW TO CREATE A SIMPL
E COMMAND

Let’s make a simple command that shows a messagebox when executed:

public class MessageBoxCommand extends ActionCommand

{


protec
ted void doExecuteCommand()


{


JOptionPane.showMessageDialog(Application.instance().getActiveWindow().getControl(), "Hello world!");


}

}

Creating a new command can be done by extending ActionCommand. This class mandates that you implement th
e
doExecuteCommand method, which represents the behavior of the command.

CONFIGURE A PROGRAMM
ATICALLY CREATED COM
MAND

Programmatically created commands need to be configured, since Spring Rich Client heavily relies on the Spring container to d
o
the
configuring. So when you create command objects in code, you’ll have to do the configuring yourself.

This can be done by calling the command configurer through the service locator in Spring Rich Client:

MessageBoxCommand command = new MessageBoxCommand();

commandConfigurer = (CommandConfigurer) ApplicationServicesLocator.services().getService(


CommandConfigurer.class);

commandConfigurer.configure(command);

After the command has been configured, it can be used to create components.


C
HANG
ING THE COMMAND TO A

VISUAL COMPONENT

After a command is configured, it can be used to create visual components. These can be:


Menu items


Buttons

Creating a visual component from a command is easy. Every command has methods to create visual components, wit
h the
command’s behavior coupled to it.

For buttons this is

command.createButton(...);

For menu items this is

command.createMenuItem(...);

Both methods have various parameter configurations, for more information on which to use in your scenario I refer to
the
JavaDoc documentation.


18


C
OMMAND INTERNATIONAL
IZATION AND IMAGES

A button needs a
text label
, perhaps an icon. We’ll now show you how you can put messages on your commands and link icons
to them.

When configuring a command, Spring Rich Client sets a “fa
ce descriptor” on the command. This face descriptor manages how
the command looks like. A face descriptor is put on the command by utilizing the id of the command.
In a Spring configured
command, this is the id of the Spring bean. Programmatically created
commands need to set their command ids themselves. If
you don’t set the command’s id, Spring Rich Client will fallback to the camel
-
cased class name of the command class. In our
example, this will be the case, as we haven’t set the id.

The label of the com
mand, and other text related messages for that matter, is found in the message source configured for the
Spring Rich Client application. To find the label of a command, Spring Rich client searches for:

[face descriptor id].label = The label of the comman
d

Similarly, you can put a caption on a command. In the case of a JButton, this will translate itself into a tooltip message:

[face descriptor id].caption = The caption of the command

Commands can also have icons coupled to them. Spring Rich Client will
look for the message keys and images in the image
source configured for the application. To find the icon for a command, Spring Rich client will search for:

[face descriptor id].icon = some_icon.png

G
ROUPING COMMANDS

Commands can also be groups. Command gr
oups in Spring Rich Clients are composite commands. They can be used to create
menus, button stacks and other aggregate components.

Command groups behave similarly to commands (command groups are subclasses of commands), so the configuration works in
the s
ame way. They can also be configured in the Spring context, as well as programmatically. However, in the latter case, the
same rules as commands apply.

Adding commands to a command group is easy, just call the add method.

Creating a visual component of a
command group works the same way as commands. Spring Rich Client provides functionality
for:


Menus


Vertical button stacks


Horizontal button
bars


Toolbars


Popup menus

See the JavaDoc documentation for more information on the usage of these creation methods.

With some effort, you can even
make trees, taskpanes or outlook
-
bar style grouping.

B
UILDING A COMMAND GR
OUP IN A
S
PRING CONTEXT

Given our hands
-
dirty example, we’ll look at a command group configured there:

<bean id="windowMenu" class="org.springframewor
k.richclient.command.CommandGroupFactoryBean">


<property name="members">


<list>


<bean class="org.springframework.richclient.command.support.NewWindowCommand" />


<value>separator</value>


19


<bean class="org.springframework.ric
hclient.command.support.ShowViewMenu" />


</list>


</property>


</bean>


As you can see, creating a command group is straightforward. You create a command group through a factory bean and set the
members.

You may have noticed the “separator” value

in the members. Spring Rich Client has facilitated adding separators to menus and
toolbars by adding this as a shortcut.

Other shortcuts that can be used as values are:


glue

Add a glue between commands


command:xyz

Add a command with id xyz to the group. Y
ou could use this instead of bean references


group:abc

Add a command group with id abc to the group. You could use
this instead of bean references

Not only commands or shortcuts can be added. Also just ordinary JComponent can be added to command groups. Th
is way you
can easily add a textfield to a toolbar.

These command groups can then be referenced for example in the lifecycle advisor to be used as the application’s menu bar,
tool bar or other navigation you might have implemented.

G
ETTING A SPRING CONF
IGU
RED COMMAND IN CODE

Getting a command that you have configured in a Spring context can be done by searching for it based on its id:

Application.instance().getActiveWindow().getCommandManager().getCommand(commandId);

This will return the command

if it can find a command with that id, or null otherwise. You don’t need to configure this command
after you’ve found it, Spring Rich Client has already handled this for you.




20

VIEWS

WHAT IS A VIEW

A view is a visual representation of concepts within your

application. Everything you show in the main application window is
contained within a view.

There can be multiple views on an application page, but only one view is visible at a time. View instances encapsulate the
creation of and access to the visual pre
sentation of the underlying control. A view's descriptor, which is effectively a singleton,
can be asked to instantiate new instances of a single view for display within an application with multiple windows. In other
words, a single view instance is never
shared between windows.

VIEW DESCRIPTORS

Every view has a view descriptor. It’s metadata about a view; a view descriptor is effectively a singleton view definition. A

descriptor also acts as a factory which produces new instances of a given view when reque
sted, typically by a requesting
application page. A view descriptor can also produce a command which launches a view for display on the page within the
current active window.

View descriptors produce the page components (in this case views) that will be sh
own to the users.

CREATING VIEWS


Creating a new view is done through subclassing the AbstractView class. This class mandates you to implement one method:
createControl. In our example, the initial view class looks like this:

public class InitialView extends AbstractView

{


// omitted for brevity



protected JComponent createControl()


{



// In this view, we're just going to use standard Swing to place a



// few controls.




// The location of the text to disp
lay has been set as a Resource in the



// property descriptionTextPath. So, use that resource to obtain a URL



// and set that as the page for the text pane.




JTextPane textPane = new JTextPane();



JScrollPane spDescription = getComponentFactory().cre
ateScrollPane(textPane);



try {




textPane.setPage(getDescriptionTextPath().getURL());



}



catch (IOException e) {




throw new RuntimeException("Unable to load description URL", e);



}




JLabel lblMessage = getComponentFactory().createLabel(getFirst
Message());



lblMessage.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));




JPanel panel = getComponentFactory().createPanel(new BorderLayout());



panel.add(spDescription);



panel.add(lblMessage, BorderLayout.SOUTH);




return panel;


}

}




21

CREATING A VIEW DESC
RIPTOR FOR A VIEW

To show a view on screen, you need to create a view descriptor. For the initial view in the example, the following view
descriptor was used:


<bean id="initialView" class="org.springframework.richclient.application.s
upport.DefaultViewDescriptor">


<property name="viewClass" value="org.springframework.richclient.samples.simple.ui.InitialView" />


<property name="viewProperties">


<map>


<entry key="firstMessage" value="firstMessage.text" />


<e
ntry key="descriptionTextPath"


value="org/springframework/richclient/samples/simple/ui/initialViewText.html" />


</map>


</property>


</bean>

This is the standard view descriptor definition. You need to give the view class to be used to
show the component. Additionally,
you can set the properties on an instance of that view by populating the viewProperties map. These properties have to
correspond to standard JavaBeans property setters. In this case, the view class has a setFirstMessage an
d a
setDescriptionTextPath method.

SHOWING THE VIEW IN
THE APPLICATION

Setting the current view is done by using a ShowViewCommand. This command sets the view of the application window in

which
the command is located.

To create such a command, use the foll
owing bean definition:


<bean id="
initialCommand
" class="
org.springframework.richclient.command.support.ShowViewCommand
">


<property name="
viewDescriptor
"
ref=”initialView”

/>


</bean>

You can now use this command in your menu, or create a button in a
nother view to switch to the defined view.






22

BINDING AND FORMS

FORMMODELS AND VALUE
MODELS

WHAT IS A VALUEMODEL

A valuemodel

provides a way for listening for changes on a property. In its simplest form, it is a property listener wrapper
around a particular property. Its purpose is to track change, so that secondary functionality such as undo functionality and
validation can be
provided.

WHAT IS A FORMMODEL

A formmodel is a wrapper around a particular instance of an object. In essence, it is a consisting of valuemodel
s

for the various
properties of an object. It handles the overall state of the object.

THE DEFAULT FORMMODE
L

The d
efault formmodel in Spring Rich Client handles more than just the overall state of the object by managing its valueobject. It

also provides :


Buffering of values
, effectively providing undo functionality


Dirty tracking


Validation possibilities through vali
dators


Set certain properties of an object to read
-
only, even if they have setters

Creating a formmodel of any given object can be done through this:

MyObject object = new MyObject();

ValidatingFormModel model = new DefaultFormModel(object);

From then on,
you can set the values of the object through the valueobject.

model.getValueModel(“someProperty”).setValue(“xyz”)

Valuemodels in formmodels are created on
-
demand. After creating a formmodel on an object, no valuemodels are present until
you start calling f
or them. Spring Rich Client will then make these on
-
demand.

BUFFERING

Buffering provides the necessary plumbing needed for undo functionality. When changing values of property, a buffered
valuemodel will still hold the old values and can revert to these if

necessary.

MyObject object = new MyObject();

object.setXyz(“xyz”);

ValidatingFormModel model = new DefaultFormModel(object);

model.getValueModel(“xyz”).setValue(“abc”);

// object hasn’t changed, object.getXyz() will return xyz

model.commit();

// object
has changed, object.getXyz() will return abc

Calling revert() before a commit on a formmodel will return all properties to their original values. Individual valuemodel
s

can be
reverted too by calling revert() on them.




23

READ
-
ONLY MANIPULATION

An entire for
mmodel can be s
et to be read
-
only by using the setReadOnly(…) method.

Setting individual properties read
-
only is a little bit more complicated. Out of the box, Spring Rich Client will inspect the object
and determine whether a property is read
-
only, based
on the existence of a setter method for that property.

However, there might be cases where you’d want to deliberately change the read
-
only behavior of a property, even if it has a
setter. The fact whether a property is set as read
-
only is held by field met
adata.

For any given property you can ask the formmodel for the field metadata by calling

FieldMetaData meta = model.getFieldMetaData(“xyz”);

Through this field metadata, you can set the read
-
only property of a property

meta.setReadOnly(true);

Obviously, t
rying to set a property that has no setter to writable will cause an exception when the valuemodels are
committed

(and the respective setters are called).

VALIDATION

The default form model also contains functionality for validating the enclosed values. The

validation is done through Spring Rich
Client’s own validation subsystem by utilizing validators. We’ll discuss the details of these validators in detail later.

When a property is changed, the validator will be called to check whether the object is still
in a consistent state. If not, the
validator will produce validation errors, which then can be showed to the user through various means.

Setting a validator on a formmodel is done through

model.setValidator(someValidator)

After that, the validation is auto
matically turned on. If you needed to, you could turn it off by calling

model.setValidating(false)

A model can be validated at any time. A model is aware whether has validation errors, and if so, contains a collection of the
se.

For more information on this, I refer to the JavaDocs on ValidatingFormModel and DefaultFormModel

CREATING FORMMODELS

To create a formmodel, Spring Rich Client has provided a factory class that can create various formmodels. This class is call
ed
FormModelH
elper.

For example, if you want to create a formmodel of an object, the simplest way would be:

FormModelHelper.createFormModel(new SomeObject(), “formModelId”);

With the FormModelHelper, you can create:


Default formmodels (with validation and buffering)


Un
buffered
formmodels


Child
formmodels
of existing
formmodels

Formmodels, at this time, are object based. To create a formmodel, you need to be able to create an object of the class to be

utilized by the formmodel.


24

There are implementations on the way to mak
e these class
-
based, but these are still in development and shaky at best at the
moment.

BINDING

WHAT IS BINDING

Binding in Spring Rich Client encompasses the connection between a visual component and the state of a certain property.

HOW DOES BINDING WOR
K

AND WHAT DOES IT DO

Binding is done through a valuemodel. A binding covers only one property at a time, most of the time (a binding could be done

by aggregating different valuemodels
, but that’s way out of scope for this introduction
).

A binding will tran
sfer all property changes to the object behind it, and vice versa. It’s bound to a particular formmodel and
property (and therefore, a valuemodel), and is
responsible

for creating the visual component

BINDERS

Binders a factories for bindings. Generally, f
or each sort of binding you’ll use in your application, you’ll have one (or more, if
there are specific variants of certain bindings that may be occurring).

BINDER EXAMPLES

In Spring Rich Client, a number of binders have been implemented out of the box.


T
extComponentBinder: can handle text
-
type variables like strings


CheckBoxBinder: can handle Boolean
-
type variables


ListBinder: can handle lists


And many more…

For Java 5+ there is even a binder available for enums, which visually is represented by a
combobox.

CREATING YOUR OWN BI
NDER

Say we want to create a binder for JodaTime’s classes. Java’s standard date classes are bad to work with, so this example may

even be somewhat useful.

We start of by creating a the binder. A binder is able to bind any JCo
mponent to a value, so we’ll use SwingX’s JXDatePicker class
to visually represent the date.

public class JodaTimeDateTimeBinding extends CustomBinding implements PropertyChangeListener

{


private final JXDatePicker datePicker;


private final boolean

readOnly;



private boolean isSettingText = false;



public JodaTimeDateTimeBinding(FormModel model, String path, JXDatePicker datePicker, boolean readOnly)


{


super(model, path, DateTime.class);


this.datePicker = datePicker;



this.readOnly = readOnly;


}



@Override


protected void valueModelChanged(Object newValue)


{


isSettingText = true;


25


setDatePickerValue((DateTime) newValue);


readOnlyChanged();


isSettingText = false;


}



private void setDatePickerValue(DateTime dateTime)


{


if (dateTime == null)


{


datePicker.setDate(null);


}


else


{


datePicker.setDate(dateTime.toDate());


}


}



@Override



protected JComponent doBindControl()


{


setDatePickerValue((DateTime) getValue());


datePicker.getEditor().addPropertyChangeListener("value", this);


return datePicker;


}



public void propertyChange(PropertyChangeEvent ev
t)


{


if (!isSettingText && !isReadOnly())


controlValueChanged(new DateTime(datePicker.getDate()));


}



@Override


protected void readOnlyChanged()


{


datePicker.setEditable(isEnabled() && !this.readOnly &&

!isReadOnly());


}



@Override


protected void enabledChanged()


{


datePicker.setEnabled(isEnabled());


readOnlyChanged();


}

}

As you can see the class does the 2 way binding. This part


@Override


protected void value
ModelChanged(Object newValue)


{


isSettingText = true;


setDatePickerValue((DateTime) newValue);


readOnlyChanged();


isSettingText = false;


}

handles the propagation of changes in the formmodel to the actual component,
whereas the property change listener (which in
this case is the binder itself, handled by


public void propertyChange(PropertyChangeEvent evt)


{


if (!isSettingText && !isReadOnly())


controlValueChanged(new DateTime(datePicker.get
Date()));


}

The isSettingText flag is there to prevent cyclic calls (formmodel changes component, which change the formmodel, which
changes, …).


26

Binding the control to the value

is done through the doBindControl() method. This method is called to
wire

the component
to
the binding
and prepares all the plumbing to make the binding work.

Creating the binder is most of the time the easiest job of the two.

public class JodaTimeDateTimeBinder extends org.springframework.richclient.form.binding.support.Abstra
ctBinder

{


private boolean defaultsSet = false;



private boolean readOnly = false;



public JodaTimeDateTimeBinder()


{


super(DateTime.class);


}



public void setReadOnly(boolean readOnly)


{


this.readOnly = readOnly
;


}



@SuppressWarnings("unchecked")


protected JComponent createControl(Map context)


{


JXDatePicker datePicker = new JXDatePicker();


datePicker.setEditor(new DateTextField());


return datePicker;


}




@SuppressWarnings("unchecked")


protected Binding doBind(JComponent control, FormModel formModel, String formPropertyPath, Map context)


{


if (!defaultsSet)


{


Map<Object, Object> defaults = UIManager.getDefaults();



defaults.put("JXDatePicker.longFormat", "EEE dd/MM/yyyy");


defaults.put("JXDatePicker.mediumFormat", "dd/MM/yyyy");


defaults.put("JXDatePicker.shortFormat", "dd/MM");


defaultsSet

= true;


}


return

new JodaTimeDateTimeBinding(formModel, formPropertyPath, ((JXDatePicker) control), this.readOnly);


}

}

The createControl() method creates the control that is to be used in bindings. Every time a binding is done, a new control wi
ll be
created through t
his method.

The actual binding is done through the doBind(). It will create a binding, do some specific behavior in some case (here we’re

manipulating some UI properties to alter the JXDatePicker’s appearance.

FORMS

Now that we have covered the formmodels
and the binding, we can now cover the combination of the both.

WHAT IS A FORM

Whereas a binding covers a single property, a form covers an entire object. It can contain many bindings, backed up by a
formmodel that wrapped the form’s object.

CREATING A FORM

Forms are created for a specific purpose and specific objects. Say we have the following object:

public class TestObject


27

{


private String field1;


private String field2;



public String getField1()


{


return field1;


}



public void setField1(String field1)


{


this.field1 = field1;


}



public String getField2()


{


return field2;


}



public void setField2(String field2)


{


this.field2 = field2;


}

}

If we want to make a
form for this, we’ll might be using something like this

public class TestForm extends AbstractForm

{


public TestForm()


{


super(FormModelHelper.createFormModel(new TestObject(), "testForm"));


}



protected JComponent createFormControl()


{


JPanel content = new JPanel();


content.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));


content.setLayout(new FormLayout(


new ColumnSpec[]



{


FormFactory.DEFAULT_COLSPEC,


FormFactory.LABEL_COMPONENT_GAP_COLSPEC,


FormFactory.DEFAULT_COLSPEC


},


new RowS
pec[]


{


FormFactory.DEFAULT_ROWSPEC,


FormFactory.LINE_GAP_ROWSPEC,


FormFactory.DEFAULT_ROWSPEC


}


));




TextComponentBinder binder = new TextComponentBinder();



Map map = new HashMap();



content.add(new JLabel("Field 1"), new CellConstraints(1, 1));


content.add(binder.bind(getFormModel(), "field1", map).getControl(), new CellCon
straints(3, 1));


content.add(new JLabel("Field 2"), new CellConstraints(1, 3));


content.add(binder.bind(getFormModel(), "field2", map).getControl(), new CellConstraints(3, 3));



return content;


}

}

This will result in a panel
with 2 text

fields

next to each other
, that represent the 2 fields of the object.

This form can then be
used to show in a view or a dialog.

Currently, there is no default view descriptor for forms, since these are mostly contained in
views in which they on
ly make up a part of the screen (for example, in combination with a table).


28


FORM BUILDERS

As shown in the example above, forms can be created by using binders and bindings directly. However, for more elaborate form,

this method is not really usable (or r
eadable for that matter).

To tackle this problem, Spring Rich Client has created form builders. Form builders make form creation a lot easier by provid
ing
simple addition of properties, labels and other component to forms. Form builders use the binding fac
tory facilities built into
Spring Rich Client.

The binding factory system can set default binders for certain types, so that you don’t need to worry how something should
look. It can also provide aliases for binders defined in the context, so that you can
use these swiftly.

Building the same form with a form builder would result in

public class TestForm extends AbstractForm

{


public TestForm()


{


super(FormModelHelper.createFormModel(new TestObject(), "testForm"));


}



protected JCompo
nent createFormControl()


{


TableFormBuilder builder = new TableFormBuilder(getBindingFactory());


builder.add("field1");


builder.row();


builder.add("field2");


JPanel panel = (JPanel) builder.getForm();


pan
el.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));


return panel;


}

}


Much simpler and easy to read, isn’t it?

An additional advantage in using a form builder is that internationalized labels are supported out of the box. In the
form builder
example no labels are coded, but the form builder w
ill add them automagically.

Currently there is a form builder that works with JGoodies FormLayout named TableFormBuilder, and there is also one that
supports Java’s GridbagLayout. You can alw
ays create your own form builder by extending AbstractFormBuilder.

BINDER SELECTION

Spring Rich Client has a mechanism to automatically choose binders based on property names, types or even the used Swing
components. This is done through BinderSelectionStr
ategy implementations.

The standard implementation is the SwingBinderSelectionStrategy, which already has support for String and Boolean type fields
.

If you want to expand this automatical binder selection, you can configure your own BinderSelectionStrateg
y in your Spring
context (which will be picked up by the service locator),
and set for example the b
indersForPropertyTypes

map property. This
map matches property types to specific binders that you also have configured in your Spring context.

For example,
if you want to change support String, Boolean and Date fields, you can define your selection strategy like this


<bean id="binderSelectionStrategy"


class="
org.springframework.richclient.form.binding.swing.SwingBinderSelectionStrategy
">


<proper
ty name="bindersForPropertyTypes" ref="propertyTypeBinders"/>


</bean>


29



<util:map id="propertyTypeBinders" key
-
type="java.lang.Class">


<entry key="java.lang.String" value
-
ref="stringBinder"/>


<entry key="java.util.Date" value
-
ref="dateBinder"/>


<entry key="java.lang.Boolean" value
-
ref="booleanBinder"/>


</util:map>

I
NTERNATIONALIZATION

Remember the id you can give to your formmodel? This is the part where it’s needed. Spring Rich Client will use the formmodel
’s
is to create the key it’ll use

to look up the label’s text.

Say your formmodel is named “personForm” and you have a field called “firstName”. Then in your message bundle you’ll have
to provide something like this:

personForm.firstName.label = First name

If no value is found for a key,
Spring Rich Client will show the key instead. This way you can easily spot missing keys (and don’t
need to guess how they are named).

ADDING FORMS TO FORM
S, AKA CHILD FORMS

Forms are just plain components. They can be added to forms as any other component.

However, when creating a child form,
you need to make sure the formmodel of the child form is also a child of the formmodel of that form’s parent. That way, event
s
are carried over correctly.

Child forms can also be added by using the addChildForm(…) meth
od on a form. This way, the formmodels between the two are
automatically linked. Bear in mind though, a setFormObject on a parent form does not cause a setFormObject on its children.
This is something you’ll have to handle yourself.

FORM VALIDATION

Form v
alidation is done through the validation subsystem by validating the formmodel (and underlying valuemodels).
Form
component interceptors such as the
OverlayValidationInterceptorFactory

can then show the validation errors to the user. For
more information o
n interceptor, read the next part.



30

FORM COMPONENT INTER
CEPTORS

INTRODUCTION

Form component i
nterceptors provide a way to intercept and add extra functionality to input components on a form.

The application context specifies the list of interceptors to at
tach to controls constructed by the platform. This allows for a
declarative model for specifying "additional" functionality to be added to various components.

Examples are interceptors to overlay validation error images and background color changes, provi
de popup menus in text fields,
and autocompletion (as you type) for comboboxes.

CREATING YOUR OWN IN
TERCEPTOR

To create your own
FormComponentInterceptor
, you have to provide both a
FormComponentInterceptor

and a
FormComponentInterceptorFactory

implementa
tion.


public interface FormComponentInterceptor {


public void processLabel(String propertyName, JComponent label);



public void processComponent(String propertyName, JComponent component);

}

CONFIGURATION

The configuration of the intercep
tors in the application context is done by defining the
FormComponentInterceptorFactory
.

Sample configuration:

<bean id="formComponentInterceptorFactory"


class="org.springframework.richclient.form.builder.support.ChainedInterceptorFactory">



<property name="interceptorFactories">


<list>


<bean
class="org.springframework.richclient.form.builder.support.ColorValidationInterceptorFactory">


<
property name="errorColor" value="255,200,200"/>


</bean>


<bean
class="org.springframework.richclient.form.builder.support.OverlayValidationInterceptorFactory"/>


<bean
class
="org.springframework.richclient.form.builder.support.DirtyIndicatorInterceptorFactory"/>


<bean class="org.springframework.richclient.text.TextComponentPopupInterceptorFactory"/>


<bean
class="org.spri
ngframework.richclient.list.ComboBoxAutoCompletionInterceptorFactory"/>


</list>


</property>


</bean>









31

BUILT
-
IN
INTERCEPTORS

There are a number of built
-
in interceptors provided with the framework.

We’ll quickly expl
ain them.

ERROR OVERLAY IMAGE

Shows an error image in the lower left corner of the component if the contents of the component is invalid. The image also ha
s a
tooltip showing the validation message.



This class has been specifically made to work with Spring Rich Client’s validation framework and will show the errors coming
from that framework

To configure this interceptor, you need to use this interceptor factory:

<bean
class="org.springframework.richclient.form.builder.support.
OverlayValidationInterceptorFactory
"

/
>

ERROR BACKGROUND COL
OR

Changes the background color of the form component

when an invalid value is entered
.

Properties:


errorColor: the background color

To c
onfigure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.ColorValidationInterceptorFactory">


<property name="errorColor" value="255,200,200"/>

</bean>


TEXT EDITING POPUP

(COPY, PASTE, UNDO,.
..)

Adds more advanced text editing functionality to text components. It adds a popup menu with
"undo/redo/cut/copy/paste/select all" items. It also adds the standard keyboard accelerators for these commands to the
component.


To conf
igure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.
TextComponentPopupInterceptorFactory
"

/
>


32

COMBOBOX AUTOCOMPLET
ION

Adds auto

completion to a combobox.


To configure this inte
rceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.
ComboBoxAutoCompletionInterceptorFactory
"

/
>

OVERLAY IMAGE INDICA
TING A CHANGED VALUE

Sho
ws an image in the top left corn
er of the component

if the contents of the component has been changed by the user. The
image also has a tooltip showing the original value. To the right of the image is a small revert button. Pushing this button
restores the original value in the component.



Properties:


includedFormModelIds: list of form models that should display the Dirty Indicator.

Only one of includedFormModelIds or excludedFormModelIds can be specified.


excludedFormModelIds: list of form models that should not display the Dirty Indicator

Only one of
includedFormModelIds or excludedFormModelIds can be specified.

To configure this interceptor, you need to use this interceptor factory:

<!
--

The login form will not show the Dirty Indicator
--
>

<bean class="org.springframework.richclient.form.builder.suppo
rt.DirtyIndicatorInterceptorFactory">


<property name="excludedFormModelIds">


<list>


<value>loginForm</value>


</list>


</property>

</bean>

SELECT ALL TEXT

Selects all the text in text fi
elds and spinners when they receive focus.


To configure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.
SelectAllInterceptorFactory
"

/
>

SETTING THE CARET TO

THE BEGINNING OF THE

FIELD

If the text is set in a text component, the caret position is set to the end of the text.

This means the beginning of the text will not be visible if the text is too long to fit in the text component.

This
FormComponentInterceptor

"fixes" this
behav
ior
, and sets the caret to position 0.


33

To configure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.
TextCaretFormComponentInterceptorFactory
"

/
>

SHOWING A TOOLTIP

If a form property has a caption defined in the messages.properties file it will be used as the tooltip for the form componen
t.

Properties:


processComponent: default is true, determines whether the tooltip of the component is set.


processLabel: default is
true, determines whether the tooltip of the label is set.

To configure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.
ToolTipInterceptorFactory
"

/
>

CHANGING THE RENDERI
NG OF A CH
ECKBOX

Allows customization on how a CheckBox form property is rendered.

Properties:


showLabel: default is true, determines whether the label will be shown.


showText: default is false, determines whether the label text will be used as text for the checkbox

itself.


textKey: default is "text", the key used to fetch the text to show.

To configure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.
CheckBoxFormComponentInterceptorFactory
"

/
>

SHOW THE CAPTION OF
THE
CURRENTLY FOCUSED
COMPONENT IN THE STA
TUSBAR

Shows the caption of the form component in the statusbar when the component is focused.

To configure this interceptor, you need to use this interceptor factory:

<bean class="org.spring
framework.richclient.form.builder.support.
ShowCaptionInStatusBarInterceptorFactory
"

/
>

SHOW THE DESCRIPTION

OF
THE CURRENTLY FOCUSE
D
COMPONENT IN THE STA
TUSBAR

Shows the description of the form component in the statusbar when the component is focused.

To
configure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.
ShowDescriptionInStatusBarInterceptorFactory
"

/
>




34

VALIDATION

WHY VALIDATION

Users make mistakes. They won’t admit it,
but they do. As GUI developers, our task is to make sure that their mistakes don’t
crash or cripple our system. Input validation can help a great deal with this.

Spring Rich Client supports validators for various
input. These are all subclasses of RichVali
dator.

VALIDATION CHOICES

Spring Rich Client has multiple validation strategies:


The built
-
in rules system


Using Hibernate Validator


Using
Spring Modules’

Valang validation framework


A combination of any of the above

RULE VALIDATION

USING THE RULE FRAME
WOR
K

Spring Rich Client has created their own validation framework, which is rule based. A change to a value it put through a numb
er
of checks, which are contained within a rule, and results in a success or a validation error.

The FormModelHelper can create f
ormmodel with rule validation by providing a RulesSource in one of its factory methods.

A rule source contains different rules for a certain object type. If, for example, we want to validate that the field1 proper
ty of the
TestObject class is never empty,
we can create a rulesource like this:

DefaultRulesSource source = new DefaultRulesSource();

Rules rules = new Rules(TestObject.class);

Constraints c = new Constraints();

rules.add(c.required("field1"));

source.addRules(rules);

CONSTRAINTS

Constraints conta
in the actual logic that checks the values.

The Constraints class contains a lot of predefined
constraints
. Among these you can find


Maximum length of string


Maximum value


Not null


Minimum value




Creating your own constraint is done by implementing the
Constraint interface, which consists of one method

public interface Constraint

{


boolean test(Object argument);

}

This
constraint will test any
object. Most of the time, we’ll want to split up functionality to check individual properties, so that
we can
reuse this logic elsewhere.
Remember, the constraints you add to a rules source always need to be coupled to a
property
.


35

For this, you’ll need to subclass AbstractPropertyConstraint, which needs a property name. Also, in it’s test method, it prov
ides
an ea
sy way to get values of individual properties.

Say we want to create a constraint that checks whether a String property’s value equals “RCP” (silly, but a good example). We
’ll
end up with something like this:

public class RcpConstraint extends AbstractProp
ertyConstraint

{


protected boolean test(final PropertyAccessStrategy domainObjectAccessStrategy)


{


Object prop = domainObjectAccessStrategy.getPropertyValue(getPropertyName());


return !(prop instanceof String) || ((String) prop).equ
als("RCP");


}

}

This constraint you can then add to your rulessource for a specific property.

VALIDATION TRIGGERS

Validation on a property is triggered when that property is changed in its valuemodel. Spring Rich Client will search for rul
es for
that p
roperty and execute them.

DEPENDENT PROPERTIES

Some rules that are registered for a certain property need to be triggered when another property is changed (for example two
dates, for which the first needs to be before the last). Spring Rich Client supports this by overriding the isDependentOn(…)
method
. Out
-
of
-
the
-
box, this method returns true if the parameters equals the property name for which the rule is defined.
However, you can add additional properties to this method. Every change in a property that returns true on this method will
cause this rule

to be checked.

HIBERNATE VALIDATOR
INTEGRATION

Hibernate Validator is a well
-
known framework for validating JavaBeans. It’s annotation
-
based, so you won’t find it in the
standard Spring Rich Client, but support is provided in the jdk5 module.

Simply put,
if the object behind a form has Hibernate Validator annotation
s
, by setting the validator to a
HibernateRulesValidator
. This validator will check all property
-
based validations (no @AssertTrue

support at the moment yet).
You can even turn off validation for certain properties (for example, a code is @NotNull, but in the GUI you’re allowed to le
ave it
empty because you’ll generate one on the f
ly when that’s the case
).

VALANG VALIDATION FR
AMEWOR
K INTEGRATION

For more information on the Valang validation framework, see the Valang documentation. Converting the rules source example
to Valang would result in something like this (I’ll show the bean definition):

<bean name="testObjectValidator" class="
org.springmodules.validation.valang.ValangValidator">


<property name="valang">


<value><![CDATA[

{ field1 : (? IS NOT NULL) : 'Field 1 is required' : 'errors.required' : 'Field 1' }

]]>

You can
then make a ValangRichValidator
f
or a certain formmodel with that validator.

INTEGRATING YOUR OWN

VALIDATION FRAMEWORK

If you want to integrate your own validation framework, you’ll need to subclass the RichValidator class and wire your validat
or
to produce validation results.



36

EXCEPTION
HANDLING

AVOIDING TRY
-
CATCH CONSTRUCTS

Most
runtime
exceptions that are thrown are unexpected: we don't expect them to happen (especially during production) such
as:


NullPointerException: Didn't I double checked all my source code to avoid NPE's?


CvsParser
Exception: Why did the user pick a html file when I asked him for a CVS file?


IDidNotKnowThisExistedRuntimeException: What the ...?

And if
you

do

expect

some of them, you us
ually can't really fix the problem, just deal with it:


Log the exception through a
logging framework such as SLF or Log4J.


Notify the user that whatever he tried didn't work, preferably with an not
-
technical, exception
-
specific explanation.


Either shutdown the application or allow the user to continue (and try again).

You could use try
-
c
atch during every user action:

protected boolean onFinish() {


try {


form.getFormModel().commit();


// ...


getApplicationContext().publishEvent(new LifecycleApplicationEvent(eventType, getEditingContact()));


return true;


} c
atch (Throwable throwable) {


handleException(throwable);


}

}

But this is tedious and error prone:


It's easy to forget to try catch some code, which makes the exception escape to the top layer exception handler.


You coul
d unwillingly eat the excep
tion or not log

it:

o

If you handle an exception, but forget to log it and/or show it to the user.

o

If you throw an exception in the catch or finally part, only the last exception bubbles up, effectively hiding the
real exception.

In production, this leads to

discussions where the user is sure he
did perform an action

(which he did in this case) and the
programmer is sure the user didn't because the system didn't report anything and nothing has changed. If you notice that whil
e
yo
u are fixing a issue and

an ex
ception is

being

eaten (making it hard to identify the original issue), create a new issue because
exceptions are eaten and fix that first.


You are in danger to handle the same exception on 2 different layers, effectively logging it or
notifying

the user t
wice.


In some layers or parts of the application, it might not be clear if you need to notify the user (and which user) through a
swing dialog or JSP or
web service

response.

Spring Rich Client’s exception handling system uses the top layer exception handl
ing. It expects that all other layers let the
exception bubble up.

REGISTERING AN EXCEP
TION HANDLER

In the LifecycleAdvisor you can register a RegisterableExceptionHandler:

<bean id="lifecycleAdvisor" class="...LifecycleAdvisor
">


<!
--

...
--
>


<
property name="registerableExceptionHandler" ref="exceptionHandler" />

</bean>


<bean id="exceptionHandler" class="org.springframework.richclient.exceptionhandling.SilentExceptionHandler"/>


37

When an exception handler is registered, it will u
s
ually register itself as the
UncaughtExceptionHandler

on the threads.
However, the event thread catches a throwable thrown in any event, to prevent getting killed, so it also registers itself to
the
event thread specifically (regrettably this is currently

S
un JRE specific

behavior
).

BUILD
-
IN EXCEPTION HANDLER
S

Most of these exception handlers are

part of the spring
-
richclient
-
jdk5

module.

LOG SILENTLY

Logs a throwable but does not notify the user in any way. Normally it is a bad practice not to notify the u
ser if something goes
wrong.

You can set a log level on it:

<bean class="org.springframework.richclient.exceptionhandling.SilentExceptionHandler">


<property name="logLevel" value="WARN"/>


<!
--

...
--
>

</bean>

This means that any exception handled by th
is exception handler will be logged at the warn level.

SHOW A MESSAGE DIALO
G

Shows the exception in a dialog to the user (as well as logging it). You can set a log level and the icon of the dialog depen
ds on
that log level. The shown dialog has a caption (
= dialog title) and description (= dialog content), which are fetched from the i18n
messages files. There are 2 ways to resolve those messages: static or dynamic (default).

You can statically set the title and description by setting the
messagesKey

propert
y. However, it's a lot more powerful to use
the default dynamic behavior based on the class of the exception. For example if a
NumberFormatException

is thrown, it
will first look for these i18n keys:

java.lang.NumberFormatException.caption=Not a number

jav
a.lang.NumberFormatException.description=
\


You did not enter a a valid number.
\
n
\


\
n
\


Please enter a valid number.

If these messages keys don't exist, it will fall back to the parent class of
NumberFormatException
, which is
IllegalArgumentException
:

java.lang.IllegalArgumentException.caption=...

java.lang.IllegalArgumentException.description=...

It will continue to fall back up the chain, untill it reaches
Throwable
. This allows you to direct all unexpected exceptions (for
example
IDidNotKnowThisExist
edRuntimeException
) to a
MessagesDialogExceptionHandler

that logs
them as an error and shows a generic message. You can even use
{0}

in your i18n message to show the
exception.getMessage()

in the description:

# Double quotes(") need to be escaped (
\
"), sin
gle quotes (') always seem to break the replacing of {0}.

java.lang.RuntimeException.caption = Unexpected general bug

java.lang.RuntimeException.description =
\


The application experienced an unexpected bug,
\
n
\


due to a programming error.
\
n
\


\
n
\


Th
e application is possibly in an inconsistent state.
\
n
\


It is recommended to reboot the application.
\
n
\


\
n
\


The exact bug is:
\
n
\


{0}
\
n
\


\
n
\


38


Please report this bug.

java.lang.Error.caption = Unexpected serious system failure

java.lang.Error.descr
iption =
\


A serious system failure occured.
\
n
\


\
n
\


The application is possibly in an inconsistent state.
\
n
\


Reboot the application.
\
n
\


\
n
\


The exact bug is:
\
n
\


{0}
\
n
\


\
n
\


Please report this bug.

Note that, although this dynamic system is pretty
powerful

and avoids a lot of boilerplate, it's usually not a replacement for
DelegatingExceptionHandler
, because it doesn't allow you to assign different log levels, etc.

You can set a shutdown policy on a
dialog exception handler:

<bean class="org.springframework.richclient.exceptionhandling.MessagesDialogExceptionHandler">


<property name="shutdownPolicy" value="ASK" />


<!
--

...
--
>

</bean>

This allows you to optionally enforce or propose a
System.exit(
1)
.

HIBERNATE VALIDATION

EXCEPTION HANDLING

A special exception handler which can only handle an
InvalidStateException

thrown by Hibernate validator. It shows
the failed validations to a user in a list in a dialog. In most cases it's inferior to the
Hibern
ateRulesValidator

which
validates before the user presses the commit button. But because the latter forces you to hand code
@AssertTrue
's and it
could be working on stale client
-
side data, it's actually a very nice backup to also configure this exception h
andler:

<!
--

Inside a delage list of DelegatingExceptionHandler
--
>

<bean class="org.springframework.richclient.exceptionhandling.delegation.SimpleExceptionHandlerDelegate">


<property name="throwableClass">


<value type="java.lang.Class">org.hibernate
.validator.InvalidStateException</value>


</property>


<property name="exceptionHandler">


<bean class="org.springframework.richclient.exceptionhandling.HibernateValidatorDialogExceptionHandler">


<property name="logLevel" value="INFO" />


<
property name="shutdownPolicy" value="NONE" />


</bean>


</property>

</bean>

CUSTOM EXCEPTION HAN
DLERS

You can also extend
AbstractLoggingExceptionHandler

and implement this method:

public void notifyUserAboutException(Thread thread, Throwable
throwable) {


// ...

}

This way, you could for example integrate e
-
mail functionality, heck, even IM functionality to the error notification towards the
user.

USING

THE RIGHT EXCEPTION
HANDLER FOR THE RIGH
T EXCEPTION

There are bunch of build
-
in exception handlers, but
usually

there isn't one exception handler that fits alls exceptions. A
DelegatingExceptionHandler

allows you to delegate an exception to the right exception handler. It accepts a delegate
list and travers
es that list in order. The first delegate that can handle the exception, has to handle the exception and the rest of
the delegate list is ignored.


39

For example, here we configure authentication and authorization exceptions to a
MessagesDialogExceptionHandle
r

with

WARN messages
, Hibernate
exceptions to an INFO
HibernateValidatorDialogExceptionHandler

and the rest
to an ERROR
MessagesDialogExceptionHandler
.


<bean id="exceptionHandler"
class="org.springframework.richclient.exceptionhandling.delegation.Delegat
ingExceptionHandler">


<property name="delegateList">


<list>


<bean class="org.springframework.richclient.exceptionhandling.delegation.SimpleExceptionHandlerDelegate">


<property name="throwableClassList">


<list>



<value type="java.lang.Class">org.acegisecurity.AuthenticationException</value>


<value type="java.lang.Class">org.acegisecurity.AccessDeniedException</value>


</list>


</property>


<property name="exceptio
nHandler">


<bean class="org.springframework.richclient.exceptionhandling.MessagesDialogExceptionHandler">


<property name="logLevel" value="WARN" />


<property name="shutdownPolicy" value="NONE" />


</bean>


</property>


</bean>


<bean class="org.springframework.richclient.exceptionhandling.delegation.SimpleExceptionHandlerDelegate">


<property name="throwableClass">


<value type="java.lang.Class">org.hibernate.valid
ator.InvalidStateException</value>


</property>


<property name="exceptionHandler">


<bean


class="org.springframework.richclient.exceptionhandling.HibernateValidatorDialogExceptionHandler">


<
property name="logLevel" value="INFO" />


<property name="shutdownPolicy" value="NONE" />


</bean>


</property>


</bean>


<!
--

The order is important: if Throwable would be first then the others would be ignor
ed
--
>


<bean


class="org.springframework.richclient.exceptionhandling.delegation.SimpleExceptionHandlerDelegate">


<property name="throwableClass" value="java.lang.Throwable" />


<property name="exceptionHandler">



<bean class="org.springframework.richclient.exceptionhandling.MessagesDialogExceptionHandler">


<property name="logLevel" value="ERROR" />


<property name="shutdownPolicy" value="ASK" />


</bean>


</proper
ty>


</bean>


</list>


</property>


</bean>

SIMPLE DELEGATION

Processes the exception if it is an instance of throwableClass or the throwableClassList.

UNWRAPPING EXCEPTION
S

An exception purger allows you to cream off wrapper exceptions. Th
is allows you to handle a chained exception in the chain of
the uncaught exception, instead of the uncaught exception itself. Almost all exception handlers and delegate's support the us
e
of a purger.
DefaultExceptionPurger

supports 2 ways to identify the d
epth to cream off: include or exclude based.

A chained exception of the type in the
includeThrowableClassList

is stripped from all it's wrapper exceptions and
handled by the exception handler or evaluated by the delegate. For example, we want to handle eve
ry
MySQLIntegrityConstraintViolationException

even if it's wrapped:



40

<bean class="org.springframework.richclient.exceptionhandling.delegation.SimpleExceptionHandlerDelegate">


<property name="exceptionPurger">


<bean class="org.springframework.richcl
ient.exceptionhandling.delegation.DefaultExceptionPurger">


<property name="includeThrowableClassList">


<list>


<value type="java.lang.Class">com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException</value>


</list>


</property>


</bean>


</property>


<property name="throwableClassList">


<list>


<value type="java.lang.Class">com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException</value>


</list>


</proper
ty>


<property name="exceptionHandler">


<!
--

...
--
>


</property>

</bean>

A chained exception of the type in the
excludeThrowableClassList

is stripped together with all it's wrapper exceptions
and it's cause is handled by the exception handler or
evaluated by the delegate. For example the server wraps all exceptions in
an annoying, useless
WrappingServiceCallException

and we want to get rid of it:

<bean id="exceptionHandler"
class="org.springframework.richclient.exceptionhandling.delegation.Delegat
ingExceptionHandler">


<property name="exceptionPurger">


<bean class="org.springframework.richclient.exceptionhandling.delegation.DefaultExceptionPurger">


<property name="excludeThrowableClassList">


<list>


<value type="
java.lang.Class">foo.bar.WrappingServiceCallException</value>


</list>


</property>


</bean>


</property>


<property name="delegateList">


<!
--

...
--
>


</property>

</bean>




41

SECURITY

INTEGRATING SECURITY

IN A GUI APPLICATION

Integrating security into a GUI application can be cumbersome. The reason for this is:


Adding login and logout functionality can take a lot of work


Adjusting screens to handle with security limitations




Spring Rich Client integrates with Spring Security t
o provide a framework to handle security
-
based problems and offers a
solution for these.

SPRING SECURITY INTE
GRATION

Simply integrating login functionality is easy: provide a login command in your commands context and make your lifecycle
advisor runs this

command before showing the screen.

<bean id="loginCommand" class="org.springframework.richclient.security.LoginCommand"/>


public class PetClinicLifecycleAdvisor extends DefaultApplicationLifecycleAdvisor

{


// omitted for brevity




public void o
nCommandsCreated(ApplicationWindow window)


{


ActionCommand command = (ActionCommand) window.getCommandManager().getCommand("loginCommand",


ActionCommand.class);


command.execute();


}

}

The login
command uses service location to find the application security manager. If no security manager is found in the context,
the default implementation will be used.


TURNING ON SECURITY
AWARENESS OF THE GUI

Spring Rich Client has a bean post processor that ca
n enable any class to be notified of security changes. You can define this post
processor as

<bean class=”
org.springframework.richclient.security.SecurityAwareConfigurer
”/>


42

If your classes implement either the AuthenticationAware or LoginAware interface, t
his bean postprocessor will make sure these
get notified of login changes.

SECURING COMMANDS

Securing commands is easy. AbstractCommand

enables you to define a security controller (by its id), which then uses a access
decision manager to decide whether a command is allowed to be executed (by enabling/disabling it).

For example, a secured command bean in the commands context may look like
this:

<bean id="newOwnerCommand" class="org.springframework.richclient.command.TargetableActionCommand">


<property name="commandExecutor" ref="newOwnerWizard" />


<property name=”securityControllerId” value=”mySecurityController”/>

</bean>

This assumes
you have a security controller named mySecurityController defined in your application context, for example

TODO: rest of the text…



43

WIZARDS

WHY USE WIZARDS

Wizards make flow
-
like form entry easy. If you have a flow of screens, with the input of the first s
creen affecting the behavior
and possibly layout of one or more the next screens, wizards are an ideal way to accomplish this.

Spring Rich Client has built
-
in wizard functionality.

CREATING A WIZARD

In Spring Rich Client, a wizard consists of wizard pages
. Every wizard page can determine which page is next or previous and
whether the wizard can stop at this page. Wizards are mostly form
-
based, which means validation is included as well. The wizard
framework will not allow a user to change to another screen

as long as the current is invalid.

Creating a wizard is quite straightforward. You create pages (or even just forms) and add them to a wizard. Creating wizard w
ill
most of the time mean subclassing the AbstractWizard class and building a wizard as a separ
ate component.

public class MyWizard extends AbstractWizard

{


private MyForm form1;


private MyOtherForm form2;




public MyWizard()


{


initializeForms();


addForm(form1);


addForm(form2);


}




protected boolean onFinish()


{


form1.commit();


form2.commit();


doSomeLogic();


}

}

This wizard will make 2 forms and when the wizard completes (the user presses finish), it’ll do some logic.

SHOWING A WIZARD

There are var
ious ways for showing a wizard. Standard, Spring Rich Client provides you with a dialog class that can show a wizard
(which most of the time is the way you’ll show a wizard).

You can off course create a view class for your wizard, so you can display your w
izard as a view too. To implement this, take a
look at WizardDialog.