Preloader image

This example shows how a standalone client using the remote OpenEJB client (org.apache.openejb.client.RemoteInitialContextFactory) can look up JMS resources, here an ActiveMQ ConnectionFactory and Queue, through JNDI. The resources are not fetched from a server: the client builds them from system properties. In effect you declare a small JNDI tree on the client side.

The example is only a test, SenderTest. There is no application code.

Dependencies

The client needs the OpenEJB client, which provides the InitialContext factory, and the ActiveMQ classes it will instantiate:

<dependency>
  <groupId>org.apache.tomee.bom</groupId>
  <artifactId>tomee-plus-api</artifactId>
  <version>11.0.0-M2-SNAPSHOT</version>
  <scope>provided</scope>
</dependency>
<!-- here what is needed to use client lookup with jms resources -->
<dependency>
  <groupId>org.apache.tomee</groupId>
  <artifactId>openejb-client</artifactId>
  <version>11.0.0-M2-SNAPSHOT</version>
  <scope>runtime</scope>
</dependency>
<dependency>
  <groupId>org.apache.tomee</groupId>
  <artifactId>openejb-ejbd</artifactId>
  <version>11.0.0-M2-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>org.apache.activemq</groupId>
  <artifactId>activemq-broker</artifactId>
  <version>6.2.6</version>
  <scope>runtime</scope>
</dependency>

Declaring the client resources

The resources are declared as system properties. The key is the JNDI name used for the lookup. The value follows the pattern <kind>:<implementation class>:<constructor argument>:

@BeforeClass
public static void configureClientResources() {
    // can be set this way or with the key Resource/<type>
    // in fact we create on client side a mini jndi tree
    // the key is the jndi name (the one used for the lookup)
    System.setProperty("aConnectionFactory", "connectionfactory:org.apache.activemq.ActiveMQConnectionFactory:tcp://localhost:11616");
    System.setProperty("aQueue", "queue:org.apache.activemq.command.ActiveMQQueue:LISTENER");
}

When the client resolves a name, it first checks for a system property with that name, after dropping a java: prefix and any comp/env/. If one exists, the value is parsed and the object is created on the client:

  • connectionfactory:, queue: and topic: load the given class through the thread context class loader and call its String constructor with the rest of the value. So new ActiveMQConnectionFactory("tcp://localhost:11616") and new ActiveMQQueue("LISTENER") are created here.

  • The client also knows datasource:, javamail: and link: (the last one points to another system property).

As the comment in the test says, you can also key the value by resource type as Resource/<type>. The client uses that property when the server answers a lookup with a resource of that type.

Creating the ActiveMQConnectionFactory does not open a connection, so nothing has to listen on tcp://localhost:11616 for this test.

The test

SenderTest creates an InitialContext with the remote client factory and looks up both resources with the java: prefix:

@Test
public void send() throws Exception {
    final Properties properties = new Properties();
    properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.RemoteInitialContextFactory");
    final Context context = new InitialContext(properties);

    final Queue destination = (Queue) context.lookup("java:aQueue");
    assertNotNull(destination);
    assertEquals("LISTENER", destination.getQueueName());

    final ConnectionFactory connectionFactory = (ConnectionFactory) context.lookup("java:aConnectionFactory");
    assertNotNull(connectionFactory);
}

It checks that the queue is found and is named LISTENER, and that the connection factory is found. Both are answered from the system properties, so no TomEE server has to be running.

Running

mvn clean test