• Feb
    • 21
    • 2013

JavaFX Maven Plugin 1.5

Posted by In JavaFX 10 comments

I’ve released version 1.5 of the JavaFX Maven Plugin:

The two big fixes in this one are:

  • The ‘app name’ is now being set correctly. Previously this was causing the build to fail when generating native bundles for Mac.
  • ‘src/main/deploy’ is now included in the classpath for the build tool, meaning you can add anything in there that the JFX packaging tools need. Among other things, this allows you to provide your own custom icons for native bundles (see the JFX deployment tools for details on how to do this).

Thanks to everyone who made contributions for version 1.4 and 1.5 – most of these fixes have come from the community or as  a result of community feedback and input.

As I mentioned in my last post, I’m off travelling for a couple of months and won’t be doing anything on this plugin during that time. I am intending to integrate it with the work the JavaFX deployment guys are doing when I get back though. So keep raising issues and requests and we’ll see what we can do with them in a few months time.

I’ll be blogging my travels a little bit too, so if you’re after a distraction check out:

http://lifefirsthand.com

Enjoy

Continue Reading→
    • Feb
    • 15
    • 2013

JavaFX Maven Plugin 1.4

Posted by In JavaFX 5 comments

I’ve just merged in contributions from the community on the JavaFX Maven plugin and released these as version 1.4.

Nothing else was changed apart from these contributions. I have been working with the JavaFX deployment guys trying to integrate and improve things using their recently open sourced packaging tools but the build setup for this is a mess, slowing everything down to a crawl. This work has also sucked up the small amount of free time I had available to put into this project recently.

I’m soon to be off travelling and will be offline for a good few months. If you wanted something fixed that didn’t make it into this build, there’s about a week left to make that happen. In particular, I think there is still an issue on Mac native builds. If someone wants to contribute a fix for this I will merge it, otherwise there’s a 50-50 chance I’ll put a fix in myself before I go.

If you have anything else you want fixed, raise it as an issue on the GitHub project. If you provide a fix you have a much higher chance of it getting sorted.

Continue Reading→
    • Dec
    • 04
    • 2012

JavaFX with a SpringMVC REST server in 5 minutes

Posted by In Enterprise, JavaFX 8 comments

Creating a simple JavaFX application in 5 minutes was pretty fun, but we can do better. This post shows you how to use the javafx-rest-archetype to create a skeleton project that includes both a REST server (based on SpringMVC) and a JavaFX client that talks to that REST server.

As before you need to have already installed JDK 7 (update 6) or later, and Maven 3.0 or later (make sure you set the JAVA_HOME environment variable when doing this).

Step 1: Fix your classpath

If you did this last time then you do not need to do it again!

When you install the JDK currently, it includes JavaFX but does not put it on the classpath (yes this is weird – it will be fixed in Java 8). To fix this, open a Command Prompt and type:

mvn com.zenjava:javafx-maven-plugin:1.3:fix-classpath

This will ask you to confirm that you want to do this, type “y”.

Step 2: Create a New Project

Open a command prompt and go to a new workspace area (i.e. create a new directory to house your code), then type:

mvn archetype:generate -DarchetypeGroupId=com.zenjava 
    -DarchetypeArtifactId=javafx-rest-archetype -DarchetypeVersion=1.1

You will be prompted for some parameters:

  • groupId: com.mycompany
  • artifactId: my-rest-app
  • version: leave as default
  • package: com.mycompany.myrest

This will create a new directory called “my-rest-project” with some basic source code which you can use as a skeleton to get you up and running quickly.

Step 3: Build the project

Change directory into your newly created project and use Maven to build your application – this will build both the client and server:

cd my-rest-app
mvn clean install

Step 4: Start the server

Change directory into the server sub-directory and start a Jetty server to run your REST web server:

cd my-rest-app-server
mvn jetty:run

You do not have to have Jetty installed, Maven will take care of this for you. Jetty is very useful for getting up and running quickly like this, however you don’t have to use Jetty. Maven builds a standard WAR file that you can deploy into any JEE web server, such as Tomact, JBoss, etc.

Your server should now be running. You can test it using a standard web browser to http://localhost:8080/my-rest-app-server/welcome and you should see XML output like:

Step 5: Run the client

Open a new command prompt, change directory into the client sub-directory and start your JavaFX client:

cd my-rest-app\my-rest-app-client
mvn jfx:run

When the JavaFX client starts up enter your name and hit the “Say Hello” button. The response from the server will be shown in the text area below:

Step 6: Edit your project

You now have a working skeleton project which you can build upon to create your next awesome JavaFX and REST server application. Since you are using Maven, you can simply open the base level POM file in your favourite IDE and your project will be automatically configured for you with the classpath all setup, etc.

Here’s the links again for using Maven with your IDE:

Your project tree should look something like (this is taken from IntelliJ):

Hopefully the code is pretty self explanatory, and I have included JavaDoc with links to external help documentation in most cases. If you need more help, post comments here or raise issues in the GitHub project for the archetype: https://github.com/zonski/javafx-rest-archetype/issues

Step 7: Distribute your app

Distributing your server is very easy, just take the generated WAR file from the ‘target’ directory of your server module and copy this to any JEE web server. I use and highly recommend Tomcat but you can use whatever you like. In tomcat simply download and install Tomcat (i.e. unzip it) onto your server and then copy the WAR file into the webapps directory. Tomcat will take care of the rest – server side deployment is easy these days.

As with the simple JavaFX application example, you can choose any of the JavaFX deployment options such as Webstart, native installer, executable JAR file, etc. They each have their advantages and disadvantages but refer to my previous post for details on this.

All the same commands are available as in the simple JavaFX project, just make sure you run them from within the client module. For example to build an executable JAR use:

cd my-rest-app\my-rest-app-client
mvn jfx:build-jar

And an executable JAR will be built into the target directory of the client module for you to copy and distribute however you want.

Conclusion

Using this archetype it is very easy to get up and running quickly with a simple JavaFX client and SpringMVC REST server. All of the code generated can be modified, added to and deleted to suit your own project needs so there are no dependencies or links to any special classes of my creation in the project. This simply provides a starting shell for you to do with as you please.

This example is deliberately simple. It does not include security or database setup, both of which would be pretty much standard in your typical REST client-server application. If I get time I and/or there is strong interest in seeing a REST setup with security and persistence, I may add an additional archetype. Register your interest in this by commenting below.

REST is very popular because it provides a way for JavaScript/AJAX clients to make remote calls on servers. I’ve provided this archetype because AJAX is such a popular space, however there are better, faster and simpler options than REST when working with pure Java on both the client and server, so why compromise? I am planning to create another archetype that creates the same setup as this one but using Spring Remoting based on Spring’s HTTPInvoker. Hopefully I will have something going on this over the next month or two – again register your interest by commenting if this is something you would find useful.

If you have any problems or suggestions please comment or raise an issue on the archetype GitHub project:  https://github.com/zonski/javafx-rest-archetype/issues

Continue Reading→
    • Nov
    • 24
    • 2012

From Zero to JavaFX in 5 minutes

Posted by In Enterprise, JavaFX 33 comments

Over the last few weeks, I’ve been working on a new Maven Plugin for JavaFX. Using this plugin it’s much, much easier to get up and running quickly and to build complicated distribution bundles (such as executable JAR files, native installers and webstart bundles). Rather than tell you about it, here’s the steps to take you from nothing to a fully working, packagable JavaFX distribution.

Before starting you will need to have installed JDK 7 update 6 or later, and Maven 3.0 or later. This guide will walk you through that.

Step 1: Fix your Classpath

When you install the JDK currently, it includes JavaFX but does not put it on the classpath (yes this is weird – it will be fixed in Java 8). To fix this, open a Command Prompt and type:

mvn com.zenjava:javafx-maven-plugin:1.3:fix-classpath

This will ask you to confirm that you want to do this, type “y”.

You will need to do this only once for each development machine (and you will never need to do it on your users’ machines, only development ones).

Step 2: Create a New Project

Open a command prompt and go to a new workspace area (i.e. create a new directory to house your code), then type:

mvn archetype:generate -DarchetypeGroupId=com.zenjava /
-DarchetypeArtifactId=javafx-basic-archetype /
-DarchetypeVersion=1.1
You will be prompted for some parameters:
  • groupId: com.mycompany
  • artifactId: my-jfx-project
  • version: leave as default
  • package: com.mycompany.myjfx
This will create a new directory called “my-jfx-project” with some basic source code which you can use as a skeleton to get you up and running quickly.

Step 3: Run the Project

Change directory into your newly created project and use Maven to launch your application:

cd my-jfx-project
mvn jfx:run

You should see a basic hello world style dialog popup like so:

Note: this run command is just a pure wrapper around the maven exec plugin. There is no special JavaFX magic going on here, it’s just a convenience method.

Step 4: Edit the Project

You can now open the new project in your favourite IDE:

Since this a Maven application any dependencies you need will be downloaded, your classpath will be all setup for you and you simply can get stuck in and start editing, running and debugging your project.

The starter project includes some example FXML, basic logging and makes use of the very cool MigPane layout manager. All of this is just a guide, you can delete, edit, rename or do what you like to all of this code to create your perfectly customised JavaFX app.

Your project should look something like this, with MainApp being the main entry point that you run:

For tips on writing JavaFX applications see: http://docs.oracle.com/javafx/

For tips on using Maven to manage your dependencies: http://maven.apache.org/guides/getting-started/index.html

Step 5: Distribute your App

JavaFX applications can be deployed in a number of different ways – each option has it’s benefits and drawbacks - choose whichever option suits you.

Executable JAR file 

From the command line, and in the base directory of your project (where the POM file is) type:

mvn jfx:build-jar

Your executable JAR will be found at: {project.dir}/target/my-jfx-project-1.0-SNAPSHOT-jfx.jar

The Executable JAR file option is simple and handy as you can easily send the single JAR around to users and they can just double click it. It does require Java to be already installed on the user’s system though, and there’s no support for auto updating and advanced functions (like menu shortcuts, file associations, etc). Also be aware that if your jars contain files with the same name then they will clobber each other (see this issue)


‘BAT’ file (for Windows)

From the command line, and in the base directory of your project (where the POM file is) type:

mvn jfx:build-win-bat-bundle

A directory containing a Windows batch file  and all project JARs will be found at: {project.dir}/target/win-bat

The ‘BAT’ file option is great for quick demos, you can easily copy the directory to your demo machine and tweak the JAR files and scripts as needed. It does require Java to be already installed on the user’s system and java.exe being on the path, so it’s more for internal use than general end user consumption.


Webstart 

Webstart applications can either be signed, or unsigned. If they are not signed then they are limited by the browser’s sandbox. Most interesting applications will need to be signed and to do this you need to get a certificate to verify you are who you say you are.  For development this can be a pain, so the JavaFX Maven plugin includes the ability to generate a quick certificate for testing (i.e. you will be able to deploy but your users will see a “this app is not trusted” message when they run it).

To generate a certificate run the following command in the base directory of your project (change the domain, country code and state to match your details):

mvn jfx:generate-key-store -DcertDomain=com.yourcompany -DcertCountry=US -DcertState=WASHINGTON

You only need to do this once for your project and you can optionally check this development keystore into your source control so other developers can avoid this step.

To then build a Webstart bundle run:

mvn jfx:build-webstart

A directory containing  a HTML file, JNLP file and your signed JAR files will be found at: {project.dir}/target/webstart

You can copy this directory directly to any web server and point users at the HTML file to run your app. Both the HTML and JNLP files are built from velocity templates which you can customise to be anything you want.

The web-based distribution, and auto updating of Webstart are great in theory, but it doesn’t work that well in practice. Use webstart only if you have control over the operating environment (e.g. you are running within a corporate IT network and can control Java versions, etc). Don’t try to use it for delivery to the general public – it just won’t work and will cause you lots of grief.
 Some other things to be aware of with webstart  depoyment:
  • browser security issues means Java will always be auto-updated, your app may break at any time if a future version of JavaFX changes the way your app works
  • there is a trend away from browser plugins and this option is not likely to be supported on major browsers soon


Native Installers

To build the native installer for your current OS run:

mvn jfx:build-native

Your bundle will be built into: {project.dir}/target/bundles

Currently native installers require you to first manually download and install an extra packaging tool specific to your OS. e.g. on Windows you need to install WiX. See the JavaFX packaging guide for more info.

Native installers are a recent addition to JavaFX, basically wrapping your Java program in a native launcher for your platform (i.e. an ‘exe’ on Windows) and bundling this into a native platform installer (i.e. an ‘MSI’ package on Windows). The JRE is actually co-bundled into the installer so your user just installs your application and does not need to install Java separately. From the end user’s perspective the whole thing is ‘native’ and the fact that your app is a Java app is hidden from them completely.

This is a very powerful option and has a lot of promise (and is the approach I would recommend) but there are still a couple of drawbacks. The main one is that you can only build the distributable for the target platform on that platform, i.e. you can only build a Windows MSI on a Windows machine, and a Mac PKG on a Mac machine. Additionally you have to download and install a third-party packaging tool that the JavaFX packing tool uses under the hood (i.e. on Windows you have to download and install WiX). I am working on extending the Maven plugin to do this last step for you.

The other major drawback is that the JRE is currently very large (70MB+) making your distributables large. This is something the Java community is (very slowly) working on, and once I get the other parts of this plugin working I may also put some effort into fixing this – it should be possible to get the bundle size under 20MB.

Finally there is no auto-updating code as yet, so each release your users must uninstall the old version and install the new one. Again this is something on the JavaFX to-do list but it hasn’t got a lot of attention. If it is something that you want, best to raise it in the open JFX mailing list.

Native installers is where I intend to spend the most effort going forward as I believe it is the only real long term option for JavaFX. I plan to release a version of the Maven plugin that can automatically download WiX for you sometime in the next few weeks. After that I will look at options for doing something similar for Mac and Linux bundles. 

Conclusion

The Maven Plugin makes it simple to get up and running with JavaFX and to build distribution bundles.  Your projects are also IDE independent (i.e. developers can use IntelliJ, Eclipse or NetBeans on the same project without problems) and you get all the cool dependency assistance that has made Maven such a popular tool. There’s little reason not to use it.

The Plugin is quite new however and since I develop on Windows, it has not been tested on Mac and Linux. If you run into any trouble on these other platforms, please raise an issue (general testers on these platforms would be great).

Currently the plugin does not support Applets. This would be trivial to add but since Applets are virtually a dead technology I have not bothered. If this is something you would like to use, raise an issue.

I also have not added Mac/Linux shell script options (i.e. similar to the Windows BAT option). Again these would be trivial to add but I don’t have environments to test on. If you have a need for these, raise an issue (and by doing so you volunteer to be the tester).

Several more advanced features are either missing (e.g. including native third-party libraries) or not well documented (e.g. templating HTML and JNLP files). I will tick away at these as and when I have time and motivation. I’m just one guy working on this in my free time, after-hours though – there’s plenty of work to be done here so if anyone is interested in volunteering some time, let me know.

Continue Reading→
    • Mar
    • 27
    • 2012

JavaFX and Spring Security

Posted by In Uncategorized 7 comments

This entry is part 15 of 15 in the series Building JEE applications in JavaFX 2.0

Disclaimer: Security is a big topic! This post is going to introduce a very basic Spring Security setup. You could probably just get away with this for a small system running on an intranet, or VPN, but for anything with serious security concerns you will need to explore the Spring Security docco and build on this post to suit your needs. At the very least you should look at encrypting passwords sent over the wire and use SSL as your socket layer. I will likely add some more complex setup to First Contact in future posts but until then check out other security articles on the web for more information, or post questions below. 

The great thing about the Internet is that it’s open to everyone. The bad thing about the Internet is that it’s open to everyone. If we’re going to put our data out there on the web chances are we want to secure that data so only those who should see and edit it, can do so.

Security is a messy business. To make a system safe, you have to put up a lot of walls and add locks to every door. Just like securing your house, the more secure you want it, the more keys you have to carry around on your keyring and the more hassles you have getting in the front door yourself.

As usual however, Spring has a framework that will help us out in this area, namely Spring Security. And, as usual, this framework is very good – non-invasive, simple to use and easy to setup. The only challenge is that Spring Security really has come out of the webapp space, so there are a few not-so-common tricks we have to employ to make them work for our JavaFX, client-server based application.

As normal, we’ll start with our code base from the previous post and add to it. The full source code for this post can be found at: http://code.google.com/p/jfxee/source/browse/trunk/first-contact/first-contact-security/

Step 1: Add Spring Security dependencies 

Spring Security is made up of a number of modules of which we need only a couple. In our server POM we need to add the following dependencies:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>3.1.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>3.1.0.RELEASE</version>
</dependency>

Security is mostly transparent to the client, however when a security violation is triggered (such as when the user tries to access something they are not authorised to) then the server will throw an exception. In order for the client to be able to process these exceptions it must have them on the classpath. As such, we add the following to the common POM so that these core classes are shared between client and server:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>3.1.0.RELEASE</version>
</dependency>

Step 2: Secure the ContactService

There are a number of ways we can define which parts of our application are secured. In web applications it is fairly common to restrict access to certain resources via URLs, so that, for example, all pages under the ‘secure’ directory or all URLs ending with “-admin.htm” are restricted to certain roles. Spring Security supports a powerful expression language for defining this in XML.

We could do this for our client-server application since all of our Service methods are exposed as URLs by the HttpServiceExporter. Given that we are dealing mostly with the Service interfaces in Java and the URL is more or less transparent, a more natural fit is to use Spring Security’s annotation based configuration. There are a couple of different annotation options we can use, but the most powerful is the expression based ones added in version 3.0. With these we can define @PreAuthorize annotations to force authentication before our method is actually executed:

@PreAuthorize("hasRole('myrole')")
public String someSecureMethod()
{
    // this method can only be accessed by users who have 'myrole'
}

As well as being defined at the method level, @PreAuthorize can be applied at the class level, in which case it will apply to all methods within that class.  If a user tries to access any secured method without having the correct role, then Spring Security will prevent this by throwing an AccessDeniedException back to the client.

The roles used in the system are completely up to us and defined through configuration (we will configure our roles in the next step). For our application, let’s define a role called ‘USER’ and another called ‘ADMIN’. In order to use our system at all, a user must have the ‘USER’ role, and in order to add or edit data the user must have the ‘ADMIN’ role.

We can secure our ContactServiceImpl by simply adding the following annotations:

import org.springframework.security.access.prepost.PreAuthorize;

@PreAuthorize("hasRole('USER')")
public class ContactServiceImpl implements ContactService
{
    public List searchContacts(String[] keywords)
    {
        ...
    }

    public Contact getContact(Long contactId)
    {
        ...
    }

    @PreAuthorize("hasRole('ADMIN')")
    public Contact updateContact(Contact updatedContact)
    {
        ...
    }
}

(see the full source code for this class here)

Step 3: Configure Spring Security

Securing our Service is all good and well, but we still need to configure Spring Security to tell it how users should be authenticated and the type of security setup we want. Since our server is a web-based application (which our client connects to over HTTP) we can make use of a lot of the standard Spring Security web stuff.

The web implementation of Spring Security uses a HTTP Filter to intercept calls to the server and manage the security access, so we need to setup this Filter in our web.xml by adding the following config:

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Next we need to add some security configuration to our Spring XML configuration (i.e. first-contact-servlet.xml). There’s a little problem here however, in web-land our Filter and our Servlet are defined as two separate entities, which means our Servlet-specific XML file won’t apply to the Filter.

We need to create a new XML configuration file; one that will apply to our application as a whole, not just our servlet. Luckily Spring defines a way to do this via the ContextLoaderListener, which is configured by a ‘context-param’. To do this we add the following to our web.xml file:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/first-contact-app.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

(you can see the full web.xml file here)

This setup will now result in two files being loaded on startup. The first is ‘first-contact-app.xml‘, which should contain all our application-wide configuration, and the second is ‘first-contact-servlet.xml‘, which should contain the minimal configuration just for our servlet.

When there is only a single servlet in use (which is how we currently have things) then the separation is not such a big deal, but when you have multiple servlets in place (for example if you add a SpringMVC or Struts web front-end to your application), then it’s important to ensure the core configuration gets shared, while the servlet specific stuff is not. In general, I put all the service, database, transaction and security configuration in the ‘app’ configuration, and include only the HTTP service exporter configuration in the ‘servlet’ file.

Here are the two updated configuration files. Included is the information needed for the Security setup. I’ll talk through this in detail below.

first-contact-app.xml

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

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:data="http://www.springframework.org/schema/data/jpa"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="

http://www.springframework.org/schema/beans


http://www.springframework.org/schema/beans/spring-beans.xsd


http://www.springframework.org/schema/context


http://www.springframework.org/schema/context/spring-context-2.5.xsd


http://www.springframework.org/schema/data/jpa


http://www.springframework.org/schema/data/jpa/spring-jpa.xsd


http://www.springframework.org/schema/tx


http://www.springframework.org/schema/tx/spring-tx-3.0.xsd


http://www.springframework.org/schema/security


http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <context:annotation-config/>
    <context:component-scan base-package="com.zenjava.firstcontact.service"/>

    <!-- Database Setup -->

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="first-contact" />
    </bean>

    <data:repositories base-package="com.zenjava.firstcontact.service"/>

    <!-- Transaction Setup -->

    <tx:annotation-driven/>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>

    <!-- Security Configuration -->

    <security:http create-session="always">
        <security:http-basic/>
    </security:http>

    <security:global-method-security pre-post-annotations="enabled"/>

    <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider>
            <security:user-service>
                <security:user name="admin" password="admin" authorities="ADMIN,USER" />
                <security:user name="user" password="user" authorities="USER" />
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>

</beans>

first-contact-servlet.xml

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

<beans xmlns="http://www.springframework.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.xsd">

    <bean name="/contact.service" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
        <property name="service" ref="contactServiceImpl"/>
        <property name="serviceInterface" value="com.zenjava.firstcontact.service.ContactService"/>
    </bean>

</beans>

So let’s look at the additional Spring configuration in more detail. First, we added the Spring namespace to the top of the XML file, no surprises here. Next we defined the ‘http’ element security like so:

<security:http create-session="always">
    <security:http-basic/>
</security:http>

This is a shortcut configuration for setting up all the normal Spring Security beans needed (and there are a number of them) for HTTP based authentication. If you want to understand all this in detail, take the time to read the Spring Security documentation, but in general you can just read this as ‘use web based security’ and move on with your life.

The only two special settings we’ve used are: the ‘create-session’ flag, which is needed to ensure a web session is created to store our authentication in; and the ‘http-basic’ setting, which tells Spring we’ll be using HTTP-BASIC AUTH for login – as you’ll see in the next section, we don’t actually use this but Spring needs to be told something here and this setting is the simplest to use.

Next, we tell Spring that we will be using annotation based authentication. As I mentioned earlier, there are a number of options, including Spring Security’s own @Secured annotation, and the JSR-235 annotations. We’re going to use the Pre/Post Authorization annotations however, and so we configure this like so:

<security:global-method-security pre-post-annotations="enabled"/>

Finally, we need to provide an AuthenticationManager. This is the core component that does user authentication (i.e. it logs users in and out and assigns them roles). In this simple setup we are going to use the most basic of AuthenticationManagers which allows us to hard code all our users and roles directly into the XML file, like so:

<security:authentication-manager alias="authenticationManager">
    <security:authentication-provider>
        <security:user-service>
            <security:user name="admin" password="admin" authorities="ADMIN,USER" />
            <security:user name="user" password="user" authorities="USER" />
        </security:user-service>
    </security:authentication-provider>
</security:authentication-manager>

We’ve define two users, one called ‘admin’ and another called ‘user’ (with matching passwords). We’ve assigned each of these users the corresponding roles via the ‘authorities’ attribute. We can edit this file and add as many users and roles as we want – no other configuration is needed.

If your application has extremely simple security requirements then just maybe you will be able to get away with this setup. In most cases however, you will want to authenticate against a database of users, using encrypted passwords and secure communication channels. In even more advanced scenarios you might want to hook into an LDAP server or single-sign-on CAS server. Spring Security supports all of this (and so much more), and mostly this is achieved just by changing the above AuthenticationManager configuration to something more advanced. I will likely add database driven authentication with encrypted databases in a future post, but if you can’t wait for that check out tutorials like this one.

Believe it or not, we’ve just secured our application. If you try to run your server now and then connect to it with your client, you should get an AccessDeniedException stopping you from accessing all that sensitive contact information.

That’s great! Just one fairly major problem: we can’t yet login so that we can actually access that data.

Step 4: Add a Security Service

In our configuration above we told Spring Security that we wanted to use HTTP Basic Authentication. This was a bit of white lie to make Spring Security happy so that we could then go off and do our own thing. While we could use HTTP Basic Authentication, a simpler and more natural way for us to authenticate with our server is for us to make a simple Java call to a ‘login’ method on our Service, passing in our username and password. It turns out this is not too hard to implement in Spring Security.

First we create a new Service for this, we’ll call it the SecurityService, but the name is arbitrary and completely up to us. Like our ContactService, the SecurityService has a few aspects to it. Firstly the Service interface goes in our common module:

package com.zenjava.firstcontact.service;

public interface SecurityService
{
    void login(String userName, String password);
}

Then we add the implementation to the server module (we’ll leave the implementation body empty for now and deal with this below):

package com.zenjava.firstcontact.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import javax.inject.Inject;

@Service
public class SecurityServiceImpl implements SecurityService
{
    private static final Logger log = LoggerFactory.getLogger(SecurityServiceImpl.class);

    public void login(String userName, String password)
    {
        // todo: login with Spring Security
    }
}

Next we can expose this service over HTTP via the first-contact-servlet.xml configuration file:

<bean name="/security.service" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
    <property name="service" ref="securityServiceImpl"/>
    <property name="serviceInterface" value="com.zenjava.firstcontact.service.SecurityService"/>
</bean>

And then in our client module, we can setup a connection to this service in our FirstContactAppFactory class. We need to refactor our code here slightly so as to be able to reuse the HTTP Request Executor:

@Bean
public SecurityService securityService()
{
    return createService("security.service", SecurityService.class);
}

@Bean
public ContactService contactService()
{
    return createService("contact.service", ContactService.class);
}

@Bean
public HttpInvokerRequestExecutor httpInvokerRequestExecutor()
{
    return new CommonsHttpInvokerRequestExecutor();
}

protected  T createService(String endPoint, Class serviceInterface)
{
    HttpInvokerProxyFactoryBean factory = new HttpInvokerProxyFactoryBean();
    String serverUrl = String.format("http://localhost:8080/%s", endPoint);
    factory.setServiceUrl(serverUrl);
    factory.setServiceInterface(serviceInterface);
    factory.setHttpInvokerRequestExecutor(httpInvokerRequestExecutor());
    factory.afterPropertiesSet();
    return (T) factory.getObject();
}

With our SecurityService now available, we can look at implementing that login method. This involves two steps: first we use the AuthenticationManager (configured above) to validate the username and password and provide an ‘Authentication’ object for us. Second we need to place that ‘Authentication’ object (which represents the logged in user) in the SecurityContextHolder provided by Spring Security. Since we’re using the standard web-based setup, this SecurityContextHolder is associated with the current web session, so each client will be associated with a different instance.

The code for this turns out to be remarkably simple:

@Service
public class SecurityServiceImpl implements SecurityService
{
    private static final Logger log = LoggerFactory.getLogger(SecurityServiceImpl.class);

    @Inject private AuthenticationManager authenticationManager;

    public void login(String userName, String password)
    {
        // never log password information!
        log.info("Logging in user '{}'", userName);
        UsernamePasswordAuthenticationToken authToken
                = new UsernamePasswordAuthenticationToken(userName, password);
        Authentication authentication = authenticationManager.authenticate(authToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        log.debug("User '{}' successfully logged in with authorities: '{}'", userName, authentication.getAuthorities());
    }
}

Now all we need is a Login screen to call this from the client.

Step 5: Add a Login screen

Adding a Login screen is now fairly simple. The general flow is not overly different to our existing Contact management screens – we gather from data from the user and call a Service method.

First some FXML, I’m lazy, so I have adapted this from official getting started with FXML guide:

Login.fxml

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

<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<BorderPane fx:id="root" fx:controller="com.zenjava.firstcontact.gui.login.LoginPresenter" xmlns:fx="http://javafx.com/fxml">

    <center>
        <GridPane alignment="top_center" hgap="8" vgap="8"
                  style="-fx-padding: 40 0 0 0">
            <children>
                <Label text="Sign In"
                       style="-fx-font: NORMAL 14 Tahoma;"
                       GridPane.columnIndex="0" GridPane.rowIndex="0"/>

                <Label text="Username:"
                       GridPane.columnIndex="0" GridPane.rowIndex="1"
                       labelFor="$usernameField"/>
                <TextField fx:id="usernameField" prefColumnCount="10"
                           GridPane.columnIndex="1" GridPane.rowIndex="1"
                           onAction="#login"/>

                <Label text="Password:"
                       GridPane.columnIndex="0" GridPane.rowIndex="2"
                       labelFor="$passwordField"/>
                <PasswordField fx:id="passwordField" prefColumnCount="10"
                               GridPane.columnIndex="1" GridPane.rowIndex="2"
                               onAction="#login"/>

                <Button fx:id="submitButton" text="Login"
                        GridPane.columnIndex="1" GridPane.rowIndex="3"
                        onAction="#login"/>

                <Label fx:id="statusText"
                       GridPane.columnIndex="0" GridPane.rowIndex="4" GridPane.columnSpan="2"
                       style="-fx-text-fill: #ff0000;"/>
            </children>
        </GridPane>
    </center>

</BorderPane>

Next a Presenter for the above FXML. This handles the login button click (and enter key) to call onto our SecurityService with the username and password. The only slight difference to our other server calls is that we actually handle login exceptions, in particular the BadCredentialsException, and tell the user what went wrong (we should really be doing better error handling everywhere, but that’s another post!).

LoginPresenter.java

package com.zenjava.firstcontact.gui.login;

import com.zenjava.firstcontact.gui.main.MainPresenter;
import com.zenjava.firstcontact.service.SecurityService;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.BadCredentialsException;

import javax.inject.Inject;

public class LoginPresenter
{
    private static final Logger log = LoggerFactory.getLogger(LoginPresenter.class);

    @FXML private Node root;
    @FXML private TextField usernameField;
    @FXML private PasswordField passwordField;
    @FXML private Label statusText;

    @Inject private SecurityService securityService;
    @Inject private MainPresenter mainPresenter;

    public Node getView()
    {
        return root;
    }

    public void login(ActionEvent event)
    {
        statusText.setText(null);

        final String username = usernameField.getText();
        final String password = passwordField.getText();

        final Task loginTask = new Task()
        {
            protected Void call() throws Exception
            {
                // never log password information!
                log.info("Logging in as user '{}'", username);
                securityService.login(username, password);
                return null;
            }
        };

        loginTask.stateProperty().addListener(new ChangeListener()
        {
            public void changed(ObservableValue source, Worker.State oldState, Worker.State newState)
            {
                if (newState.equals(Worker.State.SUCCEEDED))
                {
                    log.info("Successfully logged in as user '{}'", username);
                    mainPresenter.showSearchContacts();
                }
                else if (newState.equals(Worker.State.FAILED))
                {
                    Throwable exception = loginTask.getException();
                    if (exception instanceof BadCredentialsException)
                    {
                        log.debug("Invalid login attempt");
                        statusText.setText("Invalid username or password");
                    }
                    else
                    {
                        log.error("Login failed", exception);
                        statusText.setText("Login error: " + exception);
                    }
                }
            }
        });

        new Thread(loginTask).start();
    }
}

We need to load this Presenter and FXML in our FirstContactAppFactory:

@Bean
public LoginPresenter loginPresenter()
{
    return loadPresenter("/fxml/Login.fxml");
}

And we need to sort out our MainPresenter so it can show the Login page when requested to do so:

public class MainPresenter
{
    ...

    @Inject private LoginPresenter loginPresenter;

    public void showLogin()
    {
        log.info("Showing Login page");
        contentArea.setCenter(loginPresenter.getView());
    }

    ...
}

Finally we want to show our Login page on startup, so we make a minor tweak to FirstContactApp:

...
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(FirstContactAppFactory.class);
MainPresenter mainPresenter = context.getBean(MainPresenter.class);
mainPresenter.showLogin();
...

Hey presto! We now have a secured client-server application with Login screen.

Step 6: Try it out

Start your server now, and then run an instance of the client. You should be prompted with the following login screen:

Try entering an invalid username and password and check that you get a suitable error message. Next try logging with username ‘user’ and password ‘user’. You should be taken to the normal search screen, which you have permission to access. If you edit or add a Contact however, you will see an AccessDeniedException in the stack trace since you only have the ‘USER’ role, which does not have permission to edit data (our error handling is currently very poor, but you can fix this easily – I’ll probably look at doing so in a future post).

Run another instance of the client and this time login with username ‘admin’ and password ‘admin’. Now try editing Contact information. Since the ‘admin’ user has the ‘ADMIN’ role you can now do everything without any error.

As mentioned, this is a very basic Security setup, just to give you the idea and provide a base to work off. We’re missing simple features like ‘logout’ and we don’t actually associate Contacts with the logged in user when they are created so anything one user creates, the other can see and vice-versa. Additionally our users are all stored in an XML config file, which is not at all flexible and our passwords are stored in plain text, meaning anyone with access to the XML file can read them.

Spring Security provides the means to improve on all of this, and if you’re in a hurry, you can hunt through the Spring Security documentation to work out how. I’ll do my best to add the features most proper JEE applications need over the coming months as time permits, but if you have specific areas that you’d like to see fleshed out, post questions below.

The full source code for this post can be found at: http://code.google.com/p/jfxee/source/browse/trunk/first-contact/first-contact-security/

Continue Reading→
    • Mar
    • 23
    • 2012

Captains Log

Posted by In Uncategorized 4 comments

This entry is part 14 of 15 in the series Building JEE applications in JavaFX 2.0

It’s not galmourous or exciting, but good logging is critical to the long term survival of any large application. Logging in Java has a bit of a sordid history, with a few bad decisions made in the early days that still cause some lingering hassles. More recent frameworks have patched over some of this mess but there’s still a few hoops we have to jump through to setup simple logging.

Since JavaFX 2 uses standard Java we have all the same logging options (and hassles) as with any normal Java application. In this post we’re going to look at integrating goold old Log4J into our First Contact application. We’re also going to make use of SLF4J, which is a generic logging API that sits ontop of Log4J. Using this generic API we can keep our code free from specific Log4J dependencies, which allows us to change between any of the supported logging frameworks simply by changing configuration files (SLF4J also has binding for a number of other logging platforms such as java.util.logging, and Apache Commons Logging).

We’ll add logging support to both our client and our server. We could therefore put all the setup in the common module, so we only need to configure it one place. This is a bit of a coincidental symmetry however – there is no technical reason that the client and server should share the same logging infrastructure, particularly at a configuration level (we often want different logging levels for client and server). As such, I tend to setup logging in the client and server completely independently of each other, giving me the option to change one, should I have need, without impacting the other. If this approach doesn’t sit well with you, feel free to merge all the following setup in the common module.

Step 1: Add the dependencies

Starting with our previous code base once again, the first thing we need to do is include the SLF4J and Log4J dependencies in both our client POM and server POM. The additional dependencies are:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.6.4</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.6.4</version>
</dependency>

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.16</version>
</dependency>

As well as the base libraries for Log4J and SLF4J, we’ve also defined the SLF4J-to-Log4J binding. Adding this JAR is all the configuration we need to make SLF4J use Log4J as its implementation – SLF4J detects the available binding at startup and uses it automatically.

Step 2: Add log calls to our code

To log messages from within our code, we need to define Loggers. Typically you define one per class that you are logging from, and define the Logger as a static instance in that class. So for example if we want to log from within the ContactSearchPresenter class we do the following:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ContactSearchPresenter implements Initializable
{
    private static final Logger log = LoggerFactory.getLogger(ContactSearchPresenter.class);

    ...
}

And in the ContactDetailPresenter we do the following:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ContactDetailPresenter
{
    private static final Logger log = LoggerFactory.getLogger(ContactDetailPresenter.class);

    ...
}

Once we have these Loggers setup we can then use them along the lines of the following:

public void search(ActionEvent event)
{
    String searchPhrase = searchField.getText();
    final String[] keywords = searchPhrase != null ? searchPhrase.split("\\s+") : null;
    final Task<List<Contact>> searchTask = new Task<List<Contact>>()
    {
        protected List<Contact> call() throws Exception
        {
            log.info("Searching for contacts, keywords = {}", keywords);
            return contactService.searchContacts(keywords);
        }
    };

    searchTask.stateProperty().addListener(new ChangeListener<Worker.State>()
    {
        public void changed(ObservableValue<? extends Worker.State> source, Worker.State oldState, Worker.State newState)
        {
            if (newState.equals(Worker.State.SUCCEEDED))
            {
                List<Contact> matches = searchTask.getValue();
                log.info("Found {} matching contacts", matches.size());
                resultsList.getItems().setAll(matches);
            }
            else if (newState.equals(Worker.State.FAILED))
            {
                Throwable exception = searchTask.getException();
                log.error("Contact search failed", exception);
            }
        }
    });

    new Thread(searchTask).start();
}

SLF4J supports token replacement in the search phrases. So if you call something like:

log.info("value1 = {}, value2 = {}", value1, value2);

then each of the ‘{}’ elements will be replaced by the value passed in. For backwards compatability reasons they’ve not used varags so if you want to do more than two parameters you have to create an array, so something like:

log.info("value1 = {}, value2 = {}, value3 = {}", new Object[] {value1, value2, value3});

When you log an ‘error’, you can pass an exception as the parameter instead of the value replacements. In this case, the full stack trace of the exception will be logged along with the message you provide.

See the SLF4J documentation for more information on all of this.

Choosing how, when and where you log is an architectural decision that should be based on your particular needs (i.e. the complexity of your application, the usage of it, etc). The main levels available are ‘error’, ‘warn’, ‘info’, ‘debug’ and ‘trace’.

‘Error’ and ‘warn’ are pretty self explanatory. I tend to use ‘info’ to track the high-level user flow (e.g. “the user is now adding a new contact called John Smith”) so that this log can be used to trace back what the user was doing (or trying to do). I then use ‘debug’ for finer-grained, processing details (e.g. “Contact John Smith was created with ID 31″). Occasionally I will use ‘trace’ for very low level debugging, such as when iterating through a a loop with complex logic.

In the server, I tend to log at least one ‘info’ message in every service call. In the client, I tend to log an ‘info’ message at least once per Presenter method. I then generally add ‘debug’ logging in a more add-hoc fashion in the places where I think it will be useful. I generally don’t do a lot of logging inside the view (since you can usually see this stuff anyway), unless the view logic is doing something a little complex like dynamically loading a sub-view based on state, etc.

It’s considered good practice to also enclose your logging in an ‘if’ check to make sure the level of logging is enabled. So for a debug call you should do something like the following:

if (log.isDebugEnabled())
{
    log.debug("Some log message");
}

This stops unnecessary logging calls from happening and can improve performance. The check is not required though. If you don’t do it, your messages will still get filtered if the corresponding log level is not enabled. The check just stops an extra method call (and its parameters) getting added to the stack and any avoids any processing you do in building your log message, etc.

I tend to add this check only on log calls that either get called a lot (e.g. the body of a loop), or that have a lot of data to be logged (e.g. an array of values or a large object tree). Typically I don’t bother with this check for ‘error’ or ‘warn’ since they happen so infrequently, and I rarely bother with ‘info’ calls as well. Debug calls I usually do the check, and for trace calls I pretty much always use the check.

All of the above are just tips and suggestions. Logging is more a gut feel than a precise science. Define your own logging strategy to suit your needs – think about what you as a developer coming back to fix a bug in this code in three years time would want to see in the log file.

Step 3: Configure your loggers

Finally, we need to define a Log4J configuration file to format the log about and restrict the levels of log messages we are going to include in our log file. For this we simply add a file called ‘log4j.xml’ to src/main/resources of both the client and server modules.

src/main/resources/log4j.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%-5p %c{1}] - %m%n"/>
        </layout>
    </appender>

    <logger name="com.zenjava">
        <level value="debug"/>
    </logger>

    <root>
        <priority value ="info" />
        <appender-ref ref="console" />
    </root>

</log4j:configuration>

We’ve defined a single ‘appender’, which just logs to the console, and then we’ve set the root level of logging to ‘info’, which means only messages of ‘info’ and above will get logged. For our code however, we want to know more of what’s going on, so we’ve defined an additional logger for everything under ‘com.zenjava’ to show messages of ‘debug’ or above.

This configuration is very flexible, for a production environment you will likely want a rolling file appender and will also want to add different loggers and levels (e.g. you might want to enable Hibernate’s SQL logging to track database calls). You’ll find plenty of info on configuring Log4J for your specific needs on the web.

The full source code for this blog can be found at: http://code.google.com/p/jfxee/source/browse/trunk/first-contact/first-contact-logging/

Continue Reading→
    • Mar
    • 20
    • 2012

Search like you mean it

Posted by In Uncategorized 3 comments

This entry is part 13 of 15 in the series Building JEE applications in JavaFX 2.0

In the last post we added database support to our First Contact application, taking advantage of both JPA and Spring Data. We cheated a little however; to keep things simple we limited our contact search query to just a single keyword. Thanks to the rise of Google Search, powerful keyword searching across multiple attributes is now the most familiar way for people to navigate their data these days. Our users are going to expect more than just a simple, single keyword search.

The SQL query for this however is a little tricky. Unlike a standard query, the number of predicates in the query depends on the number of keywords. For example, if we wanted to search our contacts by first name or last name, for the keywords ‘one’, ‘two’ and ‘three’ our SQL would look something like the following:

select * from contact
  where (firstName like '%one%' or lastName like '%one%')
    and (firstName like '%two%' or lastName like '%two%')
    and (firstName like '%three%' or lastName like '%three%')

We need to check that each keyword exists in at least one of the columns we are searching (i.e. first name and last name). The more keywords we have, the more ‘and’ clauses we need. Our simple naming convention for Spring Data isn’t going to cut it for this sort of thing, we need to dynamically build our query at runtime! Luckily JPA includes a way to build dynamic queries using the classes found in javax.persistence.criteria.

The recommended way to build dynamic query predicates using Spring Data is to create a ‘Specifications‘ class that has a static method to generate each of the Specifications (i.e. dynamic query providers) that we will use. In our case we can create a ContactSpecifications class and add a single searchContacts method to it.

ContactSpecifications.java

package com.zenjava.firstcontact.service.repository;

import com.zenjava.firstcontact.service.Contact;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.*;

public class ContactSpecifications
{
    public static Specification searchContacts(final String[] keywords)
    {
        return new Specification()
        {
            public Predicate toPredicate(Root contact, CriteriaQuery query, CriteriaBuilder builder)
            {
                Predicate predicate = builder.conjunction();

                if (keywords != null)
                {
                    for (String keyword : keywords)
                    {
                        if (keyword != null && keyword.length() > 0)
                        {
                            String matchTerm = "%" + keyword.toLowerCase() + "%";
                            predicate.getExpressions().add(builder.or(
                                    builder.like(builder.lower(contact.get("firstName")), matchTerm),
                                    builder.like(builder.lower(contact.get("lastName")), matchTerm)
                            ));
                        }
                    }
                }

                return predicate;
            }
        };
    }
}

As you can see, the Specification class provides a ‘toPredicate’ method that generates a dynamic predicate (i.e. query) for the Contact table. In our implementation of this we iterate through the keywords provided, adding restrictions to the predicate as needed. This is a relatively simple predicate, searching only one table but you can create pretty much any query, including table joins, using this predicate builder approach. See the Spring Data Specification documentation for more detail on this.

Next we need a way to execute this dynamic query. With Spring Data we simply make our Repository interface extend JpaSpecificationExecutor. This additional interface provides several methods, such as  ’findOne(Specification)’ and ’findAll(Specification)’, that take Specification objects and execute the resulting queries for us. Our updated ContactRepository class now looks like this (we can remove the old ‘findByFirstNameLikeOrLastNameLike’ method as we won’t be needing this now we can do proper keyword searching):

ContactRepository.java

public interface ContactRepository
        extends CrudRepository, JpaSpecificationExecutor
{
}

As well as providing a simple ‘findAll’ method, the JpaSpecificationExecutor also provides methods for retrieving paged data – i.e. retrieving results in batches (such as 25 at a time) and paging forward and backwards through those results. This is extremely useful when you have a large set of data that you can’t show all at once. We won’t use this here, but check out the PageRequest class for more details on how to use this.

Finally, we can now update our ContactServiceImpl to use the new ContactSpecification to perform a true keyword search. Our new searchContacts method looks like this:

public List searchContacts(String[] keywords)
{
    return contactRepository.findAll(ContactSpecifications.searchContacts(keywords));
}

That’s it! Give it a run and check it out. This same basic query can be easily extended to cover more complex scenarios, allowing your users to search across multiple tables and multiple fields via a simple text field search – this is guaranteed to make you popular at parties.

The full source code for this post can be found at: http://code.google.com/p/jfxee/source/browse/trunk/first-contact/first-contact-client-db-search/

Continue Reading→
    • Mar
    • 19
    • 2012

JavaFX and persistence: adding database support

Posted by In Uncategorized 8 comments

This entry is part 12 of 15 in the series Building JEE applications in JavaFX 2.0

So far we’ve created a tidy little JavaFX contact management GUI; we’ve added some funky dependency injection via Spring; set up some handy maven-based build scripts; and even made our application work as a client-server based system over the internet. All very cool, but we’re missing one vital ingredient: persistence. We’re not yet saving our contact data, so every time we stop our server, all the information we’ve entered is lost.

In this post we’re going to add database storage to our First Contact system. we’ll make use of JPA and Hibernate, as these are the established players in this field. We’ll also make use of a few Spring tools to make things even easier, including Spring Transactions and the awe-inspiring Spring Data project. As usual, we’ll start with the code base from the previous blog post and step through each of the changes needed to get database integration included. You can access the final, complete code for this post at: http://code.google.com/p/jfxee/source/browse/trunk/first-contact/first-contact-client-db/

Step 1: Configure the JPA Persistence Unit

The Java Persistence API (JPA for short) is a standard API for using Object Relational Mapping (ORM) technologies – i.e. those that map Java Objects onto Relational Databases, where each SQL table maps to a Java Bean class. JPA is a fairly well established standard these days with lots of tooling support and good documentation out there on the web.

Since JPA is just an API, we need to choose an implementation to use with it (called a ‘provider’). I generally use Hibernate, a well established and powerful ORM. If you’re not familiar with any of this stuff you might want to take a quick look through some of the Hibernate and JPA articles out there on the web.

The first thing we need to do is configure our server application to use JPA and Hibernate, and setup our database connection. JPA requires us to define an XML configuration file called persistence.xml and include this in our META-INF directory. Since we’re using Maven, we simply include this file in the directory /src/main/resources/META-INF.

JPA/Hibernate can be configured to work with any JDBC compliant database, such as Oracle, PostgreSQL, MySQL, etc. To get us up and running quickly and easily, we’re going to use a light-weight Java database called HyperSQL (aka HSQLDB). This doesn’t require any installation (it runs within the JVM and saves its data to a local file), and is a very handy tool for demos, development environments, unit tests, and client-side storage. In a future post I’ll show you how to wire up a PostgreSQL database instead for some production grade database support, but HSQLDB will suit our purpose for now.

The persistence.xml file contains any number of ‘persistence units’, each of which defines a provider (such as hibernate) and the configuration properties for that provider (such as the URL, username and password to use when connecting to the database). Below is the persistence.xml we’ll use for our First Contact application:

/src/main/resources/META-INF/persistence.xml:

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

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence

http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"

             version="1.0">

    <persistence-unit name="first-contact">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <properties>
            <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" />
            <property name="hibernate.connection.url" value="jdbc:hsqldb:file:~/first-contact-db/first-contact" />
            <property name="hibernate.connection.username" value="sa" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
        </properties>
    </persistence-unit>

</persistence>

In the configuration above, we’ve told JPA to use Hibernate as the provider, and then we’ve told Hibernate to use HSQLDB as the database implementation. In the HSQLDB connection URL we’ve specified a local file to use (the file will be created in your ‘home’ directory). See the HSQLDB documentation for more information on URL settings.

We’ve also set Hibernate’s ‘auto ddl’ setting to ‘update’ – on startup Hibernate will automatically create our database schema for us (i.e. all the Tables and Columns to use) based on the Entity beans we specify (which we will do in the next step). This is incredibly handy for testing/development as we simply make changes to our Java beans and the database is updated automatically to match. This can be a little risky in a production environment however, and in a future post, I’ll show you some techniques I use for database schema management.

As well as the above configuration we have to setup our project to include the JPA and Hibernate libraries on the classpath. With Maven this can be done by simply adding the following dependencies to our server:

<!-- JPA -->
<dependency>
    <groupId>org.hibernate.java-persistence</groupId>
    <artifactId>jpa-api</artifactId>
    <version>2.0-cr-1</version>
</dependency>

<!-- Hibernate -->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>3.6.8.Final</version>
</dependency>

<!-- HSQL DB -->
<dependency>
    <groupId>hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <version>1.8.0.10</version>
</dependency>

All of these dependencies are available via the Maven central repository, so just by adding these to the POM, Maven will automatically download the necessary JARs and add them to the classpath (IntelliJ will automatically trigger a download, or you can force a refresh by doing a Maven -> reimport, I assume Eclipse and Netbeans do something similar but if not, you can run mvn clean install from the command line to force a download).

Note: we only need to add these dependencies to the server module. The client module is completely decoupled from the database implementation and does not have any dependencies onto Hibernate or HSQLDB. This is one of the design goals of our three-tier architecture, the data layer does not expose it’s plumbing to the other layers.

Step 2: Define the Contact Entity

We have a database but no tables yet. In JPA, we define our tables via ‘Entity beans’. These are basically regular Java Beans with a few annotations that tell the JPA system how to map the bean back to a table. Each row in the table will map to one instance of the Java bean.

We’re storing basic contact information, so a single ‘contact’ entity will do, with just first name and last name properties. In fact we have a bean already that will do the job, Contact.java. This is the Java bean we’ve been using in our previous examples to pass data between the client and server. We just need to make a few minor tweaks to this class so that it will work as an Entity.

Side note: using your service layer beans (which are effectively Data Transfer Objects between the presentation-tier and business-tier) as your entity beans (i.e. the data-tier) is a design decision that needs to be carefully considered. I personally create separate entity and DTO classes – this gives a very clean separation between the tiers at the (high) cost of code duplication. This choice is something of a contentious debate with good arguments on both sides of the fence. In the interest of keeping things simple, I am using the DTOs as the Entity beans in this post. In a later post I will likely explore the alternatives and advantages and disadvantages of each. If you are interested however, you can check out this article for some more insight.   

Here’s the updated bean, I’ll talk through the changes below:

package com.zenjava.firstcontact.service;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.io.Serializable;

@Entity
public class Contact implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String firstName;
    private String lastName;

    public Contact()
    {
    }

    public Contact(Long id, String firstName, String lastName)
    {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Long getId()
    {
        return id;
    }

    public String getFirstName()
    {
        return firstName;
    }

    public String getLastName()
    {
        return lastName;
    }
}

The changes are as follows:

  • Annotate the bean with @Entity. This just tells the JPA system that we want this Bean to be mapped to the database.
  • Annotate the ‘id’ property with @Id. In order to be managed by JPA, each bean needs a field defining the unique ID for it.
  • Annotate the ‘id’ property with @GeneratedValue(strategy = GenerationType.AUTO). This tells JPA that we want to automatically generate unique IDs for us using whatever strategy makes sense for the underlying database implementation. This is optional, but if we left it out we would have to manually generate unique IDs ourselves.
  • Make the ‘id’ property a ‘Long’ instead of a ‘long’. This allows it to be ‘null’, which is a little easier to work with in JPA. You can use a ‘long’ if you prefer, however you have to then use -1 to represent a ‘null’ ID. Using a ‘Long’ is just more natural.
  • Add an empty constructor. Hibernate uses reflection to create the class and set the fields with data loaded from the database. To do this it needs an empty constructor so it can create an instance of the class and work with it.

We haven’t added any setter methods for the properties as yet, but we could if we had a need for them (we don’t in our application as yet).

The annotations defined above are part of the JPA library. The Contact class lives in the common module (since it is shared between client and server) and so far we’ve only added our JPA dependencies to the server module. In order for our annotations to be available in the common module we need to add the following dependency to the common POM:

<dependency>
    <groupId>org.hibernate.java-persistence</groupId>
    <artifactId>jpa-api</artifactId>
    <version>2.0-cr-1</version>
</dependency>

Notice that we’re only adding the JPA API here, not the Hibernate provider or HSQLDB libraries. These are needed only by the server, the API is sufficient for the common module and is all the client will be exposed to.

Back in step 2, we used the ‘auto dll’ setting to tell Hibernate to automatically create our schema for us, but we now need to include the Contact class in the persistence.xml file in order for it to be included in the process:

...
    <persistence-unit name="first-contact">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>com.zenjava.firstcontact.service.Contact</class>
        <properties>
        ...

Now, when the system starts up, Hibernate will automatically create a database table for the Contact bean and include the firstName and lastName fields on it.

Note: defining the ‘class’ in the persistence.xml file only seems to be needed when your Entity beans are defined in a separate Maven module (in our case ‘common’). If the Entity is defined in the same maven module, Hibernate will automatically find it without having to manually specify it. I’m not sure why this is so – if anyone knows a way to avoid this please post a comment. 

This is a very simple, single-table database system we’ve setup here. Obviously Hibernate is capable of a whole lot more, including relationships via foreign keys. For more details on this however, check out the plethora of Hibernate tutorials on the web.

Step 3: Create a Spring Data Repository 

We have a database, now we need a way to get data in and out of it. In a traditional database system you would use SQL queries to do this, but with JPA we can use regular Java calls and these will be mapped to SQL for us automatically. As such, instead of writing a whole stack of SQL queries, we can just write a stack of compiler-friendly Java methods for the Entities we want to access.

A typical design strategy for this is to use Data Access Object (DAOs). With this pattern you bundle all the data access methods relating to a single Entity into a DAO, encapsulating all your queries within this class, making them easier to test and maintain. Typically these DAOs all end up looking very similar, with every DAO providing the same basic CRUD operations. Several ‘generic DAO’ patterns have emerged as a result, such as the one described here.

We can go one step further however and make use of the JPA support within the Spring Data project. This has a built in DAO-like architecture, which it then builds upon to provide automatic query generation, saving us huge amounts of boiler plate code to write. It’s a fairly new player to the scene (as far as I know) and hasn’t gained nearly as much attention as it should have – at least it seems to be largely unheard of down my end of the planet. As you’re about to see however, it’s pretty awesome.

To use Spring Data, first we add the following dependency to our server POM:

<!-- Spring data -->
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
    <version>1.0.2.RELEASE</version>
</dependency>

Now we create a Repository interface. This is the term Spring Data uses for DAOs, each Repository is basically just a DAO. We make our Repository extend Spring Data’s CrudRepository, telling it what Entity type it is a repository for, and what type of ID that entity has. Our ContactRepository looks like this:

package com.zenjava.firstcontact.service.repository;

import com.zenjava.firstcontact.service.Contact;
import org.springframework.data.repository.CrudRepository;

public interface ContactRepository extends CrudRepository<Contact, Long>
{
}

Just by extending CrudRepository, we already have all our basic CRUD support for the Contact entity. We can findOne by ID, findAll, save and delete our Contact entities. We don’t even have to provide an implementation for this interface – Spring Data will do this for us automatically at runtime!

Even better, if we want to do stuff beyond the basic CRUD functions we can do so very easily. If, for example, we want a query to find all Contacts by first name, we could just define a method like so:

public interface ContactRepository extends CrudRepository<Contact, Long>
{
    List<Contact> findByFirstName(String firstName);
}

By following this simple naming convention, Spring Data automatically generates a query for us that searches by first name! This is so ridiculously easy it almost feels like cheating. There’s loads more you can do with Spring Data (including defining your own custom queries for things that don’t fit the naming pattern using the @Query annotation). Check out the Spring Data documentation for more details.

There’s just one more step we need to do to make all of this work: we need to setup a JPA EntityManager, and enable Spring Data in our Spring config file and tell it where to find our Repository interfaces. This is a simple matter of adding the following to our spring configuration file first-contact-servlet.xml

First a ‘data’ namespace addition at the top of the file:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:data="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="

http://www.springframework.org/schema/beans


http://www.springframework.org/schema/beans/spring-beans.xsd


http://www.springframework.org/schema/context


http://www.springframework.org/schema/context/spring-context-2.5.xsd


http://www.springframework.org/schema/data/jpa


http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

Then the following  anywhere in the file:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="first-contact" />
</bean>

<data:repositories base-package="com.zenjava.firstcontact.service"/>

The above config defines a simple JPA based EntityManager that is hooked up to our ‘first-contact’ persistence unit that we defined in our persistence.xml. Then it enables Spring Data and tells it to scan the ‘service’ package and find all our Repository interfaces and automatically create implementations for them that we can use in our service beans.

Step 4: Create a Service implementation

Previously our service implementation was provided by the SimpleContactService class, which just kept a list of hard-coded contacts in memory. We can delete this simple class now and add a new one called ContactServiceImpl (the naming convention is up to you – if you end up having multiple service implementations a good name would be JpaContactService).

As with the SimpleContactService, our new ContactServiceImpl class will implement the ContactService interface. Instead of using an in-memory list however, our new service will use an injected instance of the ContactRepository to manage contacts.

@Service
public class ContactServiceImpl implements ContactService
{
    @Inject private ContactRepository contactRepository;

The getContact and updateContact methods can be implemented trivially by calling through to our repository like so:

public Contact getContact(Long contactId)
{
    return contactRepository.findOne(contactId);
}

public Contact updateContact(Contact updatedContact)
{
    return contactRepository.save(updatedContact);
}

Our ‘searchContact’ method is a little more tricky. We want to perform a detailed keyword search that requires each keyword to appear in either the first name or last name. There’s a way to do this but it requires some stuff we’ve not covered yet. So for now, to avoid getting bogged down and also to show you an example of Spring Data’s cool automatic query generation, we’re just going to do a simple query that picks the first keyword only.

For this to work we just add a new method to our ContactRepository like so:

public interface ContactRepository extends CrudRepository<Contact, Long>
{
    List<Contact> findByFirstNameLikeOrLastNameLike(String firstName, String lastName);
}

Based just on the name of the method, Spring Data will create a query that does a ‘like’ match on both first name and last name. We don’t have to write any implementation code or SQL for this, it just works!

Then we can use this in our ContactServiceImpl like so:

public List<Contact> searchContacts(String[] keywords)
{
    String searchTerm = keywords != null && keywords.length > 0 && keywords[0].trim().length() > 0
            ? "%" + keywords[0] + "%" : "%";
    return contactRepository.findByFirstNameLikeOrLastNameLike(searchTerm, searchTerm);
}

This is not quite the full multi-keyword search we wanted, but it’s still pretty good and it’s all been done with very little code. I’ll show you how to use Spring Data’s specifications to do the proper search in a future post, but for now let’s just stick to our simple query.

Our service is looking pretty good, we just now need to tell Spring to use this new implementation instead of our old SimpleContactService. This is done by editing the Spring config file, first-contact-servlet.xml, and changing the service export config to be the following:

<bean name="/contact.service" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
    <property name="service" ref="contactServiceImpl"/>
    <property name="serviceInterface" value="com.zenjava.firstcontact.service.ContactService"/>
</bean>

Step 5: Define the Transaction bounds

Something we’ve ignored up until now is transactions. Every database call has to be done within a transaction. By default each call to the database will be done with in its own local transaction, however it is much more efficient and cleaner to define your own transaction boundaries. That way you can perform several database calls in the one transaction, making your code run faster, as well as allowing you to rollback all the calls if you hit a failure half way through.

Traditionally transaction management was a messy area, but Spring comes to our rescue once again. Using Spring’s Transaction Management support we can easily enable transaction support by adding the following namespace to our Spring configuration file, first-contact-servlet.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:data="http://www.springframework.org/schema/data/jpa"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="

http://www.springframework.org/schema/beans


http://www.springframework.org/schema/beans/spring-beans.xsd


http://www.springframework.org/schema/context


http://www.springframework.org/schema/context/spring-context-2.5.xsd


http://www.springframework.org/schema/data/jpa


http://www.springframework.org/schema/data/jpa/spring-jpa.xsd


http://www.springframework.org/schema/tx


http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

And then adding the following configuration anywhere in the file:

<tx:annotation-driven/>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

The ‘transactionManager’ bean declaration defines a standard JPA transaction manager and attaches this to our EntityFactory (which provides the connection to the database).

The ‘tx:annotation-driven’ element tells Spring that we want to use annotations on our classes to define our transaction bounds. I find this the easiest and cleanest way to do this, however you can use several powerful alternatives – check out the Spring docco for more info on this.

With transaction annotations enabled all we need to do is put the @Transactional annotation on the Spring controlled classes we want to use as transaction bounds. I use my service methods for this, so each call from the client to a service method is in its own transaction (calls between services on the server side will propagate their transactions).

In the case of our ContactServiceImpl we can just apply a global read-only transaction annotation to the whole class so that every method starts a new transaction. Our updateContact method however needs to do a write action, so we place a specific annotation on this method to allow this. The final ContactServiceImpl class looks like this:

import com.zenjava.firstcontact.service.repository.ContactRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Inject;
import java.util.List;

@Service
@Transactional(readOnly = true)
public class ContactServiceImpl implements ContactService
{
    @Inject private ContactRepository contactRepository;

    public List<Contact> searchContacts(String[] keywords)
    {
        String searchTerm = keywords != null && keywords.length > 0 && keywords[0].trim().length() > 0
                ? "%" + keywords[0] + "%" : "%";
        return contactRepository.findByFirstNameLikeOrLastNameLike(searchTerm, searchTerm);
    }

    public Contact getContact(Long contactId)
    {
        return contactRepository.findOne(contactId);
    }

    @Transactional(readOnly = false)
    public Contact updateContact(Contact updatedContact)
    {
        return contactRepository.save(updatedContact);
    }
}

When a service method is called a new transaction will be created, and in the case of non-read-only methods, when the method exits successfully the transaction will be committed. If the method fails with a runtime exception however, the transaction and all of the database changes made within that method, will be rolled back automatically as you would expect.

Transactions are a pretty fundamental database concept and Spring makes them almost too simple. It’s worth taking some time to read through the Spring documentation to really get a solid understanding of how they work and what you can do with them.

Step 6: Tweak the GUI to allow adding Contacts

Our system is now actually fully configured and you should be able to run both your server and client now without errors. Unfortunately our database is currently empty – in the SimpleContactService we hard-coded a bunch of contacts into it, but with our new database setup we want to add them in manually.

Unfortunately we’ve not yet provided a way to add a contact in our GUI yet so let’s quickly throw this in so we can get some data in there and see our database in action. Luckily, adding is very similar to editing (which we have implemented) so we can reuse this.

First include an add button in ContactSearch.fxml like so:

<HBox spacing="10">
    <children>
        <Label text="Search"/>
        <TextField fx:id="searchField" prefColumnCount="20" onAction="#search"/>
        <Button text="Search" onAction="#search"/>
        <Button text="Add" onAction="#addContact"/>
    </children>
</HBox>

Then add the handler method for this to ContactSearchPresenter, which just delegates onto to the MainPresenter:

public void addContact(ActionEvent event)
{
    mainPresenter.showAddContact();
}

The MainPresenter in turn just shows the ContactDetailPresenter passing in a ‘null’ contact ID to indicate that it is in create mode:

public void showAddContact()
{
    contactDetailPresenter.setContact(null);
    contentArea.setCenter(contactDetailPresenter.getView());
}

Our ContactDetailPresenter doesn’t need to do anything special except handle a null ID being passed in and then not try to load the contact details in this case:

    public void setContact(final Long contactId)
    {
        this.contactId = contactId;
        firstNameField.setText("");
        lastNameField.setText("");

        // only load details if contactId is not null
        if (contactId != null)
        {
            final Task<Contact> loadTask = new Task<Contact>()
            {
                protected Contact call() throws Exception
                {
                    return contactService.getContact(contactId);
                }
            };

            loadTask.stateProperty().addListener(new ChangeListener<Worker.State>()
            {
                public void changed(ObservableValue<? extends Worker.State> source, Worker.State oldState, Worker.State newState)
                {
                    if (newState.equals(Worker.State.SUCCEEDED))
                    {
                        Contact contact = loadTask.getValue();
                        firstNameField.setText(contact.getFirstName());
                        lastNameField.setText(contact.getLastName());
                    }
                }
            });

            new Thread(loadTask).start();
        }
    }

Step 7: Make contact

We now have a fully functional client-server, three-tier system with a persistent database backend. If you run your server and client now you should be able to add new contacts, search for them, and then edit them. When you shut down your server and restart it, all the data you entered should be still available the next time you search. You can even run multiple clients from multiple machines and share your contact information across the network.

You may have noticed that although this is a JavaFX system, we actually did no changes to the client when adding our database. In fact we didn’t touch the ‘client’ module at all. This is very much a design goal of any three tier architecture – the presentation layer should be completely decoupled from the implementation details of the data layer. Mission accomplished on that front!

We’ve finally achieved a truly functional JEE system, covering the core fundamentals of a JEE system. This is still a pretty bare bones application however and there’s a lot more that can be added. In the next few posts we’re going to look at improving that keyword search; hooking our system up to a ‘real’ traditional database instead of our file-based HSQLDB one; and if I can find the time we’ll also add some security, include some validation support, examine the benefits of DTOs, and possibly fix up our client application to better handle threading and errors communicating with the server. If you have any specific topics you’d like to see covered, feel free to post in the comments below.

The full source code for this post can be found at:  http://code.google.com/p/jfxee/source/browse/trunk/first-contact/first-contact-client-db/

Continue Reading→
    • Feb
    • 25
    • 2012

Going Remote – JavaFX and Spring Remoting

Posted by In Uncategorized 6 comments

This entry is part 11 of 15 in the series Building JEE applications in JavaFX 2.0

Because JavaFX is so new to the scene, most of the focus of my previous blogs has been on getting our JavaFX client working cleanly. That’s only a very small part of the JEE puzzle however, and in this post we’re going to start expanding our horizons. We’re going to turn our little FirstContact application into a client-server one, using HTTP as the communication channel.

This post is probably going to be a little more complex than some of my last ones (unless you are already pretty familiar with web services development with Spring and Maven). I’m going to just push through it so as not to get bogged down in the detail. If you get lost on the way, feel free to ask questions via comments.

The full source code for this post can be found here.

Part 1: Split the project into a multi-module Maven project

Where before we had one single desktop application, now we’re going to have two: a client and a server. We also have a bit of code that is shared between these two (i.e. the service interface and data transfer objects sent between client and server), which we need to bundle into both the client and the server.

In Maven this means we need three ‘projects’, one for the client, one for the server and one for the common module shared between them. We could create these three separate projects as stand-alone instances, but it would be nice if we could bundle them all together into one so we can build them as one entity and work with them as one project in our IDE.

Maven’s answer to this is the ‘multi-module project’. If you’re not familiar with these, have a quick google on them. In fact this article here quite nicely explains what we’re about to do to our code so I’ll leave the explanation up to that and just get stuck into it.

First we need to restructure all our old single module code into the following directory structure:

c:\dev\first-contact-client-server

- pom.xml

+ first-contact-client
  - pom.xml
  + src
    + main
      + java
        + com
          + zenjava
            + firstcontact
              + gui
                + detail
                  - ContactDetailPresenter.java
                + main
                  - MainPresenter.java
                + search
                  - ContactSearchPresenter.java
                - FirstContactApp.java
                - FirstContactAppFactory.java
      + resources
        + fxml
          - ContactDetail.fxml
          - ContactSearch.fxml
          - Main.fxml
        - styles.css

+ first-contact-common
  - pom.xml
  + src
    + main
      + java
        + com
          + zenjava
            + firstcontact
              + service
                - Contact.java
                - ContactService.java

+ first-contact-server
  - pom.xml
  + src
    + main
      + java
        + com
          + zenjava
            + firstcontact
              + service
                - SimpleContactService.java

You can see our three modules are nicely contained within a single parent module called first-contact-client-server (you can use whatever name you like for). Additionally we’ve split the code and resources into the appropriate modules, so all the GUI code and FXML files are in the ‘client’ module, whereas the service interface and Contact bean (which are effectively the API onto our server implementation) are in the ‘common’ module, and our simple service implementation is in the ‘server’ module (for now we’re going to keep this simple, but in future posts we’ll look at making this use a database).

All the code and FXML is, at this stage, just a direct copy from our project in the last post, the only change is that we now have four pom.xml files instead of the single file we had before. There’s one pom.xml file for each of the three modules and a parent pom.xml to bundle it all together. Since each of these modules is doing something different, the POMs need to reflect this, so we need to modify each slightly.

First our parent POM. In this we need to let Maven know that we’re using a multi-module project and what modules are contained within. The below will do this (note the use of pom as the packaging type).

c:\dev\first-contact-client-server\pom.xml


<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zenjava</groupId>
    <artifactId>first-contact-client-server</artifactId>
    <name>JFX Contact Management System</name>

    <packaging>pom</packaging>
    <version>1.0</version>

    <modules>
        <module>first-contact-common</module>
        <module>first-contact-client</module>
        <module>first-contact-server</module>
    </modules>

</project>

Next our client POM. This is very similar to our original POM as we are using all the same client side features. The only two significant changes are firstly the reference back to the parent POM (which we just created above), and secondly a dependency onto the first-contact-common module (which we’ll create below) so that our client can use the shared code from there.

c:\dev\first-contact-client-server\first-contact-client\pom.xml

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.zenjava</groupId>
        <artifactId>first-contact-client-server</artifactId>
        <version>1.0</version>
    </parent>

    <groupId>com.zenjava</groupId>
    <artifactId>first-contact-client</artifactId>
    <name>JFX Contact Client</name>

    <packaging>jar</packaging>
    <version>1.0</version>

    <dependencies>

        <!-- First Contact Common -->

        <dependency>
            <groupId>com.zenjava</groupId>
            <artifactId>first-contact-common</artifactId>
            <version>1.0</version>
        </dependency>

        <!-- JavaFX -->

        <dependency>
            <groupId>com.sun.javafx</groupId>
            <artifactId>javafx</artifactId>
            <version>2.0.beta</version>
            <scope>system</scope>
            <systemPath>C:/apps/javafx/javafx-2.0.2_32bit/rt/lib/jfxrt.jar</systemPath>
        </dependency>

        <!-- Spring and supporting toolkits -->

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>3.0.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
        </dependency>

        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>

    </dependencies>

</project>

Our common POM is similar to our client one, however since this contains only basic code with an interface and a data transfer object, we have no need for all the dependencies onto JavaFX, Spring, etc. In fact we don’t want these dependencies because this code will be shared with the server, so there should be no reference to JavaFX or client side libraries in it.

c:\dev\first-contact-client-server\first-contact-common\pom.xml

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.zenjava</groupId>
        <artifactId>first-contact-client-server</artifactId>
        <version>1.0</version>
    </parent>

    <groupId>com.zenjava</groupId>
    <artifactId>first-contact-common</artifactId>
    <name>JFX Contact Common</name>

    <packaging>jar</packaging>
    <version>1.0</version>

</project>

Finally, our server POM. At this stage we’ve just got our very simple service implementation in this project so there’s no need for a lot of dependencies. We just need one reference back to our common module so our server can make use of the classes defined in there.

c:\dev\first-contact-client-server\first-contact-server\pom.xml

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.zenjava</groupId>
        <artifactId>first-contact-client-server</artifactId>
        <version>1.0</version>
    </parent>

    <groupId>com.zenjava</groupId>
    <artifactId>first-contact-server</artifactId>
    <name>JFX Contact Server</name>

    <packaging>jar</packaging>
    <version>1.0</version>

    <dependencies>

        <!-- First Contact Common -->

        <dependency>
            <groupId>com.zenjava</groupId>
            <artifactId>first-contact-common</artifactId>
            <version>1.0</version>
        </dependency>

    </dependencies>

</project>

That’s it, you should be able to open this project in your favourite IDE. In IntelliJ you simply choose File -> Open Project and then select the top-level pom.xml file. IntelliJ is smart enough to handle the multi-module setup and will create a corresponding multi-module IntelliJ project with all our sub-modules configured as you would expect.

Eclipse can definitely also handle this structure although I believe you have to use one of the plugins (m2Eclipse from memory) rather than the default project file generation. NetBeans also looks to have multi-module support (according to this document anyway), but I’ve not used it so can’t comment.

Alternatively you can use the command line to build your project via Maven. If you open a Command Prompt and change directory to where the top-level pom.xml file lives (so in my case that’s c:\dev\first-contact-client-server) then type the following command:

mvn clean install

This will attempt to build all three of our modules and package them into JAR files, one after the other. If the build is successful, the resulting JAR files will be found in the ‘target’ directories under each module (e.g. the client JAR will be at c:\dev\first-contact-client-server/first-contact-client/target/first-contact-client-1.0.jar).

If you run this build right now however, with our project in its current state, you will get a compile error! Our client is still trying to ‘new’ an instance of our SimpleContactService, which now lives on the server so the client doesn’t have access to it (since there is no dependency from the client POM to the server POM). We’re going to sort this all out in the next few steps.

Part 2: Create a web app for the server

Currently our modules are all setup to produce JAR files when built. For the client and common modules this works fine, but our server module is going to be deployed to a web server (i.e. Tomcat) so it needs to be bundled into a WAR file instead.

With Maven this is incredibly easy, all we do is change the ‘packaging’ type in our server POM from ‘jar’ to ‘war’:

<packaging>war</packaging>

Since this is a web application, we also need to supply a web.xml file to be included in the WAR file. We do this simply by adding one to the directory maven expects it to be, which is first-contact-server/src/main/webapp/WEB-INF.

For now we can just use an empty web.xml file, but we’ll add to this shortly:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">

</web-app>

Job done! Next time you run a build (such as mvn clean install from the command line) Maven will assemble a WAR file for us into the ‘target’ directory of the server module, which can be deployed on any servlet engine (such as Tomcat). Of course our webapp doesn’t actually do anything yet, but we’ll sort that out next.

Part 3: Expose our services using Spring’s HTTP Invoker

We have a server, but it’s not really serving anything up yet. We need to expose some ‘web services’ that our client can access and make use of. There are a number of flavours of web services we can choose between here: SOAP is the old timer, a big, heavy, verbose XML-based solution; RESTful is a lighter XML-style approach, whereas Hessian and Spring’s HTTPInvoker are binary based solutions. There’s a whole stack of other options out there too.

The choice of web service toolkit is largely down to your specific project requirements. Each of the frameworks has it’s advantages and disadvantages. The binary protocols, for example, typically have less overhead and can be more performant, whereas the XML-based ones allow for human readability. Some toolkits will work only with Java clients (such as Spring’s HTTPInvoker), some work better for limited-memory mobile devices (such as Hessian or RESTful) and others have additional features (and overheads) for solving complex business-to-business scenarios (such as SOAP).

In our application we have a JavaFX client and a Java server so for my money our best choice is Spring’s HTTPInvoker. It is incredibly simple to setup and use and since it uses Java Object serialization (i.e. our Java beans are just serialized across the HTTP connection) it is very fast and handles all our data types naturally. If we were also looking at supporting non-Java clients (such as an iPhone app) then I’d probably tend towards Hessian.

Luckily there is a toolkit out there that helps us wire in our choice of web service technology and allow us to easily change our mind later: Spring Remoting. This is another optional Spring toolkit, separate to the HTTPInvoker (i.e. you can use one without the other) which allows us to magically switch between many of the popular remoting toolkits just through some configuration changes. This gives us the flexibility to start developing using one toolkit (such as Spring’s HTTPInvoker) and if we find the need, easily switch to another (such as Hessian). The official Spring documentation on this is very good and well worth a read.

Enough pre-amble, let’s get to it. First thing we need to do is get the Spring Remoting jars into our server project. Maven makes this easy once again, we just add the following dependency into our server POM:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>3.0.6.RELEASE</version>
</dependency>

Now we need to expose a Servlet that can handle incoming requests and route them to our service implementation. Spring provides the DispatcherServlet for exactly this purpose, so we can add this to our web.xml file like so:

<servlet>
    <servlet-name>first-contact</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>first-contact</servlet-name>
    <url-pattern>*.service</url-pattern>
</servlet-mapping>

I’ve mapped the above Servlet so that any incoming request ending in .service will be passed on to the DispatcherServlet. You can use any URL pattern you like (such as *.htm or *.do).

Next we need to tell Spring which services to expose. Up until now we’ve managed to get away with using Spring’s @Configuration annotation to avoid writing Spring XML files. This is web-land however, and web-land seems to love XML, so unfortunately we have to slot in at least a little XML to get things happening.

By default Spring will look for an XML file with the same name as the <servlet-name> in our web.xml and with “-servlet.xml” appended to it. So for our above web.xml in order to configure our first-contact servlet, we need to create a file called first-contact-servlet.xml and put this in our WEB-INF directory.

In this XML file we need to tell Spring to instantiate our SimpleContactController class and expose it at a certain endpoint (i.e. web URL). Since we’ve decided to use Spring’s HTTPInvoker, it’s a very simple case of including a HttpInvokerServiceExporter reference in our XML file. Our config looks like this:

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

<beans xmlns="http://www.springframework.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.xsd">

    <bean name="simpleContactService" class="com.zenjava.firstcontact.service.SimpleContactService"/>

    <bean name="/contact.service" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
        <property name="service" ref="simpleContactService"/>
        <property name="serviceInterface" value="com.zenjava.firstcontact.service.ContactService"/>
    </bean>

</beans>

The first <bean> declaration just adds our SimpleContactService to the application context with the name ‘simpleContactService’ so it can be referenced elsewhere in the file. On it’s own, this does nothing as far as our web service is concerned. The bean is loaded into memory, but it’s not accessible on the web yet.

It’s the second <bean> declaration where the magic happens. Here we define a HttpInvokerServiceExporter to expose our service over the web. Spring knows to use the ‘name’ attribute as the end point, so in this case, our service will be accessible via the URL http://your-domain.com/contact.service. If you want to change the end point, all you do is change the name in this config file (just make sure the URL mapping in your web.xml matches the pattern you use).

When the server is running you can actually hit this URL with a standard web browser to call the service – of course it will throw an error because the browser doesn’t know how to handle Java serialized objects but it’s still a useful little test to see if things are wired up correctly.

As well as the ‘name’, we also give the Exporter a reference to the ‘simpleContactService’ that we defined in the first <bean>. This tells Spring to use the simpleContactService to provide all the implementation of the service calls. The HttpInvoker will do all the socket handling and serializing and deserializing for us, and then just delegate the calls onto our nice, Java implementation. Like magic!

There’s one more thing we have to tell the exporter. We have to explicitly specify that we want this service to be accessible via the ContactService interface. This might seem a bit redundant but it’s actually a pretty important security decision. If Spring just exposed every method on the SimpleContactService implementation bean we might accidentally allow web access to private methods that should only be used on the server side. Using a single interface allows us to tightly control what we expose to the big, scary world that is the world wide web, where hackers lurk waiting to take down our every server.

We’re done. Well almost. Because we’re using Spring’s HTTPInvoker, and it uses Java serialization to serialize our data between client and server, we need to make sure our beans are actually serializable. This is a simple case of making our Contact bean implement the standard java Serializable interface like so:


import java.io.Serializable;

public class Contact implements Serializable
{

Exposing our ContactService as a web service was that easy! All you need to do now is either run your web application in your IDE, or use ‘mvn clean install’ from the command line to generate a WAR file that you can then take and deploy to any servlet-based web server. I use Tomcat religiously because it simple and reliable, but there are literally dozens to choose from.

Part 4: Add a little magic

In our previous step, we had to manually declare our SimpleContactService bean in the XML file. In a large project there could be large numbers of these service beans (as well as dozens of supporting beans such as DAOs, etc). Declaring each one by hand can get a bit annoying.

There’s a little bit of Spring magic, called component scanning, that can save us some work in this area. Basically we can set some properties in our Spring XML file to tell Spring to scan our project’s classpath and find any class annotated with @Service (or a few alternatives that we won’t worry about yet) and Spring will then just magically add those to the application context.

Unfortunately there’s no way (that I’m aware of) to avoid defining the HttpInvokerServiceExporter in our XML file so we still have to do this step by hand. I don’t know whether this is a deliberate decision by the Spring guys for security reasons (i.e. they don’t want people accidentally exposing service beans when they didn’t mean to) or whether it was just not thought of. Either way, we’re left with the job of exposing these one-by-one in XML config.

Here’s the Spring config for using component scanning for our beans:

first-contact-servlet.xml

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

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="

http://www.springframework.org/schema/beans


http://www.springframework.org/schema/beans/spring-beans.xsd


http://www.springframework.org/schema/context


http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <context:annotation-config/>

    <context:component-scan base-package="com.zenjava.firstcontact.service"/>

    <bean name="/contact.service" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
        <property name="service" ref="simpleContactService"/>
        <property name="serviceInterface" value="com.zenjava.firstcontact.service.ContactService"/>
    </bean>

</beans>

Then all we have to do is annotate out SimpleContactService class like so:

import org.springframework.stereotype.Service;

@Service
public class SimpleContactService implements ContactService
{

For just our single bean the above component scanning is definitely overkill but as our application grows with more features and more services, this component scanning approach will save us a little bit of XML configuration file mucking around. We’ll see this pay off soon, I promise.

Part 5: Access our services from our client

Our server’s now sitting there eager to accept requests and serve up data, but our client is not talking to it yet. If you look at our old FirstContact code, you’ll remember that the SimpleContactService was created in our FirstContactAppFactory class and then injected into our various Presenters. The Presenters only ever made reference to the ContactService interface and never had any dependency on the underlying implementation being used. This was a deliberate tactic which is about to pay dividends.

Instead of creating a new instance of the SimpleContactService in our client, we can now use Spring Remoting to get a reference to the remote SimpleContactService that’s running on our server. Spring will give us a ‘stub’ implementation of our ContactService interface that uses HTTPInvoker to communicate back to the server, but from our perspective this is virtually invisible – everything is coded to use the ContactService interface so it doesn’t matter whether we’re accessing the local SimpleContactService or using a stub, the rest of our code won’t change at all!

First things first: we have to get the Spring Remoting library into our client module. Additionally we also need the HttpClient library from Apache commons. Spring’s HttpInvoker uses this under the covers to make the connection to the server. Here’s the dependencies to add to our client module’s POM:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>3.0.6.RELEASE</version>
</dependency>

<dependency>
    <groupId>commons-httpclient</groupId>
    <artifactId>commons-httpclient</artifactId>
    <version>3.1</version>
</dependency>

Next we replace the factory method in FirstContactAppFactory (which currently creates our new SimpleContactFactory), to instead create a ‘stub’ onto our server. The code for this is a tad messy because it has been written more for XML-based configuration than Java based config, meaning we have to manually do some factory stuff that XML Spring normally hides. Still it is only a few lines of extra code and it is all nicely hidden away inside our AppFactory doing no harm to anyone.

Our new factory method looks like this:

@Bean
public ContactService contactService()
{
    String serverUrl = "http://localhost:8080/contact.service";

    HttpInvokerProxyFactoryBean factory = new HttpInvokerProxyFactoryBean();
    factory.setServiceUrl(serverUrl);
    factory.setServiceInterface(ContactService.class);
    factory.setHttpInvokerRequestExecutor(new CommonsHttpInvokerRequestExecutor());
    factory.afterPropertiesSet();
    return (ContactService) factory.getObject();
}

Note that I’ve just hard coded the server URL into this class and I’m using localhost on port 8080. This is the default when you are running a local tomcat instance but obviously in a proper distribution you would need to provide a proper URL (e.g. http://yourdomain.com/yourapp/contact.service). It would be trivial to load the URL from a properties file, or there are a number of other techniques that could be used. For now I’ll leave that as something for you to play with.

Part 6: Marvel at our success

We’re done! We’ve just written a working distributed JavaFX application with a web based back-end. You can either run the server inside your IDE (check your IDE’s help for details on how to do this, or post questions below) or you can use mvn clean install to build a WAR file that you can then copy into a Tomcat webapps directory. Your client at this stage is best run through your IDE by launching the FirstContactApp class (down the road we’ll have a look at different ways to build a deployable client bundle).

Since this is a distributed application you can actually run as many instances of the client as you want and they will all talk to the same server instance. You can even run the client from different machines but in this case you will need to change the server URL in the FirstContactAppFactory class to point to the IP address or domain name of the computer running the server.

We’ve made a pretty big step with this work towards a proper JEE application, but you’ll notice that when we start and stop the server, all our data is reset because it is only stored in memory on the server. In the next post we’ll have a look at using a database to store changes long term as you’d expect from a proper JEE system.

The full source code for this post can be found here.

Continue Reading→
    • Feb
    • 20
    • 2012

Porting “First Contact” to Spring

Posted by In Uncategorized 9 comments

This entry is part 10 of 15 in the series Building JEE applications in JavaFX 2.0

In an earlier post we looked at different design patterns for building First Contact, our simple JavaFX-based contact management system. To keep things simple I deliberately avoided using Spring (or Guice) for the dependency injection and instead manually injected all the dependencies. This is great for educational purposes but really we’re doing things the hard way – Spring provides all sorts of magical things for making this easier, so let’s take advantage of them.

We looked at five different design pattern options for implementing First Contact, but moving forward let’s just pick one and work with that. I’m going to go with “Option 4: FXML and the MVP compromise” as it lets us use FXML for the presentation layer, which I think is a big win. Option 5 also uses FXML, but it is based on my third-party framework, JFX Flow and although I’m confident that JFX Flow is a nice little framework to use, I want it to leave it out of the equation at this stage so you can get a good, clean understanding of how everything is working. The pattern used in option 4 is very similar to what Flow expects, so switching between the two should be relatively trivial (and I’ll most likely do a port of our final First Contact app to JFX Flow when we get it all working).

So to give us a base to work off, we’ll make a copy of the source code from option 4, and then we’ll modify this to use Spring for dependency injection. The final source code for this blog can be found at: http://code.google.com/p/jfxee/source/browse/trunk/first-contact/first-contact-spring/.

Step 1: Add Spring dependencies

The first thing we need to do is get hold of the Spring JARs and get them on our classpath. Since we’re using Maven (check out my previous post on using Maven if you haven’t done so already) all we need to do is add the dependencies for the relevant Spring libraries to our pom.xml. Spring is made up of a whole suite of modules that we could use, but our requirements at this stage are quite simple. We just need Spring’s basic ‘context’ module for dependency injection. Since we’re using Spring’s annotation-based configuration (because I hate writing XML if I can avoid it), we’ll also need both the CGLIB module and the standard javax.inject library, which the annotation stuff in Spring makes use of.

We can update our pom.xml to look like this:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zenjava</groupId>
    <artifactId>first-contact-spring</artifactId>
    <name>JFX Contact Management System</name>

    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>

    <dependencies>

        <!-- JavaFX -->

        <dependency>
            <groupId>com.sun.javafx</groupId>
            <artifactId>javafx</artifactId>
            <version>2.0.beta</version>
            <scope>system</scope>
            <systemPath>C:/apps/javafx/javafx-2.0.2_32bit/rt/lib/jfxrt.jar</systemPath>
        </dependency>

        <!-- Spring and supporting toolkits -->

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>3.0.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
        </dependency>

        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>

    </dependencies>

</project>

We’re reaping the rewards of using Maven here – just by adding those few dependencies to the pom.xml, Maven will automatically download the necessary JARs and put them on our application classpath. How easy is that!

Step 2: Simplify the First Contact Application Factory

Without Spring, we had to hand roll our own application factory. If you’ve forgotten what this looked liked, take a moment to look through our old FistContactAppFactory class. In this class we manually created all our beans, kept references to them, and then used setter methods to wire up everything (i.e. give each object access to the other beans it needed). The general pattern was something a little like this:

public class FirstContactApplicationFactory
{
    private SomeObject someObject;

    public SomeObject getSomeObject()
    {
        if (this.someObject == null)
        {
            this.someObject = new SomeObject();
            this.someObject.setSomeOtherObject1(getSomeOtherObject1());
            this.someObject.setSomeOtherObject2(getSomeOtherObject2());
        }
        return this.someObject;
    }

    ...
}

And we repeat this over and over again for each object we want to use. Lot’s of boring, copy-paste code.

With Spring we can get rid of most of this boiler plate code. First we annotate our FirstContactAppFactory class with the @Configuration annotation. This is just a marker, that lets Spring know this class is an application factory capable of providing beans for dependency injection.

Once we’ve done that we can then annotate each of the factory methods with Spring’s @Bean annotation. By doing this, we tell Spring that the resulting object is a bean that can be injected into other classes. We also tell Spring that we want the result of the method to be a singleton (this is the default for all beans in Spring, though you can change it if you want): Spring will then make sure the bean is only created once and the result will be cached and reused for every subsequent method call.

With Spring now doing our singleton caching we can get rid of the manual caching we were doing. Our new pattern looks a little like the following:

@Configuration
public class FirstContactApplicationFactory
{
    @Bean
    public SomeObject getSomeObject()
    {
        SomeObject someObject = new SomeObject();
        someObject.setSomeOtherObject1(getSomeOtherObject1());
        someObject.setSomeOtherObject2(getSomeOtherObject2());
        return someObject;
    }

    ...
}

This has saved us a fair bit of work already, but we can go one step further. Those calls to the setter methods are actually dependency injection, which is what Spring does for us so we can drop those as well (we need to also add some annotations on our Beans for this to work – see the next step). Our new pattern is now as simple as this:

@Configuration
public class FirstContactApplicationFactory
{
    @Bean
    public SomeObject getSomeObject()
    {
        return new SomeObject();
    }

    ...
}

Pretty simple! Below is the source code for the updated FirstContactAppFatcory. All it really does is create all our presenters and return them (using the FXML loader rather than creating a ‘new’ instance, but the pattern is the same). I’ve also dropped the ‘get’ from the method names, this is just a convention thing – Spring tends to leave these off for factory methods (since they are not strictly getters anymore), but you can name the methods whatever you want.

@Configuration
public class FirstContactAppFactory
{
    @Bean
    public MainPresenter mainPresenter()
    {
        return loadPresenter("/fxml/Main.fxml");
    }

    @Bean
    public ContactSearchPresenter contactSearchPresenter()
    {
        return loadPresenter("/fxml/ContactSearch.fxml");
    }

    @Bean
    public ContactDetailPresenter contactDetailPresenter()
    {
        return loadPresenter("/fxml/ContactDetail.fxml");
    }

    @Bean
    public ContactService contactService()
    {
        return new SimpleContactService();
    }

    private <T> T loadPresenter(String fxmlFile)
    {
        try
        {
            FXMLLoader loader = new FXMLLoader();
            loader.load(getClass().getResourceAsStream(fxmlFile));
            return (T) loader.getController();
        }
        catch (IOException e)
        {
            throw new RuntimeException(String.format("Unable to load FXML file '%s'", fxmlFile), e);
        }
    }
}

There’s a whole lot more that Spring can do for us – we are definitely only using the most basic of its features at this stage. For now though, that’s all we need and as you can see it’s made our code significantly simpler and easier to maintain.

Step 3: Inject dependencies using annotations

In the previous step we took away all those explicit setter calls in our factory methods (i.e. the manual dependency injection calls). We need to annotate our beans as well so that Spring knows to inject these classes for us now. For each of our beans, where we were previously calling a set method, we need to annotate the corresponding property instead. In fact, we can get rid of the setter altogether (if you want to leave it in, you can, but I tend to get rid of them) as Spring can access our annotated properties, even if they are private member variables with no getters or setters.

So something like this:

public class MyPresenter
{
    private String myProperty;

    public void setMyProperty(String myProperty)
    {
        this.myProperty = myProperty;
    }

    ...
}

Becomes as simple as this:

public class MyPresenter
{
    @Inject private String myProperty;

    ...
}

Again we’re just removing some of the minor annoying boiler plate code and telling Spring we want it to take care of the dependency injection for us. For some before and after examples, check out the following changes:

Note for long-time Spring users: the @Inject annotation is just the newer standards-based version of @Autowired. They are more or less interchangeable, however using the standards one allows us to change frameworks (e.g. move to Guice) with minimal fuss.

Step 4: Change how the factory is loaded at startup

Our factory and our beans are now all dressed up for the Spring dance, but we’ve still got to kick off the music. In our previous FirstContactApp we were manually instantiating a new instance of our FirstContactAppFactory and then accessing the main presenter by calling getter methods. This isn’t going to give Spring a chance to get in there and do all that magic autowiring stuff for us, so we need to change this slightly.

As you’d expect, the code for this is pretty simple. All we need to do is  use Spring’s AnnotationConfigApplicationContext and let it instantiate our Factory for us so we can then use Spring’s standard bean lookup mechanism to get our fully wired-up beans:

public void start(Stage stage) throws Exception
{
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(FirstContactAppFactory.class);
    MainPresenter mainPresenter = context.getBean(MainPresenter.class);
    mainPresenter.showSearchContacts();
    Scene scene = new Scene(mainPresenter.getView(), 800, 600);
    scene.getStylesheets().add("styles.css");
    stage.setScene(scene);
    stage.setTitle("First Contact - JavaFX Contact Management");
    stage.show();
}

Wrapping it up

That’s all the changes we need to make. If you run your updated FirstContactApp main method, you should see exactly the same GUI as from our previous post. We’ve not changed any of the functionality, just simplified the plumbing and removed a lot of redundant code.

Using Spring to this level has already helped us somewhat but we’ve barely scratched the surface. The main reason I wanted to port this application across is that in my next post I’m going to look at hooking this all up to a database using JPA. Spring is really going to start to pay off in this environment, and after that, when we add Transactions, Remoting and possibly even a dash of Security, we’ll be really making the most of Spring’s power.

Continue Reading→