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

Porting “First Contact” to Spring

Posted by In Uncategorized

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

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

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

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

Step 1: Add Spring dependencies

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

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

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

    <modelVersion>4.0.0</modelVersion>

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

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

    <dependencies>

        <!-- JavaFX -->

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

        <!-- Spring and supporting toolkits -->

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

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

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

    </dependencies>

</project>

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

Step 2: Simplify the First Contact Application Factory

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

public class FirstContactApplicationFactory
{
    private SomeObject someObject;

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

    ...
}

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

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

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

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

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

    ...
}

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

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

    ...
}

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

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

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

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

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

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

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

Step 3: Inject dependencies using annotations

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

So something like this:

public class MyPresenter
{
    private String myProperty;

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

    ...
}

Becomes as simple as this:

public class MyPresenter
{
    @Inject private String myProperty;

    ...
}

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

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

Step 4: Change how the factory is loaded at startup

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

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

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

Wrapping it up

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

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

Continue Reading→
    • Feb
    • 17
    • 2012

JavaFX and Maven

Posted by In Uncategorized

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

For JEE application development, Maven is, in my opinion, a requirement. Sure you can use Ant, and that will give you more ‘control’ over you build, but you’ll be spending a fair chunk of time managing your build scripts – time that you could spend actually building your application. The two big reasons you want to use Maven for your JEE build are:

  1. Dependency management: Maven provides a free, web-hosted central repository which contains just about every major distributable toolkit out there. When you use Maven, you simply specify the toolkits you want to use and the version numbers, and Maven will automatically download the jars you need and setup your classpath.
     
  2. Minimal configuration build: Maven uses “convention over configuration”, which means if you follow its directory structure and naming conventions, you can avoid writing massive amounts of XML config. When assembling WAR or EAR files, which have some funny rules regarding WEB-INF directories and the like, Maven just makes all of this simple.

I’m not going to waste time selling you further on this (a quick web search will find you hundreds of articles comparing Maven to other build tools). What we’ll do here now is step through how to create a Maven project for running JavaFX applications. In this post, I’m only going to get us to the stage where we can run a simple, pure-client JFX app in out IDE, but we’ll grow on this later to build multi-module projects with client and server components, and include ways to build JNLP deployment bundles for web deployment.

Step 1: Download and install Maven

You can get the latest version from here: http://maven.apache.org/download.html. It’s just a zip file and doesn’t need any special ‘installing’. I usually just grab the latest ‘Binary Zip’ and extract it locally. I tend to put all my applications (like Tomcat, Maven, Java, etc) under c:\apps (on windows) as this makes it real easy to type on the command line if I ever need to.So for me, I unzip Maven to in c:\apps\maven\maven-3.0.1 but you can do whatever you like.

Once you have unzipped it, the only thing needed to install it is to add a system variable called ‘M2_HOME‘ that points to the directory you just unzipped to, and then update the PATH variable to include ‘%M2_HOME%\bin’. If you run into any trouble with this, check out this very detailed installation guide:http://www.sonatype.com/books/mvnref-book/reference/installation.html

Step 2: Create an empty project folder

Most IDE’s will generate you a skeleton Maven project these days, and Maven itself has the concept of project templates (called ‘archetypes’) that you can use to quickly generate a ready-to-use project structure but we’ll give these a miss in this round so you can see just how little magic is actually needed.

We need to create a new directory to house our project, Maven doesn’t care where we put this directory.  I tend to use c:\dev for all my projects (again because it is easy from the command line), so if we’re creating a project called ‘MyJfxProject’, I would put it in a folder called c:\dev\myjfxproject.

Step 3: Create an initial POM file

The heart of every Maven project is the POM (or Project Object Model). This is just an XML file called  ’pom.xml‘ that lives in the base directory of your project. It tells Maven what features you want to use in your build (e.g. are you building a JAR or a WAR). Unlike an Ant build script however, this file is generally pretty light however, there’s a lot Maven can work out just from your project structure.

At a minimum we need to tell Maven three pieces of information: our group ID, which is typically your domain name (so I use ‘com.zenjava’), our artifact ID, which is just the name of our project (so in this case we’ll use ‘myjfxproject’) and the version, usually it’s good to start with version 1.0. You can also do some cool stuff with snapshot versions, but we won’t get sidetracked with them right now. Here’s how our initial pom.xmlshould look:

<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zenjava</groupId>
    <artifactId>myjfxproject</artifactId>
    <version>1.0</version>

</project>

Step 4: Create our source file structure

Maven requires us to follow its convention for structuring our project. It doesn’t matter where our project base folder is, but within this base folder we need to use the Maven hierarchy. There is a lot to this, but we just need a place to store our Java files at the moment, Maven requires us to put these in the directory src/main/java. Any Java files in that directory will be automatically compiled and included in our resulting build.

You can (and should) use sub-directories to get packages like normal. In my case I use the base package com.zenjava, but you should use a domain that suits you (your registered web domain is best, but if you don’t have one, just make up something sensible – not using a package structure is bad form).

We will also want some non-Java resources (such as properties files, images, CSS style sheets and FXML files) included in our project. Maven requires us to put these in the directory src/main/resources. Any files in these directories will be automatically included in our final JAR. You can use whatever directory structure you want within the resources directory, I typically create a directory for each resource type. So our initial directory structure should look something a little like the following.

c:\dev\myjfxproject

- pom.xml
+ src
  + main
    + java
      + com
        + zenjava
          + myjfxproject
            - MyJfxProjectApp.java
    + resources
      + fxml
        -  (FXML files)
      + images
        -  (image files files)
      + styles
        -  (CSS files)

Step 5: Add JavaFX as a dependency 

In the introduction of this blog, I made the bold claim that the Maven repository “contains just about every major distributable toolkit out there”. There’s one notable exception to this however: unfortunately and frustratingly, JavaFX is not in there!

There’s a couple of reasons for this. Firstly, there’s a licencing issue. Somewhat disappointingly Oracle has used a licence that allows us to redistribute JavaFX but only if as part of a bigger application. You can’t just redistribute the JAR on it’s own. Putting the JFX JAR in any public Maven repository would blatantly violate this licence. Oracle’s not likely to change this unfortunately, but once JavaFX is fully open sourced into the OpenJDK project (sometime this year, I believe) we should be able to get around this.

The second reason is a technical one. JavaFX uses a number of native files (e.g. DLLs on windows) and Maven does not handle native files overly well. Native files need to be added to the java system path, whereas Maven’s whole dependency management is focused around the more common java classpath. Other libraries that use native files have found ways around this (such as the JOGL toolkit), but to support this the actual libraries themselves have to load their native files in a certain way, which the JavaFX guys are not doing (and as yet, are not intending to do). JavaFX requires its native files to be in a relative subdirectory (namely rt/bin), and Maven just doesn’t support this.

So this seems like a bit of a show stopper: if we can’t add JavaFX as a Maven dependency we can’t use JavaFX in Maven. Fortunately there are a couple of hack options we can use to cludge around this problem. None of the options are perfect and they all sacrifice some of the niceness that we expect when using Maven, but the cludges are just good enough to get us through and still take advantage of the other great features that Maven offers.

The easiest option, and my recommended approach, for getting a JavaFX dependency into Maven is to use the ‘system‘ scope. If you’re a regular Maven user, you may not even be aware this exists (I wasn’t) as it is very rarely used. This special scope allows you to specify a system path, which can reference the JAR file on your local system, rather than downloading it from the central repository. Maven no longer provides version management and automatic updates for us, but our native issue is resolved because we can reference the jar in its default installation location, which has the natives files relative to it.

To do this you first download and install the JavaFX SDK as per normal. Then you just add a dependency like the following to your POM (change the system path to point to your JFX installation directory):

<dependencies>
    <dependency>
        <groupId>com.oracle</groupId>
        <artifactId>javafx</artifactId>
        <version>2.0</version>
        <scope>system</scope>
        <systemPath>C:/apps/jfx2.0/rt/lib/jfxrt.jar</systemPath>
    </dependency>
</dependencies>

The groupId, artifactId and version are actually arbitrary in this case (you can put whatever you like in there). Normally Maven would use these to find the JAR in the central repository but because we’re specifying the JAR with the ‘systemPath’, Maven will ignore these other values.

Several alternate options exist for getting Maven and JavaFX to play nicely together but the above is the simplest and easiest. Probably the most powerful alternative is to use a “pre-loader” that extracts the native files from a JAR file installed into Maven when your application runs (the JFXtras project has code in it to assist with this). If you’re not wanting to take advantage of the JFX/JNLP deployment tools (more on this in future posts) then this can be a good option for bundling JFX in your final JAR. There’s a fair bit of work involved in assembling and maintaining the native JAR bundles however, so I personally tend not to use this approach.

It’s my hope that through a few of us working with the JFX team on this Maven issue that we’ll end up with a much cleaner solution for this in the future. There’s not a great deal of Maven experience in the JFX team however so it is slow going, and the future plans to co-bundle JFX with the JDK are also an influencing factor in this discussion. If JFX ends up in the JDK then version management and distribution will be intimately linked between these two taking Maven out of the game altogether (adding a whole new bucket of versioning and deployment complexities). There’s work to be done here still.

Step 6: Open your project in your favourite IDE 

We now have a fully operational JavaFX project and we can open this in our IDE. I use IntelliJ, which has fantastic, built-inn support for Maven. I simply go to File -> Open Project and then select the pom.xml file for my project. The result is a ready to run project with the classpath all set to include my source code, resources and third party libraries (in this case we’ve only added JavaFX but you can add as many dependencies as you like). I can also edit my POM file whenever I like (to add dependencies for example) and IntelliJ will automatically download the corresponding JAR files and update the classpath instantly.

I know that Eclipse also has strong support for Maven, as I have often worked with developers using Eclipse while I was using IntelliJ on the same project (which is another advantage of using Maven). I’m not totally up on the steps to getting this working but you should be able to find more info here: http://www.eclipse.org/m2e/

Additionally NetBeans also has support for Maven. Again I am not sure of the exact details, but this wiki seems to provide the right sort of information: http://wiki.netbeans.org/MavenBestPractices

If anyone has experience in using Maven with either Eclipse or NetBeans (or any other IDE out there), please post additional information in the comments below.

Step 7: Build your JAR file

With just this simple POM setup, we can now quickly and easily build the JAR file for our application. You can usually do this via your IDE, but using the command line is just as effective. On windows open a Command Prompt (Start -> Run -> cmd), then change directory into your project home directory (e.g. cd  c:\dev\myjfxproject) and type the following command:


mvn clean package

You will see a whole lot of log that should finish with “BUILD SUCCESS”. Assuming you get to this point, then the jar file containing all of your application code and resources can be found in the newly created ‘target’ directory. You can take this jar and use it as normal.

Beyond the basics

Building a single JAR file is pretty cool, but generally we will want to build a ready to run deployable application. We can use Maven to do all sorts of wonderful things, including building web deployable JNLP based deployment bundles and applets, as well as executable jars containing third party dependencies. Not to mention generating JavaDoc, automatically running unit tests, creating full project documentation and much, much more.

This does get quite a bit more complex however, and this blog post is already too long, so I will leave these more advanced topics to later. We’ll weave some deployment options into our future posts, especially when we look at building WAR files for our JEE-based server.

If you’re desperate for more info on a more complete JNLP-based deployment build process and you’re feeling comfortable with Maven then you can find some workable options buried in this forum discussion. As always, feel free to post further questions in the comment section below, or post on the JFX forum if you have more general questions.

Continue Reading→