Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my JNDI lookup for a QueueConnectionFactory returning null?

I am trying to look up a QueueConnectionFactory and Queue via Geronimo's JNDI. The Queue gets returned fine, but the QueueConnectionFactory lookup always returns null. It doesn't throw a NamingException, which is what I'd expect if the JNDI name was incorrect.

Can anyone see what I'm doing wrong? The test code below outputs:

true
false

import javax.jms.Queue;
import javax.jms.QueueConnectionFactory;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class JndiTest
{
    private final static String QUEUE_NAME = "jca:/org.apache.geronimo.configs/activemq-ra/JCAAdminObject/SendReceiveQueue";
    private final static String FACTORY_NAME = "jca:/org.apache.geronimo.configs/activemq-ra/JCAManagedConnectionFactory/DefaultActiveMQConnectionFactory";

    public static void main(String[] args) throws NamingException
    {
        InitialContext ctx = new InitialContext();
        QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup(FACTORY_NAME);
        Queue queue = (Queue)ctx.lookup(QUEUE_NAME);
        System.out.println(factory == null);
        System.out.println(queue == null);      
    }

}

In case it makes a difference: I've added openejb-client-3.0.1.jar, geronimo-ejb_3.0_spec-1.0.1.jar and activemq-core-4.1.2-G20090207.jar to my class path, and my jndi.properties file has the properties:

java.naming.factory.initial = org.apache.openejb.client.RemoteInitialContextFactory
java.naming.provider.url = ejbd://127.0.0.1:4201
like image 820
Simon Nickerson Avatar asked Aug 26 '09 08:08

Simon Nickerson


3 Answers

The reason why it is not throwing an exception is that - there is a ClassLoadException that comes when the resource is accessed.

And the reason why that is happening because the class : com.sun.jndi.url.jca.jcaURLContextFactory is being searched for by the ClassLoader called from ResourceManager.

If you change the Factory name to some other name then you shall see the NamingException - but in the case of lookup , for Exceptions such as ClassNotFound/IllegalState - no exceptions are raised.

The dependencies of ActiveMQ thus need to be analysed. Update1: One of the possible reasons is that the factory object can only be instantiated in a managed environment. Are you running your code as an application client?.

Update2: Some other pointers found for the cause of this behavior:

the openejb jndi implementation only exposes ejbs, not any other resources. If you have a j2ee app client, and you wish to use jms, you need to deploy a copy of the activemq adapter on the client. You can then use the j2ee java:comp/env context to find your stuff.

Found this on ActiveMQ site:

ActiveMQ's JNDI Implementation does NOT talk to the naming server. It's a stripped down version of a JNDI client that just allows to get Topics and Queues directly from a JMS instance. So, instead of supplying the naming server address, you have to supply the JMS server address.Most JNDI implementations use the java.naming.provider.url property to specify the naming server's address. ActiveMQ uses the brokerURL one. Using the java.naming.provider.url one instead will result in ActiveMQ trying to load the whole Broker.

See more on how to Connect using JNDI:

The initial context factory used in the explanation is: org.apache.activemq.jndi.ActiveMQInitialContextFactory

Some sample code to test with JNDI can be found here

I wrote a simple java client - note below the provider url is the brokerURL that is being used.

    Properties props = new Properties();            
props.put(Context.INITIAL_CONTEXT_FACTORY,
             "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
    //props.put(Context.PROVIDER_URL,"vm://localhost");//Either this or below
    props.put(Context.PROVIDER_URL,"tcp://localhost:65432"); 
    props.put("queue.SendReceiveQueue",
         "org.apache.geronimo.configs/activemq-ra/JCAAdminObject/SendReceiveQueue");
      
    InitialContext context = new InitialContext(props);   
    QueueConnectionFactory connectionFactory = (QueueConnectionFactory)context.lookup
                                                               ("ConnectionFactory");
    Queue q = (Queue) context.lookup("SendReceiveQueue");
    System.out.println("conn is : "  + connectionFactory.getClass().getName());
    System.out.println("queue is : " + q.getQueueName());

This program gives the output:

conn is : org.apache.activemq.ActiveMQConnectionFactory queue is : org.apache.geronimo.configs/activemq-ra/JCAAdminObject/SendReceiveQueue

like image 79
techzen Avatar answered Nov 08 '22 13:11

techzen


I have a somewhat equivalent configuration Tomcat/Geronimo J2EE jar / Geronimo JMS Jar / ActiveMQ 4 And i'm a little bit confused about your jndi.propertie file. Mine looks like this :

java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory

java.naming.provider.url = tcp://localhost:61616

connectionFactoryNames = connectionFactory , TopicConnectionFactory

The big difference is obviousely that your initial context is remote. Beside that, i must provide a connectionFactoryNames, or i get a NamingException.

like image 22
Antoine Claval Avatar answered Nov 08 '22 14:11

Antoine Claval


I don't know why, but for me, using a context didn't work. It seems that the message is sent, but the onMessage of my consumer is not called.

Using a context don't throw exception but don't work :

import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;

public class HelloClient {

public static void main(String[] args) throws Exception {
    Properties ppt2 = new Properties();
    ppt2.put(Context.INITIAL_CONTEXT_FACTORY,
            "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
    ppt2.put(Context.PROVIDER_URL, "tcp://localhost:61616");
    ppt2.put("topic.MessageDestinationTopic", "console.jms/TopicQueue/JCAAdminObject/MessageDestinationTopic");
    Context ctx2 = new InitialContext(ppt2);

    TopicConnectionFactory factory = (TopicConnectionFactory) ctx2.lookup("ConnectionFactory");
    TopicConnection connection = factory.createTopicConnection();
    TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
    Topic topic = (Topic) ctx2.lookup("MessageDestinationTopic");

    MessageProducer producer = session.createProducer(topic);

    TextMessage msg = session.createTextMessage();
    msg.setText("this is a test message");
    producer.send(msg);
    producer.close();
    session.close();
    System.out.println("Message published. Please check application server's console to see the response from MDB");
    ctx2.close();
    System.exit(0);

}

}

Using the code below ( without context ) works well :

import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;

public class HelloClient {

    public static void main(String[] args) throws Exception {

        TopicConnectionFactory factory = new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616");
        TopicConnection connection = factory.createTopicConnection();
        TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
        Topic topic = session.createTopic("MessageDestinationTopic");

        MessageProducer producer = session.createProducer(topic);

        TextMessage msg = session.createTextMessage();
        msg.setText("this is a test message");
        producer.send(msg);
        producer.close();
        session.close();
        System.out.println("Message published. Please check application server's console to see the response from MDB");
        System.exit(0);

    }

}
like image 39
Grégory Avatar answered Nov 08 '22 14:11

Grégory