camel-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Stanislaw Kulczycki <gr...@kce.one.pl>
Subject Camel-SJMS: Glassfish 4.1 OpenMQ createSession():An active Session object already exists for this connection, only one active Session object allowed per connection.
Date Thu, 12 Mar 2015 18:06:38 GMT
Hi All,

first of all as I'm new here I would like to say Hello! In addition to this
I want to say that I'm fan of Camel and I think that it is great software
and I'm very happy that I can use it in my project. 

second - unfortunately I have a problem. I'm trying to use camel-sjms
(v2.14.2) component with Glassfish 4.1 OpenMQ JMS and it is not working well
;-( 

Small background:
- I'm using Camel 2.14.2 (and 2.14.1) with Camel-CDI
- JDK 1.8.0_20
- JMS Connection Factory is obtained via Injection:
    @Resource(mappedName = "jms/__defaultConnectionFactory")
    private ConnectionFactory jmsConnectionFactory;
- I'm using default Glassfish JMS configuration
- Everything works properly with Camel-JMS (spring one)

Ok, problems:

1) When I create SJMS component this way:

SjmsComponent sjms = new SjmsComponent();
sjms.setConnectionCount(10);
sjms.setConnectionFactory(jmsConnectionFactory);
camelCtx.addComponent("sjms", sjms);

and I'm starting to use it in the route I'm getting errors:

Info:   2015-03-12 18:44:19 WARN  TimerConsumer:136 - Error processing
exchange. Exchange[Message: EmptyBody]. Caused by: [java.lang.Exception -
Unable to send message: connection not available]
java.lang.Exception: Unable to send message: connection not available
	at
org.apache.camel.component.sjms.SjmsProducer.process(SjmsProducer.java:168)

Apparently component is not being started by the context. In order to make
it "work" I have to explicitly execute: sjms.start(); after adding it to the
context.

Is this desired behaviour? I think that it is not, as "Connection pool" is
populated only in components doStart function.

Everything is fine when I do this instead of setConnectionFactory:
sjms.setConnectionResource(new ConnectionFactoryResource(10,
jmsConnectionFactory));

Funny enough even if routes are "working" component says that it is in
"Stopped" state.

2)  Problem number 2. I'm getting One Session per connection error when I'm
trying to use SJMS with OpenMQ from Glassfish.

Lets assume that I have two routes:

	from("sjms:queue:bar54")
			.log("Body rcvd: ${body}")
			.setBody(constant("Go go"));

	from("timer://foo?period=1000")
			.removeHeaders("*") //Remove headers as fire time (Date) is not supported
in JMS headers
			.setBody(constant("EmptyBody"))
			.log("Send msg")
			.to("sjms:queue:bar54");

with this configuration I'm getting following error:

Info:   17:17:17.792 [admin-listener(5)] ERROR
o.a.c.c.sjms.producer.InOnlyProducer -            - Unable to create the
MessageProducer
javax.jms.JMSException: MQJMSRA_DC4001: createSession():An active Session
object already exists for this connection, only one active Session object
allowed per connection.
    at
com.sun.messaging.jms.ra.DirectConnection.checkSessionsAllowed(DirectConnection.java:1064)
~[imqjmsra.jar:na]
    at
com.sun.messaging.jms.ra.DirectConnection.createSession(DirectConnection.java:398)
~[imqjmsra.jar:na]
    at
org.apache.camel.component.sjms.producer.InOnlyProducer.doCreateProducerModel(InOnlyProducer.java:70)
~[camel-sjms-2.14.1.jar:2.14.1]
    at
org.apache.camel.component.sjms.SjmsProducer$MessageProducerResourcesFactory.makeObject(SjmsProducer.java:44)
[camel-sjms-2.14.1.jar:2.14.1]
    at
org.apache.camel.component.sjms.SjmsProducer$MessageProducerResourcesFactory.makeObject(SjmsProducer.java:40)
[camel-sjms-2.14.1.jar:2.14.1]
    at
org.apache.commons.pool.impl.GenericObjectPool.addObject(GenericObjectPool.java:1691)
[commons-pool-1.6.jar:1.6]
    at
org.apache.camel.component.sjms.SjmsProducer.fillProducersPool(SjmsProducer.java:112)
[camel-sjms-2.14.1.jar:2.14.1]
    at
org.apache.camel.component.sjms.SjmsProducer.doStart(SjmsProducer.java:104)
[camel-sjms-2.14.1.jar:2.14.1]
    at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
[camel-core-2.14.1.jar:2.14.1]
    (...)


So I have digged into the code into and tried to understand how this
happens. After quick investigation I thin that this problem is related to
the Pooling and the way it works. Apparently SJMS is borrowing connection,
creating session and returning connection to the pool instantly after
creation of the endpoint. It is not preserving used connections. Maybe with
activeMQ it is fine but this does not work correctly in Glassfish and with
OpenMQ.

Please find extract from the actual code which I think is not working as
expected.

e.g.:
https://github.com/apache/camel/blob/master/components/camel-sjms/src/main/java/org/apache/camel/component/sjms/producer/InOnlyProducer.java

 @Override
    public MessageProducerResources doCreateProducerModel() throws Exception
{
        MessageProducerResources answer;
        Connection conn = getConnectionResource().borrowConnection(); //
<---- Connection is taken from the pool
        try {
            TransactionCommitStrategy commitStrategy = null;
            if (isEndpointTransacted()) {
                commitStrategy = getCommitStrategy() == null ? new
DefaultTransactionCommitStrategy() : getCommitStrategy();
            }
            Session session = conn.createSession(isEndpointTransacted(),
getAcknowledgeMode()); // <---- Session is created 
            Destination destination =
getEndpoint().getDestinationCreationStrategy().createDestination(session,
getDestinationName(), isTopic());
            MessageProducer messageProducer =
JmsObjectFactory.createMessageProducer(session, destination, isPersistent(),
getTtl());

            answer = new MessageProducerResources(session, messageProducer,
commitStrategy);

        } catch (Exception e) {
            log.error("Unable to create the MessageProducer", e);
            throw e;
        } finally {
            getConnectionResource().returnConnection(conn); // <------- HERE
connection is released
        }
        return answer;
    }

And it got me thinking - is it a good place (doCreateProducerModel) to
return connection to the pool? I think that this code assumes that
connection is not longer needed for this session and is being released to be
used by other resources.  
This does not look correct for me and I would expect that connection is
released After session is "stopped" or closed. In camel words I would say
when endpoint is stopped.

Shouldn't be this getConnectionResource().returnConnection(conn); moved to
other location like destroyObject() function in
(...)/camel/component/sjms/SjmsProducer.java ? This way connection would be
kept for whole duration of the session and returned when endpoint is
stopped.  Here I refered to producer but Consumer logic is the same.

Btw. I have made SJMS+OpenMQ kind of work without pooling with following
custom ConnectionResource class. I say that it kind of works but problem is
that connections are not being released to container and they are alive
forever. 

public class MyOpenMqConnectionResource implements ConnectionResource {    
    private final ConnectionFactory factory;
    private final Logger logger =
Logger.getLogger(MQConnectionResource.class.getName());    

    MQConnectionResource(ConnectionFactory connectionFactory) {
        factory = connectionFactory;        
    }

    @Override
    public Connection borrowConnection() throws Exception {
        logger.info("Creating connection");
        Connection conn = factory.createConnection();
        conn.start();
        return conn;
    }

    @Override
    public void returnConnection(Connection connection) throws Exception {
        logger.info("Returning connection");
		// To get session closed exception you could add here:
		// connection.close();
    }    
}

With connection.closed() commented out log would look like this:

Info:   2015-03-12 18:18:23 INFO  CdiCamelContext:1757 - Apache Camel 2.14.2
(CamelContext: camel-2) started in 0.422 seconds
Info:   Creating connection <--- Borrowing connection
Info:   Returning connection <--- Returning connection
Info:   2015-03-12 18:18:24 INFO  CdiCamelContext:2443 - Route: route1
started and consuming from: Endpoint[sjms://queue:bar54]
Info:   Creating connection <--- Borrowing connection
Info:   Returning connection<--- Returning connection
Info:   2015-03-12 18:18:24 INFO  CdiCamelContext:2443 - Route: route2
started and consuming from: Endpoint[timer://foo?period=1000]
Info:   2015-03-12 18:18:24 INFO  CdiCamelContext:1721 - Apache Camel 2.14.2
(CamelContext: camel-2) is starting
Info:   2015-03-12 18:18:24 INFO  CdiCamelContext:1756 - Total 2 routes, of
which 2 is started.
Info:   2015-03-12 18:18:24 INFO  CdiCamelContext:1757 - Apache Camel 2.14.2
(CamelContext: camel-2) started in 0.000 seconds
Info:   Loading application [CamelSjmsSample] at [/CamelSjmsSample]
Info:   CamelSjmsSample was successfully deployed in 5,050 milliseconds.
Info:   2015-03-12 18:18:25 INFO  route2:96 - Send msg
Info:   2015-03-12 18:18:25 INFO  route1:96 - Body rcvd: EmptyBody <--
message received however all connections are in the pool.
Info:   2015-03-12 18:18:26 INFO  route2:96 - Send msg
Info:   2015-03-12 18:18:26 INFO  route1:96 - Body rcvd: EmptyBody

I hope that this shows clearly that there are 2 sessions working and there
were 2 connections "created" and returned to the pool for reuse. I think
that with current code one connection would be used all the time in any
case.

Ok, so is it desired behaviour or I is it me who understand it in wrong way?
;-)

Thanks & Kind regards,
Stan



--
View this message in context: http://camel.465427.n5.nabble.com/Camel-SJMS-Glassfish-4-1-OpenMQ-createSession-An-active-Session-object-already-exists-for-this-conne-tp5764057.html
Sent from the Camel - Users mailing list archive at Nabble.com.

Mime
View raw message