jump to navigation

Enterprise Swing Best Practices August 6, 2009

Posted by Phill in Presentation Layer.
Tags: , ,
comments closed

I know this blog is about J2EE, i.e. enterprise Java on the server side. But the past few months I’ve been working on an “enterprise” Swing-based desktop application. I say “enterprise” because it’s virtually the same as a server-side application – the only difference is that it’s using Swing for the presentation layer.

Anyway, I wanted to post up some of the things I’ve discovered: Swing is very easy, but it seems there aren’t many “best practice” guides for building an application using it. So, here is my list of “best practices”… hope you find it interesting!

  • The Presentation Model pattern is well worth using. It creates a much more loosely coupled dependency between the GUI code and the presentation logic.
  • On a similar note, using a binding framework (such as JGoodies Binding).
  • Use Actions (i.e. subclass javax.swing.AbstractAction) for use with menus and buttons etc.
  • For laying out forms, JGoodies Forms is awesome.
  • There are benefits to using component factories, i.e. a factory method to create your different UI components such as buttons.

I think that’s about it for the moment. The only other thing is, the Spring Rich Client Project (Spring RCP) looks really interesting, and I think if I was starting a new project I’d probably use it.

What are your favourite Swing tips?

Advertisements

Using Spring Security in a Swing Desktop application June 12, 2009

Posted by Phill in Frameworks, Spring.
Tags: , ,
comments closed

It seems like there’s very little support (in terms of documentation) for using Spring Security in a Swing (or general Desktop) application. All the documentation I could find assumed that Spring Security was going to be used in a web application.

However, it’s very possible to use the security framework in a Swing application – a little custom code is required, but then, that is only to be expected!

Essentially what we did is create a LoginUtils class, which had an authenticate(username, password) method. This referenced the Spring AuthenticationProvider (we’re using a custom LDAP AuthenticationProvider, but you can use whichever suits your needs).

This is what the code looks like:

public Authentication authenticate( String username, String password )
 {
 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken( username, password );

 Authentication auth = _authProvider.authenticate( token );
 if (null != auth)
 {
 SecurityContextHolder.getContext().setAuthentication( auth );

 _eventPublisher.publishEvent( new InteractiveAuthenticationSuccessEvent( auth, this.getClass() ) );

 return auth;
 }
 throw new BadCredentialsException( "null authentication" );
 }

You can then call this method from wherever you want in your application (for example, from a Login action) and your user will be logged in.

Both _authProvider and _eventPublisher are dependency-injected properties.

Notice the _eventPublisher.publish(…) call.  You do not need this if you have nothing listening out for those events. However, if you do not publish them then they will not be published, so it’s worthwhile doing – particularly if you’re writing a security framework!

The other important thing is – and this is something which caught me out first time round – is that the SecurityContextHolder by default uses a ThreadLocal pattern. For a Swing application you will want the Global pattern. Put this somewhere in your code (i.e. a static initializer, or your main method):

SecurityContextHolder.setStrategyName( SecurityContextHolder.MODE_GLOBAL );

This means that the Authentication object will be available to your entire application – if you don’t do this, objects on a different thread to the one you logged in on will not be able to ‘see’ your credentials. For a while I couldn’t figure out why my Authentication object was coming back as null, until I realised!

Note: this post is application to Spring Security 2.0.4. At the time of writing, version 3 is only at milestone 1 so I have not tried it yet!