CAMD_3441
CAMD_3441

Reputation: 3154

Can't invoke ActiveMQConnection class directly in a java web servlet

Issue:

I'm trying to set a timeout using ActiveMQConnection object to invoke the setSendTimeout method in my Java servlet but when that code is invoked I get:

Warning:   RAR5038:Unexpected exception while creating resource for pool jms_amq_conn_pool. Exception : javax.resource.ResourceException: Could not create connection.
Warning:   RAR5117 : Failed to obtain/create connection from connection pool [ jms_amq_conn_pool ]. Reason : com.sun.appserv.connectors.internal.api.PoolingException: Could not create connection.

How can I get around this?

Issue in more detail:

I have a Payara server that has an activemq-rar resource loaded that a servlet I have invokes. I followed these instructions to do that.

Here's a list highlighted the steps from that link:

  1. Get activemq rar file to deploy to Payara server.
  2. Configure the ActiveMQ Connector
  3. Create JMS Connection pool
  4. Create JNDI mapping to JMS Connection pool by creating a JMS Resource.

I have Java servlet code that looks like this that works fine when I want it to send a message:

    /**
    * Creates a connection using Payara resource then creates a producer/consumer then sends a message.
    */
    public void sendAMQMessage() {
        javax.jms.ConnectionFactory connectionFactory = InitialContext.doLookup("servlet_jms_amq_conn_factory");
        javax.jms.Connection connection = connectionFactory.createConnection();

        // creation is created, now set the client id and start it
        connection.setClientID("test_client_id");
        connection.start();

        javax.jms.Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        javax.jms.TemporaryQueue queue = session.createTemporaryQueue();

        javax.jms.MessageConsumer consumer = session.createConsumer(queue);

        consumer.setMessageListener(this);

        javax.jms.Queue serviceQueue = session.createQueue("queue_name");

        javax.jms.MessageProducer producer = session.createProducer(serviceQueue);

        producer.send("data");
    
    }


    @Override
    public void onMessage(Message message) {
        // receives data back from the initial request.
    }

The current web application's pom.xml doesn't reference an ActiveMQ library since the code above does not import any ActiveMQ classes. But I want to implement a timeout on the message being sent by the Java servlet so that if the receiving application doesn't respond in a certain amount of time I can handle that.

The javax.jms.Connection does not have a timeout setter method.

The ActiveMQConnection JavaDoc does have a setSendTimeout(int sendTimeout). So I included the ActiveMQ dependency in the app's pom.xml:

        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-all</artifactId>
            <version>5.10.0</version>
            <type>jar</type>
        </dependency>

Then when I update the sendAMQMessage method above to use the setSendTimeout(int sendTimeout):

int milliseconds = 10000; // 10,000 ms = 10 seconds
((ActiveMQConnection)connection).setSendTimeout(milliseconds);

and then run the code I get these warnings and exception messages:

Warning:   RAR5038:Unexpected exception while creating resource for pool jms_amq_conn_pool. Exception : javax.resource.ResourceException: Could not create connection.
Warning:   RAR5117 : Failed to obtain/create connection from connection pool [ jms_amq_conn_pool ]. Reason : com.sun.appserv.connectors.internal.api.PoolingException: Could not create connection.
Warning:   RAR5038:Unexpected exception while creating resource for pool jms_amq_conn_pool. Exception : javax.resource.ResourceException: Could not create connection.
Warning:   RAR5117 : Failed to obtain/create connection from connection pool [ jms_amq_conn_pool ]. Reason : com.sun.appserv.connectors.internal.api.PoolingException: Could not create connection.

javax.jms.JMSException: Error in allocating a connection. Cause: Could not create connection.
    at org.apache.activemq.ra.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:101)
    at org.apache.activemq.ra.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:67)

I've looked at this link which says to just copy the jar to the Payara server's domains/domain1/ilb/ext folder. So I did that with the activemq-all-5.10.0.jar then when I run the code above I get this exception:

java.lang.ClassCastException: org.apache.activemq.command.ActiveMQQueue cannot be cast to javax.jms.Queue

There must be a way to resolve this. Anyone have thoughts?

Upvotes: 0

Views: 591

Answers (1)

Justin Bertram
Justin Bertram

Reputation: 35008

The timeout you're referring to is not related to how long it takes the consumer who receives message to "respond." The timeout is simply about how long the sending client will wait for the broker to acknowledge that it has indeed received the message. This happens before the consumer ever receives the message.

If you're implementing request/response functionality with JMS then you should follow the proper pattern either using correlation ID or temporary reply queues.

Given that you're using the ActiveMQ JCA resource adapter it's very likely the connection implementation your client actually gets from the JNDI lookup will be wrapped by the JCA implementation of your container. It's unlikely you will be able to simply cast it to the ActiveMQ implementation. Furthermore, all the ActiveMQ client classes are packaged in the JCA resource adapter archive and isolated from your application. You're likely to get weird classloading behavior (e.g. unexpected ClassCastException) if you put those same classes somewhere else in your runtime environment. Java EE application servers are designed to give access to the Java EE APIs (e.g. JMS, JDBC, JNDI, etc.). Getting access to the underlying implementations to do non-portable stuff is generally difficult and discouraged.

Upvotes: 2

Related Questions