How to create a jms Topic and TopicConnectionFactory programmatically?

simgineer picture simgineer · Dec 7, 2011 · Viewed 7k times · Source

Anyone know if you can create a topic and its connection factory programmatically? Currently I use the glassfish admin utility to create my topic and its connection factory. If I can't create it in code does glassfish/openmq have a default topic and conn factory I can use?

Answer

mdo picture mdo · Dec 8, 2011

If you only want to circumvent creating the resources manually in the admin you can simply deploy them with the file "glassfish-resources.xml" (GF 3.1, see http://docs.oracle.com/cd/E18930_01/html/821-2417/giyhh.html).

You need an admin-object-resource like this one (for a topic):

<admin-object-resource enabled="true" jndi-name="jms/myTopic"
   object-type="user" res-adapter="jmsra" res-type="javax.jms.Topic">
  <property name="Name" value="physicalTopic"/>
</admin-object-resource>

Be aware that you must use different "Name" values for the Topic (here: "physicalTopic") if you implement multiple Topics whose messages should not get mixed up.

Further you need a connector-resource referencing a connector-connection-pool of type javax.jms.TopicConnectionFactory.

If you don't aim for dynamically creating resources using the deployment descriptor glassfish-resources.xml seems to be the best way.

Please note that resources deployed that way are application-scoped: http://docs.oracle.com/cd/E18930_01/html/821-2417/giydj.html

"glassfish-resources.xml" is the file for GF 3.x, for GF 2.x it was "sun-resources.xml". The file is located in the "Server Resources" folder in your project view if you are using NetBeans. Attention: the glassfish-resources.xml in "Server Resources" is only used by NetBeans if you use NetBeans to deploy! NetBeans knows how to create theses resources and conducts this task. If you deploy an EAR directly to Glassfish without NetBeans -- which seems very likely for a production environment -- you have to provide glassfish-resources.xml in:

  • META-INF of your EJB module or WEB-INF of your WAR for module scoped resources
  • META-INF of your enterprise application for application wide resources In NetBeans you accomplish this by placing the file into the "Configuration Files" folder of your project view (which is src/conf/ in the file system).

You can easily create this resource definition by using NetBeans' [New Message-Driven Bean] wizard (simply add an MBean by selecting [New ...]). In the wizard choose "Project Destinations" > [Add]. A complete 3.1 example looks like this:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
    <admin-object-resource enabled="true" jndi-name="jms/myDestination"  res-type="javax.jms.Topic"  res-adapter="jmsra">
        <property name="Name" value="PhysicalTopic"/>
    </admin-object-resource>
    <connector-connection-pool name="jms/myDestinationFactoryPool"  connection-definition-name="javax.jms.TopicConnectionFactory"  resource-adapter-name="jmsra"/>
    <connector-resource enabled="true" jndi-name="jms/myDestinationFactory" pool-name="jms/myDestinationFactoryPool"  />
</resources>

This is the MBean annotation:

@MessageDriven(mappedName = "java:app/jms/myDestination", activationConfig =
{
    @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
    @ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "Durable"),
    @ActivationConfigProperty(propertyName = "clientId", propertyValue = "NewMessageBean"),
    @ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "NewMessageBean")
})
public class NewMessageBean implements MessageListener
{ 
[...]

Caution: "java:app/" in mappedName is correct only if you use application scoped resources. You can spare "java:app/" in the definition in glassfish-resources.xml. The GF deployment guide says: "Application-scoped resource JNDI names begin with java:app or java:module. If one of these prefixes is not specified in the JNDI name, it is added."

You can also introduce another level of indirection by using "name" instead of "mappedName". You then have to provide a file named "application-client.xml" where the (logical) name gets mapped to an JNDI "physical" location.