• Feb
    • 25
    • 2012

Going Remote – JavaFX and Spring Remoting

Posted by In Uncategorized

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→
    • Mar
    • 19
    • 2012

JavaFX and persistence: adding database support

Posted by In Uncategorized

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→
    • Mar
    • 20
    • 2012

Search like you mean it

Posted by In Uncategorized

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
    • 23
    • 2012

Captains Log

Posted by In Uncategorized

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
    • 27
    • 2012

JavaFX and Spring Security

Posted by In Uncategorized

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→