2009-08-26 10 views
7

Estoy tratando de buscar un QueueConnectionFactory y Queue a través del JNDI de Geronimo. El Queue se devuelve bien, pero la búsqueda QueueConnectionFactory siempre devuelve nulo. No arroja un NamingException, que es lo que esperaría si el nombre JNDI fuera incorrecto.¿Por qué mi búsqueda JNDI para QueueConnectionFactory devuelve nulo?

¿Alguien puede ver lo que estoy haciendo mal? El código de prueba por debajo de las salidas:

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

} 

En caso de que se hace una diferencia: He añadido openejb-cliente-3.0.1.jar, geronimo-ejb_3.0_spec-1.0.1.jar y activemq -núcleo-4.1.2-G20090207.jar a mi camino de clase, y mi archivo jndi.properties tiene las propiedades:

 
java.naming.factory.initial = org.apache.openejb.client.RemoteInitialContextFactory 
java.naming.provider.url = ejbd://127.0.0.1:4201 

Respuesta

12

La razón por la que no se lanza una excepción es que - hay una excepción ClassLoadException que se produce cuando se accede al recurso.

Y la razón por la que eso está sucediendo porque la clase: com.sun.jndi.url.jca.jcaURLContextFactory está siendo buscada por el ClassLoader llamado desde ResourceManager.

Si cambia el nombre de fábrica a otro nombre, verá la NamingException, pero en el caso de la búsqueda, para Excepciones como ClassNotFound/IllegalState, no se generarán excepciones.

Por lo tanto, es necesario analizar las dependencias de ActiveMQ. Update1: Una de las posibles razones es que el objeto de fábrica solo se puede crear una instancia en un entorno administrado. ¿Estás ejecutando tu código como cliente de aplicaciones ?.

Update2: Algunos otros indicadores encontrados para la causa de este comportamiento:

la implementación jndi openejb única expone ejbs, y no cualquier otro recurso. Si tiene un cliente de la aplicación j2ee y desea usar jms, necesita desplegar una copia del adaptador activemq en el cliente. A continuación, puede usar el contexto j2ee java: comp/env para encontrar sus cosas.

encontrado esto en el sitio ActiveMQ: Implementación JNDI

de ActiveMQ no habla con el servidor de nombres. Es una versión reducida de un cliente JNDI que solo permite obtener Temas y colas directamente desde una instancia JMS.Por lo tanto, en lugar de proporcionar la dirección del servidor de nombres, debe proporcionar la dirección del servidor JMS. La mayoría de las implementaciones JNDI utilizan la propiedad java.naming.provider.url para especificar la dirección del servidor de nombres. ActiveMQ utiliza el brokerURL. El uso de java.naming.provider.url en su lugar dará como resultado que ActiveMQ intente cargar todo el Broker.

Ver más sobre cómo Connect using JNDI:

La factoría de contexto inicial utilizado en la explicación es: org.apache.activemq.jndi.ActiveMQInitialContextFactory código

Parte de la muestra para probar con JNDI se puede encontrar here

Escribí un cliente simple de Java - observe a continuación la url del proveedor es el brokerURL que se está utilizando.

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

Este programa da la salida:

conn es: org.apache.activemq.ActiveMQConnectionFactory cola es: org.apache.geronimo.configs/activemq-ra/JCAAdminObject/SendReceiveQueue

+0

Wow. Gracias por la respuesta reflexiva y completa. –

0

Hay dos participantes aquí, que está buscando en JNDI para algo. Alguien más tuvo que ponerlo allí. No sé los detalles de su entorno, pero mi enfoque para tales problemas es

  • explorar el espacio de nombres, ¿qué hay allí? ¿Tienes alguna herramienta de navegación JNDI?
  • mirar carfeully en los registros para el servicio que se supone que se registra con JNDI, ¿informa algún error?
+0

Geronimo proporciona una herramienta de navegación JNDI, y ambos nombres JNDI parecen estar allí. Cambiar los nombres en mi herramienta de prueba produce una NamingException, por lo que debe encontrar * algo *. –

+0

Correcto, pero ¿qué es lo que encuentra y quién lo colocó allí? Para mí, todo esto apunta al problema que está en el proveedor JMS en lugar de su código. – djna

1

Tengo una configuración algo equivalente jar Tomcat/Geronimo J2EE/Geronimo JMS Jar/ActiveMQ 4 Y estoy un poco confundido acerca de su archivo jndi.propertie. mina se parece a esto:

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

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

connectionFactoryNames = connectionFactory , TopicConnectionFactory

La gran diferencia es que obviousely su contexto inicial es remota. Además de eso, debo proporcionar una connectionFactoryNames u obtener una NamingException.

1

No sé por qué, pero para mí, usar un contexto no funcionó. Parece que se envía el mensaje, pero no se llama al onMessage de mi consumidor.

Usando un contexto no tirar excepción, pero no funcionan:

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

} 

} 

Usando el código de abajo (fuera de contexto) funciona bien:

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

    } 

} 
Cuestiones relacionadas