tiainen

March 01, 2011

Load balancing with Glassfish 3.1 and Apache

Glassfish 3.1 was released on February 28th. This is the first application server that supports Java EE 6 in a clustered and high available environment. We at LodgON have a high interest in this, as Johan Vos already mentioned in his blog and we are eager to find out how easy it is to configure Glassfish to let it run multiple instances using Apache as a load balancer. I'll describe the steps I had to go through for setting up the following configuration:

  • machine1: Glassfish DAS, 1 instance, Apache HTTP server with mod_jk enabled

  • machine2: 1 instance


Configuring the nodes



Install Glassfish 3.1 on machine1. Once that is completed, we need to setup ssh so we can manage node machine2 centrally from machine1. So on machine1 enter the following command:

$ asadmin setup-ssh machine2


This is basically a frontend for the ssh-keygen tool. It will ask for the password of your user on machine2 and copies the necessary keyfiles over to that machine. We are now ready to install glassfish on machine2 by using the install-node command:

$ asadmin install-node --installdir /opt/glassfish3 machine2


This copies glassfish over to the node with the host name specified in the last parameter and installs it in the specified installation directory. I encountered a problem where it said that the command jar was not found. To resolve this in Ubuntu, make sure you specify java in your PATH in ~/.bashrc before the following lines:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return


Everything after these lines will not be executed when logging in with an non-interactive shell like in our case, via ssh.

Now we can start the DAS on machine1 and begin configuring our instances.

$ asadmin start-domain


Configuring the cluster



We will now create a remote and a local instance into one cluster. We will first let the DAS know that we have another node on machine2 that we want to use by creating an ssh node:

$ asadmin create-node-ssh --installdir /opt/glassfish3 --nodehost machine2 node1


After that we can create the cluster and add two instances to it: one remote instance on node node1 and a local instance on the local node. This local node, with name localhost-domain1, is automatically available when installing glassfish.

$ asadmin create-cluster cluster1
$ asadmin create-instance --cluster cluster1 --node node1 inst1
$ asadmin create-instance --cluster cluster1 --node localhost-domain1 inst2


We can now start the cluster and deploy an application into it. It doesn't really matter which application you want to deploy. I will use a simple application containing only 1 jsp (download the application):

$ asadmin start-cluster cluster1
$ asadmin deploy --target cluster1 --name simple simple-application.war


When deploying, you specify our cluster1 as the target. This will deploy the application into every instance that was added to the cluster. When deployment was successful, you should be able to browse to the application using the following URL: http://machine2:28080/simple. It should also be running on the second instance at the following URL: http://machine1:28081/simple.

Configuring the load balancer



We have both instances running our application, so now we can start configuring Apache to run as the load balancer. To let Apache connect with Glassfish, you'll have to use the mod_jk module. Installing it in Ubuntu is very easy:

$ sudo apt-get install libapache2-mod-jk


Once the module is installed, create a file called jk.conf in the mods-available directory in your apache configuration directory (mine is located in /etc/apache2/mods-available) and link it into the mods-enabled directory.

$ sudo touch /etc/apache2/mods-available/jk.conf
$ sudo ln -s /etc/apache2/mods-available/jk.conf /etc/apache2/mods-enabled/jk.conf


In that file you can copy the following configuration:

JkWorkersFile /etc/apache2/worker.properties
JkLogFile /var/log/apache2/mod_jk.log
JkLogLevel error
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
JkRequestLogFormat "%w %V %T"


The first line specifies the location of the workers file in which we will configure our Glassfish instances. So, create the file in the directory /etc/apache2 and add the following properties:

worker.list=worker1,worker2,loadbalancer

# default properties for workers
worker.template.type=ajp13
worker.template.port=28009
worker.template.lbfactor=50
worker.template.connection_pool_timeout=600
worker.template.socket_keepalive=1
worker.template.socket_timeout=300

# properties for worker1
worker.worker1.reference=worker.template
worker.worker1.host=machine1

# properties for worker2
worker.worker2.reference=worker.template
worker.worker2.host=machine2

# properties for loadbalancer
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=worker1,worker2


Finally, in the default virtual host configuration file (on my machine this is located at /etc/apache2/sites-available/default) we add a line to tell mod_jk which URLs have to be forwarded to the load balancer:

JkMount /simple/* loadbalancer


You can read more about all these configuration directives and properties on the website of the Apache Tomcat Connector:


When you are done with this, we restart the Apache HTTP server to let the settings take effect:

$ sudo apache2ctl graceful


Finally, we need to add a HTTP listener in the Glassfish cluster that will listen for the calls from mod_jk. As we specified in the workers.properties file, this listener will be listening on port 28009. Adding this listener works with the following command:

$ asadmin create-network-listener --protocol http-listener-1 --listenerport 28009 --jkenabled true --target cluster1-config jk-connector


Restart the cluster and we should be able to connect to our application through Apache at the following URL: http://machine1/simple.

$ asadmin stop-cluster cluster1
$ asadmin start-cluster cluster1


Conclusion



You can see that it was quite easy to set up a clustered Glassfish with Apache running as the load balancer. You might want to watch the following video about the new features in Glassfish 3.1. It might give you a bit more insight in the way that clustering and load balancing works. It will also show you that you can configure everything by using the admin website (running at port 4848) instead of using the asadmin command as I did in this blog.

May 02, 2010

Isometric tile rendering in JavaFX

1) Introduction


I'm currently working on a strategy game in JavaFX and decided to use isometric projection for rendering the graphics. During development I encountered some performance issues specific to JavaFX 1.2. It was expensive to add many nodes in a single Group and it was furthermore expensive to add/remove a lot of nodes from a Group.

The first issue was resolved by having more levels of Groups. Instead of 1 Group containing all the nodes, I added several layers of Groups. Each Group in the bottom layer would then only hold a small portion of all the nodes.

Resolving the second issue was done by using a quadtree to quickly decide which nodes should be added and which nodes should be removed from the scene graph. This way I only had to add/remove a small portion from the scene graph during the render pass.

Of course, a few weeks ago, Oracle released JavaFX 1.3, which magically solved all these problems by itself. Rendering many nodes in one Group no longer was a problem. However, having the quadtree structure still has a major advantage. You only need to render the nodes that are actually visible on the screen. This should eat a lot less memory then when you would render all the nodes in your world. So, I'm still going to show you how I've done the quadtree implementation.

2) Brute force rendering


Before going over to using quadtrees, I will first show you the easy way: rendering all tiles in a brute force manner. My game world consists of a series of tiles laid out in a two-dimensional grid. Each tile has an X and a Y position to store it's position within that grid. Rendering brute force means that we will render all the tiles in the game world, even when they are not visible on screen.

var scene : Scene = Scene {
width : 1000
height : 800
content : BruteForceRenderer {
tilesWidth : 512
}
}

Stage {
scene : scene
}

def TILE_WIDTH = 32;
def TILE_HEIGHT = 16;

public class BruteForceRenderer extends CustomNode {
postinit {
var numberTiles = Math.pow(tilesWidth, 2);
tilesGroup.content = [
for (i in [0 .. numberTiles - 1]) {
var x = (i / tilesWidth) as Integer;
var y = (i mod tilesWidth) as Integer;
Polygon {
points : [ TILE_WIDTH / 2, 0.0, TILE_WIDTH, TILE_HEIGHT / 2, TILE_WIDTH / 2, TILE_HEIGHT, 0.0, TILE_HEIGHT / 2 ]
translateX : TILE_WIDTH / 2 * (x - y)
translateY : TILE_HEIGHT / 2 * (x + y)
fill : Color.GREEN
}
}
];
}

public-init var tilesWidth : Number = 64;

var tilesGroup : Group = Group {};

override protected function create () : Node {
tilesGroup
}
}

The BruteForceRenderer is a CustomNode that contains one Group in which all the tiles are rendered. The tilesWidth parameter defines how wide our grid must be. A value of 8 for instance means that we will have a grid that contains 64 tiles in total.

The tiles themselves are made up of a Polygon with a green color. They are added one by one into tilesGroup. The order in which the tiles are layed out is from top to bottom and from right to left. The following image, which is a render of 9 tiles, probably clarifies this a bit. The numbers between the brackets are the x and y coordinate of the tile that is being rendered.


The main advantage for using the brute force approach is that the code remains very simple to understand. The disadvantage will become clear when you start raising the tilesWidth parameter. Even though they've made lots of performance improvements in JavaFX 1.3, it's still becoming a bit sluggish for instance when implementing mousedragging to move around the world.

3) Using a QuadTree


With brute force rendering, we keep track of all tiles whether they are visible on screen or not. However, we should only render a tile when it is actually visible on the screen. On the next image we can see the tiles in green and our screen in blue.


This clearly shows how brute force rendering is done: all tiles are visible, even those that do not fall within the blue rectangle. To solve this, before rendering a tile, we could check to see if it's bounds fall within the screen view or not. The easiest way to do this is to check all the tiles one by one. However, a more elegant solution is to use a quadtree. A quadtree allows us to quickly discover which nodes are actually visible on screen without having to check every possible node.

The process is as follows:

  1. divide the world space into four equally sized squares

  2. for every square, check if it's bounds intersect with the screen bounds
    • if they don't intersect: skip this square

    • if they do intersect: divide this square into four equally sized squares and repeat step 2


We keep dividing until we reach a specific depth. When this depth is reached, we will just individually check all tiles that are still available and render those that fall within the screen. Again, I'll use an image to make this more clear.


Step 1 divides the world into 4 squares. We check the bounds of square 1 and see that it intersects with the screen bounds (again the blue rectangle). In step 2 we divide this square again into 4 squares and check the bounds of square 1. We see that it doesn't intersect with the screen, so we check square 2. This time we have an intersection. So again, in step 3, we will divide this square number 2 into 4 equally sized squares and repeat our intersection checks. We can clearly see that square number 1 doesn't intersect, but square number 2 does.

At this moment we have reached our maximum depth of 3. So instead of dividing this last square into 4 smaller squares, we will go over the nodes that are contained in this square and perform the bounds check on each of these nodes. If a node intersects it will be added to the scene graph, otherwise it will be skipped. This is shown in step 4.

Below is a sample of this application rendering a world containing 256 by 256 tiles. You can also download the code as a NetBeans project.


March 20, 2010

Beware of JavaFX and null references

Yesterday I was trying to implement a simple Animation class, that could for example be used for animating sprites in a game. I wrote the following code:

public class Animation extends ImageView {
var index : Integer;
public-init var images : Image[] on replace {
timeline.start();
}

var timeline : Timeline = Timeline {
repeatCount : Timeline.INDEFINITE
keyFrames : [
KeyFrame {
time : 0.2s
action : function() {
if (index + 1 >= images.size()) index = 0 else index++
}
}
]
}

override var image = bind images[index];
}


Let's now create an Animation object as follows:

var animation : Animation = Animation {
images : drillingWell
}


You might expect that this would work just fine and that the program would display an animation of a drilling well. Since we are assigning the sequence drillingWell to Animation.images, this would call the on replace trigger. Which it does. However, during object instantiation the timeline variable is still null. This means that calling timeline.play() won't have any effect because JavaFX quietly ignores null references. Throwing a NullPointerException here would have saved me quite some time and work ;-).

To fix the code I had to assign the timeline in the on replace trigger itself, like this:

public class Animation extends ImageView {
public-init var images : Image[] on replace {
Timeline {
repeatCount : Timeline.INDEFINITE
keyFrames : [
KeyFrame {
time : 0.2s
action : function() {
if (index + 1 >= images.size()) index = 0 else index++
}
}
]
}.play();
}

var index : Integer;
override var image = bind images[index];
}

February 18, 2010

Using Jersey to (un)marshall Java objects

When developing a REST API in Java, it is straightforward when you do that using Jersey. At least when implementing the server side. For instance, we can have the following methods to manage a Foo object:

@GET
@Path("{fooId}")
@Produces("application/xml")
public Foo getFoo(@PathParam("fooId") int fooId) {
return FooBean.getInstance().findFoo(fooId);
}

@GET
@Path("/list")
@Produces("application/xml")
public List<Foo> getFoos() {
return FooBean.getInstance().findAllFoos();
}

@PUT
@Produces("application/xml")
public Foo putFoo(@FormParam("name") String name, @FormParam("bar") String bar) {
Foo foo = new Foo();
foo.setName(name);
foo.setBar(bar);
return FooBean.getInstance().createFoo(foo);
}

@POST
@Path("/{fooId}")
@Produces("application/xml")
public Foo updateFoo(@PathParam("fooId") int fooId, @FormParam("name") String name, @FormParam("bar") String bar) {
Foo foo = FooBean.getInstance().findFoo(fooId);
if (foo != null) {
foo.setName(name);
foo.setBar(bar);
return FooBean.getInstance().updateFoo(foo);
}

return null;
}

@DELETE
@Path("/{fooId}")
public void deleteFoo(@PathParam("fooId") int fooId) {
FooBean.getInstance().deleteFoo(fooId);
}


The Foo class must be annotated with @XmlRootElement, otherwise Jersey won't know how to marshall the object into XML or JSON.

@XmlRootElement
public class Foo implements Serializable {
private int id;
private String name;
private String bar;
...
}


Recently I discovered that you can also use Jersey when developing client applications that make use of a REST API. The Jersey Client API, as it is called, can be used to easily produce and consume REST requests and responses. The code below shows a quick overview of how to call the methods listed above.

Client client = Client.create();

WebResource wr = client.resource("http://localhost:8080/jm/rest/foo");

// getting a single Foo object
Foo foo = wrGetFoo.path("/1").get(Foo.class);

// getting a list of Foo objects
List<Foo> foos = wr.path("/list").get(new GenericType<List<Foo>>() {});

// creating a Foo object
MultivaluedMap params = new MultivaluedMapImpl();
params.add("name", "Foo2");
params.add("bar", "bar2");
Foo foo2 = wr.put(Foo.class, params);

// updating a Foo object
params.clear();
params.add("name", "Foo2");
params.add("bar", "bar2updated");
foo2 = wr.path("/" + foo2.getId()).post(Foo.class, params);

// deleting a Foo object
wr.path("/" + foo2.getId()).delete();


As you can see, the methods on the WebResource class map perfectly with the HTTP methods generally used in a REST API: GET, POST, PUT and DELETE. You can download the sample project, jerseymarshall.zip, which contains two NetBeans projects: a web project for the server side and a plain java project for the client side.

January 06, 2010

Simple animation in JavaFX

Having two weeks off during the Christmas holidays gives you some time to create something in JavaFX. I had already used JavaFX before, but animations were a part I didn't yet have any experience in. So I was thinking of remaking a simple banner application that a client once needed for his website. That version was written in Flash and was created by a third party. You can have a look at that animation at http://vi.be.

The application is quite simple. It reads in an XML-file which contains a list of banners. Each banner has an image, a title, a description and a URL. After the XML-file has been read, it displays the banners one after another. The transition between two different banners is done by using a simple fading out/fading in animation. Doing this animation in JavaFX is simple.

First I create a variable to hold the current opacity and bind this to the opacity of the banner. The SingleBanner class used below is nothing more than a CustomNode in which the image, the title and the description are placed.

var bannerOpacity = 1.0;

insert SingleBanner {
banner : banner // the POJO containing all banner info
visible : false // initially all banners are invisible
opacity : bind bannerOpacity // bind the opacity variable to the banner

// when the mouse is hovering over the banner, pause the timeline
onMouseEntered : function(event : MouseEvent) {
timeline.pause();
}
onMouseExited : function(event : MouseEvent) {
timeline.play();
}
} into banners;


To do the actual animation in JavaFX, we need to create a Timeline. A Timeline does nothing more than perform actions at specified "keyframes". You can execute this Timeline once, a few times or even infinitely. Here's the code for our Timeline:

var timeline : Timeline = Timeline {
repeatCount : Timeline.INDEFINITE
keyFrames: [
at (4.75s) {
bannerOpacity => 1.0
},
at (4.85s) {
bannerOpacity => 0.0 tween Interpolator.EASEOUT
}
at (5.0s) {
bannerOpacity => 1.0 tween Interpolator.EASEIN
}
]
}


The syntax is easy to understand and you can clearly see what the Timeline does. 4.75 second after the Timeline was started, it will assign 1.0 to the variable bannerOpacity. Between 4.75 and 4.85 seconds the opacity will be brought down to zero using an EaseOut interpolation. Finally, the opacity will be brought back up to 1.0 with an EaseIn interpolation. The trick is now to make the current banner invisble when the opacity reaches 0. At the same time, the next banner in the array will be made visible. We can do that easily using a replace trigger.

var bannerOpacity = 1.0 on replace {
if (bannerOpacity == 0.0) {
counters[index].active = false;
if (index + 1 >= sizeof(banners)) {
index = 0;
} else {
index++;
}
counters[index].active = true;
}
}

var index = 0;
var banner = bind banners[index] on replace oldBanner {
oldBanner.visible = false;
banner.visible = true;
}


That's all that is required to do some simple animation. The code for the project can be downloaded here. There are only two problems that I couldn't resolve:

  • I have not yet found a way how to open a URL from within JavaFX. This can be achieved with: AppletStageExtension.showDocument(banner.link, "_new");

  • In browser mode the loading of the images takes a long time. In desktop mode it seems to go a lot quicker.



Below you can have a look at the banner application itself.


October 03, 2009

Easy file upload in Java using Jersey and Uploadify

Uploading a bunch of files to your server. I have come across this particular requirement a few times now during my web development career, but only recently did I discover a very easy way to implement it. And by easy I mean easy on both the client side and the server side.

Server

On the server side we develop our web applications in Java using Glassfish for our deployement server. You can have your standard Servlet class that catches your requests, but recently we bumped into Jersey. And I must say, I really love it. Here is for example the code to accept a file upload request.

@Path("/file")
public class FileHandler {
@POST
@Path("/upload")
@Consumes("multipart/form-data")
@Produces("text/plain")
public String uploadFile(@FormParam("file") File file, @FormParam("file") FormDataContentDisposition fcdsFile) {
String fileLocation = "/files/" + fcdsFile.getFileName();
File destFile = new File(fileLocation);

// your code here to copy file to destFile

return "1";
}
}

That's it. The FormDataContentDisposition is a recent addition to Jersey which allows you to retrieve the name of the file that is being uploaded.

Client

For the client side, I decided to make use of Uploadify. They basically provided a wrapper around SWFUpload using JQuery. Here is the code I used on the client side:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>SimpleFileUpload</title>
<script type="text/javascript" src="js/swfobject.js"></script>
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="js/jquery.uploadify.v2.1.0.min.js"></script>
<link rel="stylesheet" href="css/uploadify.css" type="text/css" media="screen"/>

<script type="text/javascript">
$(function() {
$('#file_upload').uploadify({
'uploader' : 'swf/uploadify.swf',
'script' : 'rest/file/upload',
'fileDataName' : 'file',
'cancelImg' : 'img/cancel.png',
'multi' : true
});
});
</script>
</head>
<body>
<h1>Simple File Upload</h1>

<h3>Multiple file upload made easy</h3>

<div id="file_upload"></div>
<br/>
<input type="button" value="Clear Queue" onclick="$('#file_upload').uploadifyClearQueue();"/>
<input type="button" value="Submit Queue" onclick="$('#file_upload').uploadifyUpload();"/>
</body>
</html>

Voila, now you have a simple web application that is able to upload files to your server. You can download a sample application here.

August 09, 2007

UTF-8 encoding with MySQL and Glassfish

Allright, after 6 hours of coding, googling, experimenting and swearing, I finally managed to develop a website that fully supports UTF-8. The website is running on Glassfish Application Server (build V2 50g to be more precise) with a MySQL database underneath. Listed below, you can find all the steps I had to go through in order to get the website running.

JSP's

  • With the JSP @page directive you can specify the desired encoding by specifying both the page encoding and the content type:
    <%@ page pageEncoding="UTF-8" contentType="text/html;charset=UTF-8" language="java" %>
    pageEncoding specifies in which encoding the jsp page has been saved. contentType defines what content type should be sent in the response to the browser.

  • It is further recommended to provide the content type through the meta-tag within the head-tag of the HTML-document:
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    ...
    </head>
    ...
    </html>
  • To be complete, you can also specify the @charset directive at the top of every external css page you are using:
    @charset "utf-8";
    ...

Servlets

  • With every request you get in a Servlet, you'll have to set the encoding on the Request object:
    public void doXXXX(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.setCharacterEncoding("UTF-8");
    ...
    }
    Beware that if you use a filter that already reads from the Request, you will need to set the character encoding in the filter.

  • At the same time, when you build your response, for example to return XML or JSON data, you set the content type of the Response object:
    response.setContentType("application/json; charset=UTF-8");
    As you probably know, this response header has to be set before you start writing your data.

Database

  • MySQL supports Unicode as of version 4.1 and by that it is possible to store data in de database in UTF-8 encoding. Activating the UTF-8 encoding on a MySQL table is done during its creation by specifying a CHARACTER SET and a COLLATION:
    CREATE TABLE `USER` (
    ...
    ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_unicode_ci;
    For more information about character sets in MySQL, you can read the document Character Set Support.

  • At least your data is now stored in UTF-8, but it doesn't end there. In Glassfish, you still have to create a JDBC Connection Pool with the correct settings allowing the JDBC driver to actually read and write your data in UTF-8. In the Admin Console you select the desired Connection Pool and then you navigate to Additional Properties. You will already see a number of properties being filled in (like DatabaseName, url, username and password). To enable UTF-8 support for JDBC, you'll have to add to extra properties:
    useUnicode = true
    characterEncoding = utf8

Mail

  • To be able to send e-mail messages encoded in UTF-8, you will also need to provide the encoding type on the subject and the content of the message. Finally, you also need to set the content type of the e-mail message itself.
    MimeMessage msg = new MimeMessage(session);
    msg.setSubject(subject, "UTF-8");
    msg.setText(body, "UTF-8");
    if (asHtml) {
    msg.setContent(mailMessage.getBody(), "text/html; charset=UTF-8");
    msg.setHeader("Content-Type", "text/html; charset=UTF-8");
    } else {
    msg.setHeader("Content-Type", "text/plain; charset=UTF-8");
    }


And that's it. You should now have a website that doesn't give problems showing and storing your UTF-8 content. Below you can see a screenshot of my web application that shows data in Georgian (username), in Japanese (Location) and even in Runic alphabet (Tags):