blob: 951488446a3b80a59bcbc768604214ace01dbb69 [file] [log] [blame]
<div class="wiki-content maincontent"><p>ActiveMQ will work with any JNDI provider capable of storing Java objects. However it is common to require a JNDI initial context to be able to run many JMS example programs, like <a shape="rect" class="external-link" href="http://java.sun.com/products/jms/tutorial/1_3_1-fcs/doc/jms_tutorialTOC.html" rel="nofollow">Sun's JMS tutorial.</a></p><p>So we provide a simple JNDI&#160;<strong><code>InitialContextFactory</code></strong> which can be used to lookup JMS connection factory objects as well as Destination objects. For example if you place this <a shape="rect" class="external-link" href="http://svn.apache.org/repos/asf/activemq/trunk/activemq-unit-tests/src/test/resources/jndi.properties">jndi.properties</a> file on your classpath, you can look inside the&#160;<strong><code>InitialContext</code></strong> and lookup&#160;<strong><code>ConnectionFactory</code></strong> objects and&#160;<strong><code>Destinations</code></strong> etc.</p><plain-text-body>java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
# Use the following property to configure the default connector
java.naming.provider.url = vm://localhost
# Use the following property to specify the JNDI name the connection factory
# should appear as.
#connectionFactoryNames = connectionFactory, queueConnectionFactory, topicConnectionFactry
# Register some queues in JNDI using the form:
# queue.[jndiName] = [physicalName]
queue.MyQueue = example.MyQueue
# Register some topics in JNDI using the form:
# topic.[jndiName] = [physicalName]
topic.MyTopic = example.MyTopic</plain-text-body><p>You can edit the&#160;<strong><code>jndi.properties</code></strong> file to configure the <strong><code>ActiveMQConnectionFactory</code></strong>'s properties such as&#160;<strong><code>brokerURL</code></strong> and whether or not there should be an embedded broker etc. See <a shape="rect" href="how-do-i-embed-a-broker-inside-a-connection.xml">how to embed a broker in a connection</a> for more details.</p><h3 id="JNDISupport-ActiveMQJNDITutorial">ActiveMQ JNDI Tutorial</h3><p>This is a quick one page tutorial on how to setup and use JNDI to create a connection to ActiveMQ. The first thing is ActiveMQ does not provide a full JNDI server. This means JMS clients need to use properties files to create a JNDI <strong><code>IntialContextFactory</code></strong>. If you need an example properties file, you can look the source distribution <a shape="rect" class="external-link" href="https://github.com/apache/activemq/blob/master/activemq-unit-tests/src/test/resources/jndi.properties" rel="nofollow">https://github.com/apache/activemq/blob/master/activemq-unit-tests/src/test/resources/jndi.properties</a>. Before we proceed, here are the properties.</p><div class="table-wrap"><table class="confluenceTable"><tbody><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Name</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Value</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p><code>java.naming.factory.initial</code></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><code>org.apache.activemq.jndi.ActiveMQInitialContextFactory</code></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p><code>java.naming.provider.url</code></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><code>tcp://hostname:61616</code></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p><code>topic.MyTopic</code></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><code>example.MyTopic</code></p></td></tr></tbody></table></div><p>Make sure to add&#160;<strong><code>activemq-<em>&lt;version&gt;</em>.jar</code></strong> and&#160;<strong><code>spring-1.x.jar</code></strong> to your classpath. If the libraries are not in the classpath, you will get a&#160;<strong><code>ClassNotFoundException</code></strong> at runtime. If you get <strong><code>ClassNotFoundException</code></strong>, try printing out the classpath and check it is present. You can also run ActiveMQ with&#160;<strong><code>-verbose</code></strong> option to verify the jar was loaded correctly.</p><p><strong>Sample Code</strong></p><parameter ac:name="language">java</parameter><plain-text-body>// Create a new intial context, which loads from jndi.properties file:
javax.naming.Context ctx = new javax.naming.InitialContext();
// Lookup the connection factory:
javax.jms.TopicConnectionFactory factory = (javax.jms.TopicConnectionFactory)ctx.lookup("ConnectionFactory");
// Create a new TopicConnection for pub/sub messaging:
javax.jms.TopicConnection conn = factory.getTopicConnection();
// Lookup an existing topic:
javax.jms.Topic mytopic = (javax.jms.Topic)ctx.lookup("MyTopic");
// Create a new TopicSession for the client:
javax.jms.TopicSession session = conn.createTopicSession(false,TopicSession.AUTO_ACKNOWLEDGE);
// Create a new subscriber to receive messages:
javax.jms.TopicSubscriber subscriber = session.createSubscriber(mytopic);
</plain-text-body><p>Notice the name of the topic in the sample is <strong><code>MyTopic</code></strong>. ActiveMQ will read the&#160;<strong><code>jndi.properties</code></strong> files and creates the topics and queues in a lazy fashion. The prefix topic and queue is stripped, so the JNDI name begins after the prefix.</p><p>Once you have the&#160;<strong><code>jndi.properties</code></strong> edited and ready, it needs to be accessible to your application. The easiest way is to add&#160;<strong><code>jndi.properties</code></strong> to a jar file. When&#160;<strong><code>new InitialContext()</code></strong> is called, it will scan the resources and find the file. If you get <strong><code>javax.naming.NamingException</code></strong>, it usually means the&#160;<strong><code>jndi.properties</code></strong> file is not accessible.</p><p>You can also try to create a new initial context using either an instance of properties file or a map. For example, the approach recommended by JMS specification will work just fine.</p><div class="table-wrap"><table class="confluenceTable"><tbody><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Example Recommended by Specification</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><parameter ac:name="language">java</parameter><plain-text-body>Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY,"org.apache.activemq.jndi.ActiveMQInitialContextFactory");
props.setProperty(Context.PROVIDER_URL,"tcp://hostname:61616");
javax.naming.Context ctx = new InitialContext(props);||
</plain-text-body></td></tr></tbody></table></div><p>If ActiveMQ is embedded within an EJB container, you will need to look at the containers documentation for the correct JNDI values.</p><h3 id="JNDISupport-DynamicallyCreatingDestinations">Dynamically Creating Destinations</h3><p>For the easiest possible configuration with JNDI based programs, there are two dynamic contexts, namely:</p><ul><li><strong><code>dynamicQueues</code></strong></li><li><strong><code>dynamicTopics</code></strong></li></ul><p>These allow you to lookup queues and topics using JNDI without any configuration.</p><p>For example, if you use the following name to lookup into JNDI:</p><plain-text-body>dynamicQueues/FOO.BAR
</plain-text-body><p>you will get back an&#160;<strong><code>ActiveMQQueue</code></strong> of the name <strong><code>FOO.BAR</code></strong>. This can be very handy if you can easily reconfigure the JNDI name to use to lookup something in JNDI, but don't want to have to double configure a&#160;<strong><code>jndi.properties</code></strong> to match.</p><h3 id="JNDISupport-WorkingWithEmbeddedBrokers">Working With Embedded Brokers</h3><p>It is often useful to use an embedded broker in the same JVM as the JMS client. For this see <a shape="rect" href="how-do-i-embed-a-broker-inside-a-connection.xml">How do I embed a Broker inside a Connection</a>.</p><p>If you want to use an embedded broker with your JNDI provider you can just use the <a shape="rect" href="vm-transport-reference.xml">VM Transport</a> to connect to the broker in your URL. e.g. to create a purely in JVM broker use this URI</p><plain-text-body>vm://locahost
</plain-text-body><p>If you want to customize the broker use something like this:</p><plain-text-body>vm:broker:(tcp://localhost:61616)
</plain-text-body><p>More options are available in the <a shape="rect" href="vm-transport-reference.xml">VM Transport Reference</a></p><h3 id="JNDISupport-ExampleJavaCode">Example Java Code</h3><p>Once you have configured JNDI on the classpath you can run any normal JMS application such as the following <a shape="rect" class="external-link" href="http://svn.apache.org/repos/asf/incubator/activemq/trunk/activemq-unit-tests/src/test/java/org/apache/activemq/demo/SimpleProducer.java">example</a>. Notice that the Java code just uses pure JMS APIs and is not in any way ActiveMQ specific</p><parameter ac:name="language">java</parameter><plain-text-body>/**
* The SimpleQueueSender class consists only of a main method,
* which sends several messages to a queue.
*
* Run this program in conjunction with SimpleQueueReceiver.
* Specify a queue name on the command line when you run the
* program. By default, the program sends one message. Specify
* a number after the queue name to send that number of messages.
*/
package org.apache.activemq.demo;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A simple polymorphic JMS producer which can work with Queues or Topics which
* uses JNDI to lookup the JMS connection factory and destination.
*/
public final class SimpleProducer {
private static final Logger LOG = LoggerFactory.getLogger(SimpleProducer.class);
private SimpleProducer() {}
&#160;/**
* @param args the destination name to send to and optionally, the number of
* messages to send
*/
public static void main(String[] args) {
Context jndiContext;
ConnectionFactory connectionFactory;
Connection connection;
Session session;
Destination destination;
MessageProducer producer;
String destinationName;
final int numMsgs;
&#160;if ((args.length &lt; 1) || (args.length &gt; 2)) {
LOG.info("Usage: java SimpleProducer &lt;destination-name&gt; [&lt;number-of-messages&gt;]");
System.exit(1);
}
&#160;destinationName = args[0];
LOG.info("Destination name is " + destinationName);
if (args.length == 2) {
numMsgs = (new Integer(args[1])).intValue();
}
else {
numMsgs = 1;
}
/*
* Create a JNDI API InitialContext object
*/
try {
jndiContext = new InitialContext();
}
catch (NamingException e) {
LOG.info("Could not create JNDI API context: " + e.toString());
System.exit(1);
}
&#160;/*
* Look up connection factory and destination.
*/
try {
connectionFactory = (ConnectionFactory)jndiContext.lookup("ConnectionFactory");
destination = (Destination)jndiContext.lookup(destinationName);
}
catch (NamingException e) {
LOG.info("JNDI API lookup failed: " + e);
System.exit(1);
}
&#160;/*
* Create connection. Create session from connection; false means
* session is not transacted. Create sender and text message. Send
* messages, varying text slightly. Send end-of-messages message.
* Finally, close the connection.
*/
try {
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(destination);
TextMessage message = session.createTextMessage();
&#160;for (int i = 0; i &lt; numMsgs; i++) {
message.setText("This is message " + (i + 1));
LOG.info("Sending message: " + message.getText());
producer.send(message);
}
&#160;/*
* Send a non-text control message indicating end of messages.
*/
producer.send(session.createMessage());
}
catch (JMSException e) {
LOG.info("Exception occurred: " + e);
}
finally {
if (connection != null) {
try {
connection.close();
}
catch (JMSException ignored) {}
}
}
}
}
</plain-text-body></div>