HornetQ JMS on Jetty

javapipe java hosting

Over the past few days I've been working on getting HornetQ (http://www.hornetq.org) to work on Jetty (http://www.mortbay.org/jetty/) -- specifically the embedded Jetty that Gradle (http://www.gradle.org) uses. I would first like to thank those on the HornetQ irc channel (irc://freenode.net:6667/hornetq) for helping me out and offering advice. Specifically I would like to thank Clebert Suconic and Andy Taylor for looking at some of my code and making suggestions that ultimately led me to this solution. It should be noted that the two solutions I will be discussing here are probably not the only roads to success. I'm quite confident the same could be achieved programmatically by setting up HornetQ in a bean that's loaded at application deploy time or similar fashion.

HornetQ setup using jetty-env.xml

Both of my two solutions are using jetty-env.xml to call the needed setup functions for HornetQ. The same could be achieved with jetty.xml if deploying to a standard install of Jetty. More information about these configuration files can be found at http://docs.codehaus.org/display/JETTY/Configuring+Jetty. In short these files act as an XML means of working with Java objects.  Objects can be instantiated, methods called, etc. All that's being done here is calling the methods in the HornetQ API to startup HornetQ in Embedded mode. Below is the jetty-env.xml I used:

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">

<Configure id="wac" class="org.mortbay.jetty.webapp.WebAppContext">
  <New id="jmsServerManager" class="org.mortbay.jetty.plus.naming.Resource">
    <Arg><Ref id="wac"/></Arg>
    <Arg>jms/serverManager</Arg>
    <Arg>
      <New class="org.hornetq.jms.server.impl.JMSServerManagerImpl">
        <Arg>
          <Call class="org.hornetq.core.server.HornetQ" name="newHornetQServer">
            <Arg>
              <New class="org.hornetq.core.config.impl.ConfigurationImpl">
                <Set name="persistenceEnabled">false</Set>
                <Set name="securityEnabled">false</Set>
                <Get name="AcceptorConfigurations">
                  <Call name="add">
                    <Arg>
                      <New class="org.hornetq.core.config.TransportConfiguration">
                        <Arg>org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory</Arg>
                      </New>
                    </Arg>
                  </Call>
                </Get>
              </New>
            </Arg>
          </Call>
        </Arg>
        <Call name="start" />
        <Call name="createConnectionFactory">
          <Arg>HornetQConnectionFactory</Arg>
          <Arg>
            <New class="org.hornetq.core.config.TransportConfiguration">
              <Arg>org.hornetq.core.remoting.impl.invm.InVMConnectorFactory</Arg>
            </New>
          </Arg>
          <Arg>
            <New class="java.util.ArrayList">
              <Call name="add">
                <Arg>java:comp/env/jms/connectionFactory</Arg>
              </Call>
            </New>
          </Arg>
        </Call>
        <Set name="context">
          <New class="javax.naming.InitialContext">
          </New>
        </Set>
        <Call name="createQueue">
          <Arg>testQueue</Arg>
          <Arg>java:comp/env/jms/queues/testQueue</Arg>
          <Arg></Arg>
          <Arg type="boolean">false</Arg>
        </Call>
      </New>
    </Arg>
  </New>
</Configure> 

An instance of JMSServerManager is being created and the needed configuration objects are being created inline in this example. It's very important to make the start call on the JMSServerManager before any other calls on the object to create queues, topics or connection factories are made, otherwise you'll get exceptions in your log saying the server hasn't been started yet. It's also important to make sure the full JNDI names are used. jetty-env.xml is used to bind elements to JNDI for you but because the JMSServerManager will be doing the binding for us I found that the full JNDI name must be used. If programmatic access to the JMSServerManager is needed this is also bound to JNDI for us by Jetty under jms/serverManager -- which doesn't use the full JNDI name because Jetty is handling the binding, a slight bit confusing I know. Work with JMS can now proceed using standard JNDI lookups and JMS code to send and receive messages. All of this code is available at my GitHub repo: http://github.com/LightGuard/Research---Development--JEE-/tree/hornetq feel free to check it out, fork it, whatever :)

HornetQ setup using jetty-env.xml and HornetQ configuration files

This setup is very similar to one above, only using the HornetQ configuration files. Code is located at http://github.com/LightGuard/Research---Development--JEE-/tree/hornetq-with-config-file. Here's the jetty-env.xml file:

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">

<Configure id="wac" class="org.mortbay.jetty.webapp.WebAppContext">
	<New id="jmsServerManager" class="org.mortbay.jetty.plus.naming.Resource">
		<Arg><Ref id="wac"/></Arg>
		<Arg>jms/serverManager</Arg>
		<Arg>
			<New class="org.hornetq.jms.server.impl.JMSServerManagerImpl">
				<Arg>
					<Call class="org.hornetq.core.server.HornetQ" name="newHornetQServer">
						<Arg>
							<New class="org.hornetq.core.config.impl.FileConfiguration">
								<Set name="configurationUrl">hornetq-configuration.xml</Set>
								<Call name="start" />
							</New>
						</Arg>
					</Call>
				</Arg>
				<Arg>hornetq-jms.xml</Arg>
				<Call name="start" />
				<Set name="context">
					<New class="javax.naming.InitialContext">
					</New>
				</Set>
			</New>
		</Arg>
	</New>
</Configure> 

It's much smaller this time as most of the configuration has been moved into the hornetq-configuration.xml and hornetq-jms.xml files (both of which are on GitHub). That's really all there is to it! My next steps will be to get logging of hornetq (and hopefully Jetty) using log4j and same log file as the rest of the application.