| <div class="wiki-content maincontent"> |
| <p>ActiveMQ is the default JMS provider in <a shape="rect" href="http://geronimo.apache.org">Apache Geronimo</a>.</p> |
| |
| <p>ActiveMQ can be used both as JMS Client and a JMS Broker. This short<br clear="none"> |
| article explains how to use it on a standalone client to access the<br clear="none"> |
| topics/queues setup on a remote Geronimo/ActiveMQ broker.</p> |
| |
| <p>1) Setup the queues and topics on the ActiveMQ Broker<br clear="none"> |
| If you're using a standalone ActiveMQ broker, then following the instructions on<br clear="none"> |
| ActiveMQ's website should be enough to setup everything.<br clear="none"> |
| However, if your ActiveMQ's instance is embedded inside the J2EE Geronimo<br clear="none"> |
| Application Server, creating Queues and Topics is about deploying Resource<br clear="none"> |
| Adapters to your Geronimo server.<br clear="none"> |
| The following deployment descriptor can be used to deploy two topics and a<br clear="none"> |
| ConnectionFactory: weatherTopic and weatherRequestsTopic</p> |
| |
| <structured-macro ac:macro-id="d2250b10-bf1d-4e52-8a7e-e645e9fb44a1" ac:name="code" ac:schema-version="1"><plain-text-body> |
| <?xml version="1.0" encoding="UTF-8"?> |
| <connector xmlns="http://geronimo.apache.org/xml/ns/j2ee/connector" |
| version="1.5" |
| configId="weather/Topics" |
| parentId="org/apache/geronimo/SystemJMS"> |
| <resourceadapter> |
| <resourceadapter-instance> |
| <resourceadapter-name>ActiveMQ RA</resourceadapter-name> |
| <config-property-setting name="ServerUrl">tcp://localhost:61616</config-property-setting> |
| <config-property-setting name="UserName">geronimo</config-property-setting> |
| <config-property-setting name="Password">geronimo</config-property-setting> |
| <workmanager> |
| <gbean-link>DefaultWorkManager</gbean-link> |
| </workmanager> |
| </resourceadapter-instance> |
| <outbound-resourceadapter> |
| <connection-definition> |
| |
| <connectionfactory-interface>javax.jms.ConnectionFactory</connectionfactory-interface> |
| <connectiondefinition-instance> |
| <name>ConnectionFactory</name> |
| |
| <implemented-interface>javax.jms.QueueConnectionFactory</implemented-interface> |
| |
| <implemented-interface>javax.jms.TopicConnectionFactory</implemented-interface> |
| <connectionmanager> |
| <xa-transaction> |
| <transaction-caching/> |
| </xa-transaction> |
| <single-pool> |
| <max-size>10</max-size> |
| |
| <blocking-timeout-milliseconds>5000</blocking-timeout-milliseconds> |
| <match-one/> |
| </single-pool> |
| </connectionmanager> |
| <global-jndi-name>ConnectionFactory</global-jndi-name> |
| <!-- |
| <credential-interface>javax.resource.spi.security.PasswordCredential</credential-interface> |
| --> |
| </connectiondefinition-instance> |
| </connection-definition> |
| </outbound-resourceadapter> |
| </resourceadapter> |
| <adminobject> |
| <adminobject-interface>javax.jms.Topic</adminobject-interface> |
| |
| <adminobject-class>org.codehaus.activemq.message.ActiveMQTopic</adminobject-class> |
| <adminobject-instance> |
| <message-destination-name>weatherTopic</message-destination-name> |
| <config-property-setting |
| name="PhysicalName">weatherTopic</config-property-setting> |
| </adminobject-instance> |
| </adminobject> |
| <adminobject> |
| <adminobject-interface>javax.jms.Topic</adminobject-interface> |
| |
| <adminobject-class>org.codehaus.activemq.message.ActiveMQTopic</adminobject-class> |
| <adminobject-instance> |
| |
| <message-destination-name>weatherRequestsTopic</message-destination-name> |
| <config-property-setting |
| name="PhysicalName">weatherRequestsTopic</config-property-setting> |
| </adminobject-instance> |
| </adminobject> |
| |
| </connector> |
| </plain-text-body></structured-macro> |
| |
| <p>Then deploy it using Geronimo's deploy tool :</p> |
| |
| <structured-macro ac:macro-id="d52711e4-100d-4c6a-bd05-d7b309b3b4d1" ac:name="code" ac:schema-version="1"><plain-text-body> |
| D:\geronimo>java -jar bin\deployer.jar deploy d:\projects\weather\src\resources\ |
| geronimo-activemq.xml repository\activemq\rars\activemq-ra-3.1-SNAPSHOT.rar |
| Username: system |
| Password: manager |
| Deployed weather/Topics |
| </plain-text-body></structured-macro> |
| |
| <p>The geronimo.log file should now refer to these newly deployed Topics.</p> |
| |
| <p>2) Now that the queues are available server-side, what we want is access them<br clear="none"> |
| thanks to a standalone Client.<br clear="none"> |
| Usually, the process is the following one :</p> |
| <ul><li>Contact the J2EE naming server (port 1099, RMI) to get an JNDI InitialContext.</li><li>The J2EE server automatically exposes the ConnectionFactory and the Topics<br clear="none"> |
| through JNDI, so the InitialContext allows you to retrieve both the<br clear="none"> |
| ConnectionFactory and the Topics</li><li>Once you have your Topics, you just use them..</li></ul> |
| |
| |
| <p>However, ActiveMQ's JNDI Implementation does NOT talk to the naming server. It's<br clear="none"> |
| a stripped down version of a JNDI client that just allows to get Topics and<br clear="none"> |
| Queues directly from a JMS instance.<br clear="none"> |
| So, instead of supplying the naming server address, you have to supply the JMS<br clear="none"> |
| server address.<br clear="none"> |
| Most JNDI implementations use the java.naming.provider.url property to specify<br clear="none"> |
| the naming server's address. ActiveMQ uses the brokerURL one. Using the<br clear="none"> |
| java.naming.provider.url one instead will result in ActiveMQ trying to load the<br clear="none"> |
| whole Broker.</p> |
| |
| <p>3) So, now we have explained the process, let's detail the Spring way of doing<br clear="none"> |
| things :</p> |
| |
| <ul class="alternate"><li>Create a bootstrap.properties file that's available in your classpath<br clear="none"> |
| jms.connectionFactoryName=ConnectionFactory<br clear="none"> |
| jms.jndiProviderUrl=tcp://localhost:61616<br clear="none"> |
| jms.jndiContextFactory=org.activemq.jndi.ActiveMQInitialContextFactory</li></ul> |
| |
| |
| <p>jms.weatherTopic=weatherTopic<br clear="none"> |
| jms.weatherRequestsTopic=weatherRequestsTopic</p> |
| |
| <ul class="alternate"><li>Now, in your Spring description file, declare the bean that will read<br clear="none"> |
| the properties from the bootstrap.properties file |
| <structured-macro ac:macro-id="4c35d9fb-b949-42d6-ac4a-848b747a8fa2" ac:name="code" ac:schema-version="1"><plain-text-body> |
| <bean id="placeholderConfig" |
| class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> |
| <property name="location"><value>classpath:/bootstrap.properties</value></property> |
| </bean> |
| </plain-text-body></structured-macro></li></ul> |
| |
| |
| <ul class="alternate"><li>Create a JNDI template (A Spring-specific wrapper around the JNDI InitialContext |
| <structured-macro ac:macro-id="2c47a0d9-75fe-436a-8995-0ced8834813c" ac:name="code" ac:schema-version="1"><plain-text-body> |
| <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate"> |
| <property name="environment"> |
| <props> |
| <prop key="java.naming.factory.initial">${jms.jndiContextFactory}</prop> |
| |
| <!-- Specific to ActiveMQ --> |
| |
| <!-- the address of the ActiveMQ broker --> |
| <prop key="brokerURL">${jms.jndiProviderUrl}</prop> |
| <!-- Some Topics Registration, since we are using a fake JNDI implementation --> |
| <prop key="topic.${jms.weatherTopic}">${jms.weatherTopic}</prop> |
| <prop key="topic.${jms.weatherRequestsTopic}">${jms.weatherRequestsTopic}</prop> |
| </props> |
| </property> |
| </bean> |
| </plain-text-body></structured-macro></li></ul> |
| |
| |
| <ul class="alternate"><li>Retrieve the ConnectionFactory from the JNDI context</li></ul> |
| |
| |
| <structured-macro ac:macro-id="060cb49a-9253-4db0-8a36-06f8fcef8896" ac:name="code" ac:schema-version="1"><plain-text-body> |
| <bean id="internalJmsQueueConnectionFactory" |
| class="org.springframework.jndi.JndiObjectFactoryBean"> |
| <property name="jndiTemplate"> |
| <ref bean="jndiTemplate"/> |
| </property> |
| <property name="jndiName"> |
| <value>${jms.connectionFactoryName}</value> |
| </property> |
| </bean> |
| </plain-text-body></structured-macro> |
| |
| <p>I'm not 100% sure, but I think that you can put any Factory Name, it will just<br clear="none"> |
| work. (In a scenario where the JNDI context actually contacts a naming server,<br clear="none"> |
| it should match the name of the deployed ConnectionFactory)</p> |
| |
| <ul class="alternate"><li>Get the Topics instances from the JNDI Context</li></ul> |
| |
| |
| <structured-macro ac:macro-id="d7a1771f-06d0-4f42-9806-62aa17e81627" ac:name="code" ac:schema-version="1"><plain-text-body> |
| <bean id="weatherTopic" |
| class="org.springframework.jndi.JndiObjectFactoryBean" |
| singleton="true"> |
| <property name="jndiTemplate"> |
| <ref bean="jndiTemplate"/> |
| </property> |
| <property name="jndiName"> |
| <value>${jms.weatherTopic}</value> |
| </property> |
| </bean> |
| <bean id="weatherRequestTopic" |
| class="org.springframework.jndi.JndiObjectFactoryBean" |
| singleton="true"> |
| <property name="jndiTemplate"> |
| <ref bean="jndiTemplate"/> |
| </property> |
| <property name="jndiName"> |
| <value>${jms.weatherRequestsTopic}</value> |
| </property> |
| </bean> |
| </plain-text-body></structured-macro> |
| |
| <ul class="alternate"><li>Now, you can reuse these Topics beans the way you want.</li></ul> |
| </div> |
| |