Simple guide to Java Message Service (JMS) using ActiveMQ

JMS let’s you send messages containing for example a String, array of bytes or a serializable Java object, from one program to another. It doesn’t however use a direct connection from program A to program B, instead the message is sent to a JMS provider and put there in a Queue where it waits until the other program receives it.

MessageProducer is a Java program sending a JMS message to a Queue on the JMS Provider. MessageConsumer is another program which receives that message. These two programs can run on separate machines and all they have to know to communicate is the URL of the JMS Provider. The Provider can be for example a Java EE server, like JBoss or Glassfish. But don’t be afraid, you don’t need a full-blown JEE server to send a JMS message. In this article we will use ActiveMQ which is lightweight and easy to use.

First we need to download ActiveMQ. If you are using Linux, you can get it from this link. For Windows you can use this link. In case the links don’t work, you can find the files in ‘Downloads’ section on ActiveMQ’s webpage.

After the download, extract it to any directory and run the ‘activemq’ program from beneath the ‘{path-where-you-extracted-activemq}/bin’ directory:

user@user-laptop:~/activemq/apache-activemq-5.3.0/bin$ ./activemq

You should see a bunch of INFO messages appearing on the terminal:

...
INFO | ActiveMQ Web Demos at http://0.0.0.0:8161/demo
INFO | RESTful file access application at http://0.0.0.0:8161/fileserver
INFO | Started SelectChannelConnector@0.0.0.0:8161

Now the ActiveMQ server is up and running. You can close it any time by pressing Ctrl-C. ActiveMQ has a nice admin console, where you can see a lot of useful informations and change the settings: http://localhost:8161/admin/.

Now that we have a JMS provider running, let’s write our message producer and consumer programs. For that, you will need to put the ActiveMQ’s JAR file on the class path. The file you need is called (for version 5.3.0) ‘activemq-all-5.3.0.jar’ or something similar and is in the extracted ActiveMQ directory. In Eclipse you could click right mouse button on your project and choose Properties->Java Build Path->Libraries->Add External Library.

Here is the code of the program sending (producing) the messages:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
import javax.jms.*;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;

public class Producer {
    // URL of the JMS server. DEFAULT_BROKER_URL will just mean
    // that JMS server is on localhost
    private static String url = ActiveMQConnection.DEFAULT_BROKER_URL;

    // Name of the queue we will be sending messages to
    private static String subject = "TESTQUEUE";

    public static void main(String[] args) throws JMSException {
        // Getting JMS connection from the server and starting it
        ConnectionFactory connectionFactory =
            new ActiveMQConnectionFactory(url);
        Connection connection = connectionFactory.createConnection();
        connection.start();

        // JMS messages are sent and received using a Session. We will
        // create here a non-transactional session object. If you want
        // to use transactions you should set the first parameter to 'true'
        Session session = connection.createSession(false,
            Session.AUTO_ACKNOWLEDGE);

        // Destination represents here our queue 'TESTQUEUE' on the
        // JMS server. You don't have to do anything special on the
        // server to create it, it will be created automatically.
        Destination destination = session.createQueue(subject);

        // MessageProducer is used for sending messages (as opposed
        // to MessageConsumer which is used for receiving them)
        MessageProducer producer = session.createProducer(destination);

        // We will send a small text message saying 'Hello' in Japanese
        TextMessage message = session.createTextMessage("こんにちは");

        // Here we are sending the message!
        producer.send(message);
        System.out.println("Sent message '" + message.getText() + "'");

        connection.close();
    }
}

There is a lot going on here. The Connection represents our connection with the JMS Provider – ActiveMQ. Be sure not to confuse it with SQL’s Connection. ‘Destination’ represents the Queue on the JMS Provider that we will be sending messages to. In our case, we will send it to Queue called ‘TESTQUEUE’ (it will be automatically created if it didn’t exist yet).

What you should note is that there is no mention of who will finally read the message. Actually, the Producer does not know where or who the consumer is! We are just sending messages into queue ‘TESTQUEUE’ and what happens from there to the sent messages is not of Producer’s interest any more.

The most interesting for us part in the above code is probably line 46 where we use function ‘.createTextMessage(”こんにちは”);’ to send a text message (in this case to our Japanese friend).

Now let’s see how to receive (consume) the sent message. Here is the code for the Consumer class:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
import javax.jms.*;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;

public class Consumer {
    // URL of the JMS server
    private static String url = ActiveMQConnection.DEFAULT_BROKER_URL;

    // Name of the queue we will receive messages from
    private static String subject = "TESTQUEUE";

    public static void main(String[] args) throws JMSException {
        // Getting JMS connection from the server
        ConnectionFactory connectionFactory
            = new ActiveMQConnectionFactory(url);
        Connection connection = connectionFactory.createConnection();
        connection.start();

        // Creating session for seding messages
        Session session = connection.createSession(false,
            Session.AUTO_ACKNOWLEDGE);

        // Getting the queue 'TESTQUEUE'
        Destination destination = session.createQueue(subject);

        // MessageConsumer is used for receiving (consuming) messages
        MessageConsumer consumer = session.createConsumer(destination);

        // Here we receive the message.
        // By default this call is blocking, which means it will wait
        // for a message to arrive on the queue.
        Message message = consumer.receive();

        // There are many types of Message and TextMessage
        // is just one of them. Producer sent us a TextMessage
        // so we must cast to it to get access to its .getText()
        // method.
        if (message instanceof TextMessage) {
            TextMessage textMessage = (TextMessage) message;
            System.out.println("Received message '"
                + textMessage.getText() + "'");
        }
        connection.close();
    }
}

As you see, it looks pretty similar to the Producer’s code before. Actually only the part starting from line 35 is substantially different. We produce there a MessageConsumer instead of MessageReceiver and then use it’s .receive() method instead of .send(). You can see also an ugly cast from Message to TextMessage but there is nothing we could do about it, because .receive() method just returns interface Message (TextMessage interface extends Message) and there are no separate methods for receiving just TextMessage’s.

Compile now both programs remembering about adding ActiveMQ’s JAR file to the classpath. Before running them be also sure that the ActiveMQ’s instance is running (for example in a separate terminal). First run the Producer program:

2009/11/14 15:56:37 org.apache.activemq.
transport.failover.FailoverTransport doReconnect
情報: Successfully connected to tcp://localhost:61616
Sent message 'こんにちは'

If you see something similar to the output above (especially the ‘Sent message’ part) then it means that the message was successfully sent and is now inside the TESTQUEUE queue. You can enter the Queues section in the ActiveMQ’s admin console http://localhost:8161/admin/queues.jsp and see that there is one message sitting in TESTQUEUE:

In order to receive that message run now the Consumer program:

2009/11/14 15:58:03 org.apache.activemq.
transport.failover.FailoverTransport doReconnect
情報: Successfully connected to tcp://localhost:61616
Received message 'こんにちは'

If you are getting above input (or something similar) everything went ok. The message was successfully received.

You are now probably thinking “Why would anybody want to do that??”. In fact, the code presented here to transfer just a small text message was pretty big, and you also needed an instance of ActiveMQ running, and dependencies in the classpath and all that…. Instead of using JMS we could use plain TCP/IP with few times less effort. So, what are good points of using JMS compared to simple TCP/IP or Java RMI? Here they are:

  • Communication using JMS is asynchronous. The producer just sends a message and goes on with his business. If you called a method using RMI you would have to wait until it returns, and there can be cases you just don’t want to lose all that time.
  • Take a look at how we run the example above. At the moment we run the Producer to send a message, there was yet no instance of Consumer running. The message was delivered at the moment the Consumer asked ActiveMQ for it. Now compare it to RMI. If we tried to send any request through RMI to a service that is not running yet, we would get a RemoteException. Using JMS let’s you send requests to services that may be currently unavailable. The message will be delivered as soon as the service starts.
  • JMS is a way of abstracting the process of sending messages. As you see in the examples above, we are using some custom Queue with name ‘TESTQUEUE’. The producer just knows it has to send to that queue and the consumer takes it from there. Thanks to that we can decouple the producer from the consumer. When a message gets into the queue, we can do a full bunch of stuff with it, like sending it to other queues, copying it, saving in a database, routing based on its contents and much more. here you can see some of the possibilities.

JMS is widely used as a System Integration solution in big, distributed systems like those of for example banks. There are many books dealing with this huge topic, for example Enterprise Integration Patterns. If you want to learn more about JMS itself you can do it for example on this JMS Tutorial on Sun’s webpage.

A guide to Java SimpleDateFormat in examples

Today I want to show you some examples of how you can use SimpleDateFormat class in your code. I hope some of them will be new and surprising!

The basic example

First the most basic usage of the class. Lets use it to format Date object into a simple string showing day, month and a year:

1:
2:
3:
4:
5:
6:
SimpleDateFormat simpleDateFormat =
        new SimpleDateFormat("dd/MM/yy");
String dateAsString = simpleDateFormat.format(new Date());

System.out.println(dateAsString);
// Result: "12/11/09"

Slightly more advanced

Obviously we can use more complicated patterns than that (see SimpleDateFormat JavaDoc for the full list). Besides adding more data to be shown we can also add some regular text – to do that in a pattern you need to escape the text with an apostrophe. So here is a fancy way of printing the time and date:

1:
2:
3:
4:
5:
6:
SimpleDateFormat simpleDateFormat =
        new SimpleDateFormat("hh:mm 'o''clock on' MMMM dd yyyy");
String dateAsString = simpleDateFormat.format(new Date());

System.out.println(dateAsString);
// Result: "06:49 o'clock on November 12 2009"

Now with Locale

SimpleDateFormat is Locale dependent, so by providing one you can get the Date string localized for specific language or country. This is a date in French:

1:
2:
3:
4:
5:
6:
SimpleDateFormat simpleDateFormat =
        new SimpleDateFormat("dd MMMM yyyy zzzz G", Locale.FRENCH);
String dateAsString = simpleDateFormat.format(new Date());

System.out.println(dateAsString);
// Result: "12 novembre 2009 Heure du méridien de Greenwich ap. J.-C."

Parse String to Date

Good thing about the SimpleDateFormat class is that it can be used not only for formatting, but also for parsing string into a Date object. In this example the used pattern is exactly the same as used by Date.toString() method. With it we can parse the strings created by Data.toString() back into dates:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
// SimpleDateFormat that works exactly like Date.toString()
SimpleDateFormat simpleDateFormat =
        new SimpleDateFormat("E MMM dd HH:mm:ss zzz yyyy", Locale.ROOT);
Date today = new Date();

String dateAsString_format = simpleDateFormat.format(today);
String dateAsString_native = today.toString();
// Both strings are: "Thu Nov 12 18:49:36 GMT 2009"

Date parsedDate = simpleDateFormat.parse(dateAsString_native);
System.out.println(parsedDate.toString());
// Result: "Thu Nov 12 18:49:36 GMT 2009"

Setting the default time zone

Notice that when you parse a string into a Date the result may be ambiguous. For example the string “11:23 1 Jan 2001″ is a different moment in time depending whether you live in Japan or Canada. By default Java resolves this by using your local time zone obtained from the default Locale.

Since the time zone may not be a part of the parsed string you may want to set it manually instead using the default one. You can do this with setTimeZone() method:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
SimpleDateFormat simpleDateFormat =
        new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH);
Date date = simpleDateFormat.parse("13-07-1999");
System.out.println(date);
// Result: "Tue Jul 13 00:00:00 GMT 1999"

simpleDateFormat.setTimeZone(TimeZone.getTimeZone("PST"));
date = simpleDateFormat.parse("13-07-1999");
System.out.println(date);
// Result: "Tue Jul 13 08:00:00 GMT 1999"

Setting the century

Similar ambiguity occurs when parsing two-digit year dates. Whether “01/01/59″ is the new year’s day of 1959 or 2059 can be set by specifying the century to the SimpleDateFormat object. To be specific with set2DigitYearStart() method you can specify the 100 year period in which the parsed date will be placed. By default the 100 year period is [today - 80 years, today + 20 years]. See the example:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
SimpleDateFormat simpleDateFormat =
        new SimpleDateFormat("dd MMMM yy", Locale.ENGLISH);
Date date = simpleDateFormat.parse("1 November 45");
System.out.println(date);
// By default the year 45 will be taken from period 1929 - 2029
// Result: "Thu Nov 01 00:00:00 GMT 1945"

Date startOf19thCentury = new GregorianCalendar(1801,1,1).getTime();
Date startOf21stCentury = new GregorianCalendar(2001,1,1).getTime();

simpleDateFormat.set2DigitYearStart(startOf19thCentury);
date = simpleDateFormat.parse("1 November 45");
System.out.println(date);
// After invoking set2DigitYearStart() the period is now 1801 - 1901
// Result: "Thu Nov 01 00:00:00 GMT 1845"

simpleDateFormat.set2DigitYearStart(startOf21stCentury);
date = simpleDateFormat.parse("1 November 45");
System.out.println(date);
// This time the period is 2001 - 2101
// Result: "Thu Nov 01 00:00:00 GMT 2045"

Make the parsing more strict

By default the parse method of SimpleDateFormat is very forgiving. If the provided string is not entirely compatible with the pattern, SimpleDateFormat instead of giving up tries with many tricky heuristics to guess what would be the correct answer. In many situations this behavior is more than welcome, but if you do not like this you can disable it. With setLenient() method you can make the parsing obey exactly the pattern and throw an exception if string is invalid.

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
SimpleDateFormat simpleDateFormat =
        new SimpleDateFormat("dd MMMM yyyy", Locale.ENGLISH);
Date date = simpleDateFormat.parse("31 April 1999");
System.out.println(date);
// Since April has only 30 days the parser will assume
// user meant April 30th + one day = May 1st
// Result: "Sat May 01 00:00:00 GMT 1999"

// Make the parsing more strict
simpleDateFormat.setLenient(false);
// This throws java.text.ParseException: Unparseable date: "31 April 1999"
date = simpleDateFormat.parse("31 April 1999");

Using Java SecurityManager to grant/deny access to system functions

In Java it is possible to restrict access to specific functions like reading/writing files and system properties, thread control, networking, object serialization and much more for the running application. Such restrictions may be crucial for guaranteeing security of the system and are implemented for example in Applets, Java Web Start or Java EE Servers.

Class witch takes care of all that security is SecurityManager whose currently registered instance can be accessed through System.getSecurityManager() method. Normally for stand-alone Java applications there is no SecurityManager registered, which means a call to getSecurityManager() would return null. In such case, all the system functions are allowed.

We will show here a simple example of how security in Java works. Take a look at the class below:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class SecurityTest {
    public static void main(String[] args)
        throws FileNotFoundException {
        //Is there a SecurityManger registered?
        System.out.println("SecurityManager: " +
            System.getSecurityManager());

        //Checking if we can open a file for reading
        FileInputStream fis = new FileInputStream("test.txt");
        System.out.println("File successfully opened");

        //Checking if we can access a vm property
        System.out.println(System.getProperty("file.encoding"));
    }
}

The class first gets the SecurityManager’s instance and prints it out. Note that this step has no influence on two proceeding steps. It’s purpose is just to show clearly if SecurityManager is there or not. Next step is opening a file called ‘test.txt’ for reading. For this step you should create a file ‘text.txt’ (it may be empty) and put it in the application’s directory. Last step reads a system property “file.encoding” which on most systems should be set by default to “UTF-8″.

Now run the program! If you got any exceptions, check if you copied everything well and if you created the file ‘text.txt’ in the program’s directory. If everything went right, you should get the following output:

SecurityManager: null
File successfully opened
UTF-8

First note that the instance of SecurityManager we got from System.getSecurityManager() is null. There is no SecurityManager so everything is allowed and we were able to successfully open a file and read the system property.

Now let’s put security to play! We will need a file defining current security policy. It is a file that tells the SecurityManager what it should allow and what it should deny. Below is an example of such a file:

grant {
};

As you see, there is nothing written inside the ‘grant’ block. It means that there are no permissions specified and (almost) all system functions will be denied. Put that in a file called ‘test.policy’ and place it in the application’s directory (along with file ‘text.txt’). You can read much more about structure of .policy files here.

With the policy file in place, we should tell the JVM to create a SecurityManager and use file ‘test.policy’ for the security policy. We do it by specifying two system properties while running the SecurityTest program: -Djava.security.manager and -Djava.security.policy=test.policy. You can specify them for example in Eclipse in ‘Run Configurations…->Arguments->VM arguments:’ dialog. Alternatively you can specify them straight from the command line (supposing you exported your code to SecurityTest.jar and put it in the same directory where ‘test.policy’ is:

java -Djava.security.manager -Djava.security.policy=test.policy
 -jar SecurityTest.jar

Using these parameters run the program! If everything goes well, this time SecurityManager activates and you should see something like this:

SecurityManager: java.lang.SecurityManager@1a46e30
Exception in thread "main"
    java.security.AccessControlException: access denied
    (java.io.FilePermission test.txt read)
    ...

First line indicates that SecurityManager is registered. The exception you see on the next line is proper behavior. InputFileReader’s constructor internally checks if there is a SecurityManager installed. If so, it calls it to check if reading the specified file is allowed according to the current security policy. The security policy (which we specified in ‘test.policy’ file) contains no permissions for reading a file, so SecurityManager throws AccessControlException.

What to do to allow reading files? We have to put a specific rule to ‘test.policy’. Rules for accessing files are implemented by FilePermission class. You can specify which file the rule applies to and what kind of access is being granted. Below you see what must be written in ‘test.policy’ file:

grant {
  permission java.io.FilePermission "test.txt", "read";
};

This rule grants reading on file ‘text.txt’ (you could also use “<<ALL FILES>>” to grant the reading of all files). With this permission in place, let’s run the program once again:

SecurityManager: java.lang.SecurityManager@1a46e30
File successfully opened
Exception in thread "main"
    java.security.AccessControlException:
    access denied (java.util.PropertyPermission file.encoding read)

As you see this time file was successfully opened, but next exception appeared while trying to read the property “file.encoding”. Permission allowing programs to access system properties is called PropertyPermission. We define it following way:

grant {
  permission java.io.FilePermission "test.txt", "read";
  permission java.util.PropertyPermission "file.encoding", "read";
};

It will allow reading of property “file.encoding”. This time when we run the program, everything will be allowed by the SecurityManager and we should get following output:

SecurityManager: java.lang.SecurityManager@1a46e30
File successfully opened
UTF-8

Writing .policy files for a big application can be tedious, especially if you don’t know yet the correct syntax. Fortunately there is help in form of ‘policytool’, which is a small program distributed along with JDK. You can read something about it here.

This short introduction shows just a tiny bit of SecurityManager’s features. You can do a lot more with it, like for example defining your own permissions and using them in your classes. You can also set principals for every permission and specify files containing digital signatures for them, so that a user running your program must be in possession of a key file to access specific functions. You can read about this functionality for example on this Sun’s tutorial. There is also a bunch of useful links concering security on this site.