Ok, due to popular demand, I’m going to fast track a bit of this walk through. I had planned to do more on the client end first, but it seems everyone wants to know how to build a client-server app (apparently that Internet thing has really taken off).

So in this post we’re going to build a very simple hello world client-server application, using HTTP. We’re going to use Hessian to make all our client-server communication nice and easy. There are a whole load of other communication options out there but Hessian is simple, lightweight and just works.

By the looks of it people are favouring Guice over Spring at this stage, due to the concept of it being ‘lightweight’. As such, I’m going to stick with Guice as our DI toolkit for the front-end. In later posts we’ll have a look at changing over to Spring, which really starts to show its advantages when we start working with database transactions and security.

This topic is a little more in-depth than some of the previous stuff. If you’ve never written a servlet or basic web application before, you may want to brush up on this first. Also, we’re going to use some JavaFX threading which is only lightly documented at this stage, and the API is just a little raw still too in my opinion. It may be a bumpy ride for some.

Step 1: Design your application

We’re going to keep things as simple as we can. We will have a simple client that allows the user to enter their first and last name. The client will then pass these details to the server and the server will return a simple welcome message based on the name entered.

If we get everything right, our client will end up looking like the following:

Step 2: Create a Service interface

The great thing about Hessian is that it allows us to define our client-server protocol in pure Java objects. It works in a very similar way to RMI, where you define an interface for your server, which your server implements and client accesses. Hessian then provides the magical wiring underneath our interface to serialize our data and send it (over HTTP) to the server, where it gets deserialized and passed into our server implementation. Pretty sweet.

For our example, our service interface is very simple and looks like this:

public interface HelloService
{
String sayHello(Person person);
}

This is our ‘contract’ between the client and the server. The client will call the sayHello method and the server will implement it.

We could pass two strings into the sayHello method for the first name and last name, but to make things a little bit interesting and show the power of Hessian, I have chosen to encapsulate all this in a Person bean. Hessian will magically handle all the serialization for this.

Our person bean is a standard serializable Java bean and looks like this:

Step 3: Create a Service implementation

Now that we’ve defined the contract between our client and server, we need to have our server fulfill that contract. We’re keeping things simple in this example: our server will simply build a message out of the Person details and send this back to the client. In a real world application, your server will likely hit a database, provide some security and do all the other things that a serious application does, but we won’t worry about that here.

Our service is just another Java object that implements the HelloService interface we defined above. The only special thing about it is that it extends HessianServlet, which is a custom servlet provided by the Hessian platform. All the magic happens in here and by simply extending it we have a ready-to-roll server implementation. Too easy.

Step 4: Run your server as a web application

The next step is to publish our service as a web service. I’m going to assume you are at least a little familiar with creating normal servlets and building webapps. If not, you probably want to google these topics – there’s a wealth of information out there on this, just ask Google.

To publish our service we create a web.xml that loads our HelloServiceImpl as a servlet. The HelloServiceImpl is no different to any other servlet and can be exposed in exactly the same way:

The resulting war file can be deployed to any servlet friendly server. I use good old Tomcat but you can use Jetty, Resin or any of the other free ones out there. If you’re insane, you can pay for one of the commercial JEE servers (but really, don’t bother).

Step 5: Create a view and controller

Our server is now deployed and running, and we’re ready to build our client. The first part is easy, we just build a GUI to service our needs. I’m going to use the same Guice + FXML approach as in my last post but you could use the Spring approach, or even roll it all by hand and use no Dependency Injection at all if you’re into an old-fashion style.

Step 7: Use Guice to load the UI and inject the service

In order for our client to connect to the server, all it needs to do is use the HelloService interface we created earlier and use Hessian to load this. The following code will do the trick:

HessianProxyFactory factory = new HessianProxyFactory();
String serverUrl = "http://localhost:8080/hello";
HelloService helloService = (HelloService) factory.create(HelloService.class, serverUrl);
// use the helloService object now and hessian will magically make the calls on the server for you

This is basic Hessian stuff – we use the HessianProxyFactory to create a new instance of our HelloService for us, passing in the URL of our server. The factory then creates a ‘proxy’ (in this case, you could call it a ‘stub’), that implements the interface by making HTTP calls onto the servlet on the server side. The Proxy and the servlet work together to serialize the data between each other and make the actual call on the server. From our end, it’s all just nice simple Java.

We could create this proxy anywhere in our code and use it via plain Java calls and for this simple little scenario that would do the job. In our last post however we looked at ways to use Guice to load our controllers and provide Dependency Injection and this is a great candidate for this. As our project gets bigger and we end up with more controllers wanting to use more services, this DI is really going to pay off.

In order to inject our service using Guice, we first add the following line to our HelloController:

@Inject private HelloService helloService;

And now we can just wire up everything in our Guice module. I’m going to use instance injection in this case, but you could use the provider style approach just as easily. The instance injection approach looks like so:

Now that the call to sayHello() is actually a remote call to a server it could be slow. Depending on the network speed it could take seconds for the client and server to do all the socket and serialization work. Java FX (like Swing) uses a single thread for application processing. If we lock this thread up waiting for the server to respond then our UI will become unresponsive as the application thread won’t be able to process mouse moves or even redraw the screen (this is a slight simplification of how threads and rendering work in JFX but from our point of view this is enough for us to know).

As well as the threading issue, we’ve also introduced a lot more room for things to go wrong: the server may be down, the client may have lost internet connection, the wrong URL may have been entered, etc. These will all be thrown as runtime exceptions so we could just ignore them and have the system crap out but this is not very nice for our users. Ideally we need to start handling these errors and show the user a friendlier message, such as “Hey mate, did you forget to plug in your network cable again?”, so they can actually do something about it and try again.

Fortunately JFX has an answer to both of these problems, and that answer is the Worker/Task/Service framework. Unfortunately this is not a simple toolkit to use (although if you are familiar with SwingWorker you will have a good head start) and even more unfortunately there is extremely little documentation on this as yet. The only real guide that I’ve found is this post from Richard that uses an early version of the framework while still in beta. The API has been tidied up a little since and Richard also neglected to give us too much detail on how to actually handle the response from the server, or handle errors.

We can muddle through it however, and by piecing all the bits together here’s a threading approach that works:

We also have pretty simple exception handling here. Ideally we would check the type of the Exception thrown and provide an error message to match. To do this we just use a big if-else statement and instanceof like so:

A note on building, deploying and running

Above are all the bits and pieces we need for our client and server communication and if you’re familiar with web applications and this style of development that’s probably all you need to know. Simply deploy your generated WAR file to your web server, edit the URL in the client to match and then run HelloApplication. Sorted.

For anyone who is not familiar with this stuff however, there are a few gotchas to be aware of when it comes to deploying and running. Firstly is how to package all of this up. You have two separate applications now, a client and a server, but they both share the common service API. You could bundle all the classes together and deploy it this way if you’re being lazy, but you should really separate them to avoid bloat, especially the client which typically is downloaded.

In my setup, I have one module (bundles into a jar) for the ‘common’ code, which includes the HelloService interface and the Person bean. Then my ‘client’ module has all my client code (bundled into a jar) and my ‘server’ module has all my server code (bundled into a war). The client and server then reference back to the ‘common’ module as if it were a third party library. It’s a little more complicated but it is the cleanest separation – you are free to make your own setup work for you.

When you deploy your web application the server will have a base address (such as http://zenjava.com) where the server (e.g. Tomcat) is running. When you run locally this address will typically be http://localhost:8080. Depending on how you deploy your WAR file it may then be allocated a sub-domain. In Tomcat for example, if you name your WAR file ‘helloserver.war’ and then put this into Tomcat’s ‘webapps’ directory, the URL you will need to use in your HelloClientModule is “http://localhost:8080/helloserver/hello”.

Ultimately you will likely want to deploy your client via webstart and then you will want it all bundled into your server (but not on the server’s classpath just for some added complexity). I’m not going to confuse people further with this here, if you can’t work out the packaging side of it yourself just run the client from within the IDE for now. I am planning to post something on doing this sort of complex deployment using Maven (our best friend in this situation) in a future post.

The above is hopefully enough to get you started on the road to developing client-server Java FX 2 applications over the web.

15 Comments

Very nice series, and extremely instructive. Would you consider repurposing this material for a series of technical articles on JavaFX and Java EE on the Oracle Technology Network (OTN) or Java Magazine? You can contact me on Twitter (@javafx4you) or by email javafx4you at sun dot com (yes those email addresses still work)

John Smith

November 3, 2011

Very, very nice post. It is so good to see new work on taking the mountain of experience in server side Java and better integrating with client side Java.

Very nice post. Since I was trying JavaFX on Linux, I used this as second test to see if wine could communicate with linux.

Marco

September 4, 2012

this post is very interesting, tank you,
i had try to deploy it with intyellj IDEA and Maven with the same directory and files, but i see an error that i can’t fix in the IDE:
In the file HelloClientModule, in the catch field, there are two instructions where appear “String.format” and my Ide say: cannot resolve the metod “format(java.lang.String)”.
I had remove the argumets of the RuntimeException and type at the command line “mav clean package”
but the application in the target folder don’t work…
what’s my error ?
thank you very much

Daniel Todt

September 11, 2012

Hello, I found your article very interesting.

However, I have some problems to run the jfxee7.

I’m running on JBoss, to test, and shows nothing, does not load the GUI.

Is there anything that is not on that source from SVN?
Well I just downloaded the source, I changed the path and name of the JavaFX war after build.

I’m trying to make a JavaFX application running in the browser from a web application that is running on the JBoss.

Howdy! I know this is kinda off topic nevertheless I’d figured I’d ask.
Would you be interested in trading links or maybe guest authoring a blog
post or vice-versa? My site discusses a lot of the same topics as yours and I feel we could greatly benefit from each other.
If you happen to be interested feel free to shoot me an e-mail.
I look forward to hearing from you! Great blog by the way!