Why is my JNDI lookup for a QueueConnectionFactory returning null?

36,647

Solution 1

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

Solution 2

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.

Solution 3

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);

    }

}
Share:
36,647
fmunshi
Author by

fmunshi

I am a software engineer working at Google UK in London. All original source snippets I post on stackoverflow are dedicated to the public domain. Do with them as you see fit.

Updated on August 19, 2020

Comments

  • fmunshi
    fmunshi almost 4 years

    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
    
  • fmunshi
    fmunshi almost 15 years
    Geronimo provides a JNDI browsing tool, and both JNDI names appear to be there. Changing the names in my test tool produce a NamingException, so it must be finding something.
  • djna
    djna almost 15 years
    Right, but what is it finding and who put it there? To me all of this points to the problem being in the JMS provider rather than your code.
  • Stephen Harmon
    Stephen Harmon over 14 years
    Wow. Thanks for the thoughtful, thorough answer.