users@glassfish.java.net

Re: Trouble connecting MDB to external JMS destination

From: Comerford, Sean <Sean.Comerford_at_espn.com>
Date: Tue, 26 Jun 2012 17:14:09 -0400

Hey Nigel,

Yeah, my feeling is you're right – you cannot set the resource adapter name to use anywhere except the ejb-jar.xml

I've gotten a bit further at this point but I don't know how to tell the IBM resource adapter what connection factory to use.

I have a connection factory resource defined on the instance as jms/UTQueueConnectionFactory but don't see anyway to tell the IBM resource adapter to use it.

The generic mms adapter has properties like ConnectionFactoryJndiName and DestinationJndiName but IBM's adapter only appears to support an activation JNDI property for the destination and still expects the host, port, etc of the queue manager which obviously is not portable between application environments (I.e. dev, QA, prod).

I don't suppose anyone out there has successfully pulled this off?

---
Sean Comerford
ESPN.com Architecture & Platforms
From: Nigel Deakin <nigel.deakin_at_oracle.com<mailto:nigel.deakin_at_oracle.com>>
Reply-To: "users_at_glassfish.java.net<mailto:users_at_glassfish.java.net>" <users_at_glassfish.java.net<mailto:users_at_glassfish.java.net>>
Date: Tue, 26 Jun 2012 05:19:10 -0400
To: "users_at_glassfish.java.net<mailto:users_at_glassfish.java.net>" <users_at_glassfish.java.net<mailto:users_at_glassfish.java.net>>
Subject: Re: Trouble connecting MDB to external JMS destination
Hi Sean,
There's nothing in your MDB configuration to tell GlassFish to use the IBM resource adapter.
The exception you're seeing is from ActiveJmsResourceAdapter - that is because by default it's trying to use the built-in JMSRA resource adapter to talk to GlassFish MQ, and you don't want that.
You need to configure the resource adapter in glassfish-ejb-jar.xml (I don't think you can set this anywhere else)
<glassfish-ejb-jar>
  <enterprise-beans>
    <ejb>
      <ejb-name>ejbname</ejb-name>
      <mdb-resource-adapter>
        <resource-adapter-mid>raname</resource-adapter-mid>
       . . .
...where "raname" is the name of the resource adapter. This is the name you'll have specified previously when you created the connection factory and destination objects.
 "ejbname" is the fully-qualified class name since you don't set this using @MessageDriven(name="ejbname")
Don't set @MessageDriven(mappedName="...") - that's not used.
Nigel
On 25/06/2012 23:23, Comerford, Sean wrote:
Using GF 3.1 here.
I have a Websphere MQ connection pool and factory defined on my GF instance using IBM's wmq.jmsra RAR.
I can publish using this simple servlet code below.
    @Resource(mappedName = "jms/UTTopicFactory")
    private TopicConnectionFactory topicConnectionFactory;
    @Resource(mappedName = "jms/UTTopic")
    private Topic topic;
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            String msgText = request.getParameter("msgText");
            sendToTopic(msgText);
        } catch (Exception e) {
            out.print(e.toString());
        }
    }
    private void sendToTopic(String msgText) throws Exception  {
        TopicConnection connection = topicConnectionFactory.createTopicConnection();
        TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
        MessageProducer messageProducer = session.createProducer(topic);
        TextMessage textMessage = session.createTextMessage();
        textMessage.setText(msgText);
        messageProducer.send(textMessage, DeliveryMode.PERSISTENT, TextMessage.DEFAULT_PRIORITY, 1000);
        messageProducer.send(textMessage);
        messageProducer.close();
        session.close();
        connection.close();
    }
And I read from it using this simple servlet:
    @Resource(mappedName = "jms/UTTopicFactory")
    private TopicConnectionFactory topicConnectionFactory;
    @Resource(mappedName = "jms/UTTopic")
    private Topic topic;
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            out.write("Topic response = " + readTopic());
        } catch (Exception e) {
            out.write("Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            out.close();
        }
    }
    private String readTopic() throws Exception {
        String result = null;
        TopicConnection connection = topicConnectionFactory.createTopicConnection();
        TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
        TopicSubscriber subscriber = session.createDurableSubscriber(topic, "SEAN.TEST");
        connection.start();
        TextMessage textMessage = (TextMessage) subscriber.receive(10000);
        if (textMessage != null) {
            System.out.println("Got " + textMessage.getText());
            result = "Retrieved message from topic: " + textMessage.getText();
            textMessage.acknowledge();
        } else {
            System.out.println("No messages in topic");
            result = "No messages in topic";
        }
        subscriber.close();
        session.close();
        connection.close();
        return result;
    }
My (possibly dumb) question is how do I create a MDB that talks to the topic in the same way as the servlet above – by just referencing the JNDI name. Tried this:
@MessageDriven(mappedName = "jms/UTTopic", activationConfig = {
    @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
    @ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "Durable"),
    @ActivationConfigProperty(propertyName = "clientId", propertyValue = "MyMDB"),
    @ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "SEAN.TEST")
})
public class MyMDB implements MessageListener {
    public MyMDB() {
    }
    @Override
    public void onMessage(Message message) {
    }
}
But this won't deploy properly – yields:
SEVERE: Exception while loading the app : EJB Container initialization error
com.sun.appserv.connectors.internal.api.ConnectorRuntimeException: Could not find physical destination : null
at com.sun.enterprise.connectors.jms.system.ActiveJmsResourceAdapter.getPhysicalDestinationFromConfiguration(ActiveJmsResourceAdapter.java:2068)
at com.sun.enterprise.connectors.jms.system.ActiveJmsResourceAdapter.updateMDBRuntimeInfo(ActiveJmsResourceAdapter.java:1864)
at com.sun.enterprise.connectors.inbound.ConnectorMessageBeanClient.setup(ConnectorMessageBeanClient.java:186)
at com.sun.ejb.containers.MessageBeanContainer.<init>(MessageBeanContainer.java:205)
at com.sun.ejb.containers.ContainerFactoryImpl.createContainer(ContainerFactoryImpl.java:121)
at org.glassfish.ejb.startup.EjbApplication.loadContainers(EjbApplication.java:230)
at org.glassfish.ejb.startup.EjbDeployer.load(EjbDeployer.java:290)
at org.glassfish.ejb.startup.EjbDeployer.load(EjbDeployer.java:101)
at org.glassfish.internal.data.ModuleInfo.load(ModuleInfo.java:186)
at org.glassfish.internal.data.ApplicationInfo.load(ApplicationInfo.java:257)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:461)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:240)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:382)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:355)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:370)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1064)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl.java:96)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1244)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1232)
at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:459)
at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:209)
at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:168)
at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:117)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:238)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:680)
Bear in mind the topic here is an EXTERNAL topic being provided by the web sphere MQ resource adapter.
Any help?
---
Sean Comerford
ESPN.com Architecture & Platforms