DBCP Idle Connections not being reused in Camel Route - jdbc

I am pretty sure the idle connections are not being re-used or I am leaking connections. I have a simple route that start from a file consumer. The file consumer consumes text files. After picking up the file I check a table to ensure that this is not a duplicate file.
I then convert the message body from a file to string. I then split the file up and run the individual pieces through a route depending on what type of record it is. Each one of these routes eventually inserts this record into staging table on a server running on MySQL.
Below is a simplified version of the route.
<bean id="myPool" class="java.util.concurrent.Executors" factory-method="newFixedThreadPool">
<argument index="0" value="8"/>
</bean>
<camelContext trace="false" handleFault="true" errorHandlerRef="redeliveryErrorHandler" id="FileETLProcess" xmlns="http://camel.apache.org/schema/blueprint">
<errorHandler type="DefaultErrorHandler" useOriginalMessage="true" id="redeliveryErrorHandler">
<redeliveryPolicy maximumRedeliveries="3" redeliveryDelay="25" backOffMultiplier="2" useExponentialBackOff="false" retryAttemptedLogLevel="INFO"/>
</errorHandler>
<onException useOriginalMessage="true">
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<log message="STARTING ERROR GENERAL HANDLER"/>
<bean ref="GeneralError"/>
<to uri="smtp://mailsrv?to=x.x#yadda.com&from=Error#Camel.com.au&subject=GENERAL ERROR: A File Could Not Be Imported&contentType=text/html"/>
<to uri="file:d:/Inbox/.badFile?fileName=${file:onlyname.noext}_GENERALERROR_${date:now:yyyyMMddHHmmss}.${file:name.ext}"/>
</onException>
<route id="ExtractFileRoute">
<from uri="file:d:/Inbox?delay=10000&move=.donebackup/${date:now:yyyyMMdd}/${file:onlyname.noext}_DONE_${date:now:yyyyMMddHHmmss}.${file:name.ext}&readLock=changed&include=.*.dl&maxMessagesPerPoll=0&sortBy=${file:length}"/>
<bean ref="FileCheck"/>
<choice>
<when>
<simple>${header.ACCEPTEDFILE} == 'YES'</simple>
<log message="File Import Route Started At:${date:now:yyyy-MM-dd HH:mm:ss}"/>
<convertBodyTo type="java.lang.String"/>
<log message="Converted File To String:${date:now:yyyy-MM-dd HH:mm:ss} handing data to File To DB route."/>
<split parallelProcessing="true" executorServiceRef="myPool" streaming="true" shareUnitOfWork="true">
<tokenize token="\n"></tokenize>
<setHeader headerName="SPLITFINISHED">
<simple>${property.CamelSplitComplete}</simple>
</setHeader>
<setHeader headerName="SPLITNUMBER">
<simple>${property.CamelSplitIndex}</simple>
</setHeader>
<bean ref="EnrichHeader"/>
<choice>
<when>
<simple>${header.RECORDTYPE} == 'HEADER'</simple>
<doTry>
<unmarshal ref="bindyHeader"/>
<bean ref="HeaderPersist"/>
<choice>
<when>
<simple>${property.CamelSplitComplete} == true</simple>
<to uri="direct:auxrecordsmove"/>
</when>
</choice>
<doCatch>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<bean ref="RecordErrorReport"/>
<choice>
<when>
<simple>${property.CamelSplitComplete} == true</simple>
<to uri="direct:auxrecordsmove"/>
</when>
</choice>
</doCatch>
</doTry>
</when>
<when>
<simple>${header.RECORDTYPE} == 'A'</simple>
<doTry>
<unmarshal ref="bindyAccount"/>
<bean ref="AccountPersist"/>
<choice>
<when>
<simple>${property.CamelSplitComplete} == true</simple>
<to uri="direct:auxrecordsmove"/>
</when>
</choice>
<doCatch>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<bean ref="RecordErrorReport"/>
<choice>
<when>
<simple>${property.CamelSplitComplete} == true</simple>
<to uri="direct:auxrecordsmove"/>
</when>
</choice>
</doCatch>
</doTry>
</when>
<when>
<simple>${header.RECORDTYPE} == 'C'</simple>
<doTry>
<unmarshal ref="bindyComaker"/>
<bean ref="CoMakerPersist"/>
<choice>
<when>
<simple>${property.CamelSplitComplete} == true</simple>
<to uri="direct:auxrecordsmove"/>
</when>
</choice>
<doCatch>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<bean ref="RecordErrorReport"/>
<choice>
<when>
<simple>${property.CamelSplitComplete} == true</simple>
<to uri="direct:auxrecordsmove"/>
</when>
</choice>
</doCatch>
</doTry>
</when>
Some other beans here........
<when>
<simple>${property.CamelSplitComplete} == true</simple>
<to uri="direct:auxrecordsmove"/>
</when>
<otherwise>
<to uri="smtp://ims-mail?to=ops#ipanic&from=Error#yadda.com&subject=URGENT:UNKOWN RECORD TYPE FOUND IN FILE"/>
<choice>
<when>
<simple>${property.CamelSplitComplete} == true</simple>
<to uri="direct:auxrecordsmove"/>
</when>
</choice>
</otherwise>
</choice>
</split>
</when>
<otherwise>
<to uri="file:d:/RMSInbox/.badFile?fileName=${file:onlyname.noext}_POSSIBLE_DUPLICATE_ERROR_${date:now:yyyyMMddHHmmss}.${file:name.ext}"/>
<bean ref="FileErrorReport"/>
<to uri="smtp://ims-mail?to=ops#panic.com&from=Error#yadda.com&subject=ERROR: A File Could Not Be Imported&contentType=text/html"/>
</otherwise>
</choice>
</route>
So each message on this route eventually hits a bean which will insert it into a database. So I added DBCP to the dependencies and then declare it in my osgi xml blueprint as follows:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://Canttouchthis:3306/ETLDB"/>
<property name="username" value="ETLUser"/>
<property name="password" value="password"/>
<property name="initialSize" value="2"/>
<property name="maxActive" value="16"/>
<property name="maxIdle" value="16"/>
<property name="minIdle" value="2"/>
<property name="timeBetweenEvictionRunsMillis" value="180000"/>
<property name="minEvictableIdleTimeMillis" value="180000"/>
<property name="testOnBorrow" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="validationQuery" value="SELECT 1"/>
<property name="maxWait" value="10000"/>
<property name="removeAbandoned" value="true"/>
<property name="logAbandoned" value="false"/>
<property name="removeAbandonedTimeout" value="300"/>
</bean>
I also declare my beans that will do the processing like this:
<bean id="AccountPersist" class="com.foo.NewAccount.AccountInformationToDatabase">
<property name="dataSource" ref="dataSource"/>
</bean>
Now when the split on the file has been finished I want to ensure that the records match up. Basically the file has account records and some auxiliary information. So I check in the routes when the split is finished and then once the file is completely in the staging tables I run some additional sanity checks in MySQL.
This second route looks something like this:
<route trace="false" id="MoveMatchingAuxRecordsFromStage">
<from uri="direct:auxrecordsmove"/>
<log message="File Import Route Ended At:${date:now:yyyy-MM-dd HH:mm:ss}"/>
<log message="ETL Route Start AT: ${date:now:yyyy-MM-dd HH:mm:ss}"/>
<log message="Moving Matching Comaker records at: ${date:now:yyyy-MM-dd HH:mm:ss}"/>
<bean ref="CoMakerETL"/>
<log message="Matching Comaker records move finised at: ${date:now:yyyy-MM-dd HH:mm:ss}"/>
<log message="Moving Matching Credit History records at: ${date:now:yyyy-MM-dd HH:mm:ss}"/>
<bean ref="CreditHistoryETL"/>
<log message="Matching Credit History records move finised at: ${date:now:yyyy-MM-dd HH:mm:ss}"/>
<log message="Moving Matching Extra Detail records at: ${date:now:yyyy-MM-dd HH:mm:ss}"/>
<bean ref="ExtraDetailInformationETL"/>
<log message="Matching Extra Detail records move finised at: ${date:now:yyyy-MM-dd HH:mm:ss}"/>
<log message="Moving Legal Information records at: ${date:now:yyyy-MM-dd HH:mm:ss}"/>
<bean ref="LegalInformationETL"/>
<log message="Matching Legal Information records move finised at: ${date:now:yyyy-MM-dd HH:mm:ss}"/>
<log message="ETL Route Finished At ${date:now:yyyy-MM-dd HH:mm:ss}"/>
</route>
So in my testing everything went fine I could import a file quiet effectively like this. My problems started when I placed more than 5 files in the folder. Basically I watch MySQL grow the connection pool to the maximum size and then not re-use the connections.
So we hit 16 concurrent connections they go to sleep after the a couple of files has been loaded then somewhere at the 4,5,6 file all of a sudden I get the following error:
Cannot get a connection, pool error Timeout waiting for idle object
Or as it appears in the log
[ pool-3-thread-35] oveMatchingAuxRecordsFromStage INFO Matching Extra Detail records move finised at: 2013-07-26 17:41:59
[ pool-3-thread-35] oveMatchingAuxRecordsFromStage INFO Moving Legal Information records at: 2013-07-26 17:41:59
[ pool-3-thread-35] DefaultErrorHandler INFO Failed delivery for (MessageId: ID-IMS-WS2013-001-52799-1374824474993-0-2693 on ExchangeId: ID-IMS-WS2013- 001-52799-1374824474993-0-3230). On delivery attempt: 0 caught: java.lang.Exception: Cannot get a connection, pool error Timeout waiting for idle object
[thread #0 - file://d:/RMSInbox] ExtractRMSNewAccountFileRoute INFO STARTING ERROR GENERAL HANDLER
The MySQL max connections have been pushed to a massive 512. I have tried various pool sizes, threading options etc.
As a matter of interest all of my JDBC code follows this structure. It is not complicated SQL just insert statements....
public class RecordParserErrorReporter {
private static final String SQL_INSERT="INSERT INTO `ETL`.`ETLLog` "+
" ( "+
" `ETL_log_text`, "+
" `filename`, "+
" `record_number`, "+
" `error_message`) "+
" VALUES "+
" ( "+
" ?, "+
" ?, "+
" ?, "+
" ? "+
" ); ";
private BasicDataSource dataSource;
public BasicDataSource getDataSource() {
return dataSource;
}
public void setDataSource(BasicDataSource dataSource) {
this.dataSource = dataSource;
}
public void HandleError
(
#Body String msgBody
, #Headers Map hdr
, Exchange exch
)
{
Connection conn = null;
PreparedStatement stmt=null;
try
{
Exception e = exch.getProperty(Exchange.EXCEPTION_CAUGHT,Exception.class);
conn= dataSource.getConnection();
stmt =conn.prepareStatement(SQL_INSERT);
stmt.setString(1, msgBody);
stmt.setString(2, (String)hdr.get("CamelFileName"));
stmt.setInt(3, (Integer)hdr.get("SPLITNUMBER"));
stmt.setString(4, e.getMessage());
stmt.executeUpdate();
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
finally
{
try
{
if (stmt!=null)
{
stmt.close();
}
if (conn!=null)
{
conn.close();
conn= null;
}
}
catch(SQLException e)
{
System.out.println(e.getMessage());
}
}
}
}
How do I track down why my connections are not being reused? Or if I am leaking connections how do I track that down?
Update:
I set the file consumer to consume 1 file on each poll with a second delay between the polls. I can see it creating a new connection pool for each time the route starts and then not reusing the previously created pool. Appears that for every file I queue a new connection pool is created. Not exactly what I want. Is this correct.
I have included a screen shot of how this looks see below:
Update 2:
This not running under spring DM but a OSGI blue print. I am pretty convinced that the datasource is getting instantiated more than once.
Update 3:
Well ok so the datasource is not getting instantiated more than once. The idle connections are simply not used. I did find something interesting though so I suspect this might be related to what I am see more info in the link here: http://fusesource.com/forums/thread.jspa?threadID=4659&tstart=15
Judging by the amount of view this question is getting I am pretty much stuck out there.

Found the problem. This was a real picnic error or id10t mistake on my side.
In my ETL beans I had the following lines of code
try
{
conn= dataSource.getConnection();
stmt =conn.prepareStatement(SQL_ETL_INSERT);
stmt.setString(1, (String)hdr.get("CamelFileName"));
stmt.executeUpdate();
conn= dataSource.getConnection();
stmt =conn.prepareStatement(SQL_ETL_DELETE);
stmt.setString(1, (String)hdr.get("CamelFileName"));
stmt.executeUpdate();
}
catch (Exception e)
{
throw new Exception(e.getMessage());
}
finally
{
try
{
if (stmt!=null)
{
stmt.close();
stmt= null;
}
if (conn!=null)
{
conn.close();
conn= null;
}
}
catch(SQLException e)
{
throw new Exception(e.getMessage());
}
}
Notice I run the conn= dataSource.getConnection(); twice! Then I release only one of the connections. Copy and paste and late nights coding does not mix.

Related

Oracle AQ JMS with XA transaction throwing NullPointException while fetching connection

I am trying to use Oracle AQ supporting XA transaction since i have other datasource like Active MQ and DB involved in the transaction. When i tried to post to oracle aq queue1. it is failing with a NullPointerException while getting the XAconnection from the datasource.
I am using oracle ojdbc6,aqapi.jar of 11.2 version
Snippet of my camel blueprint with my bean defintion is given below
<reference id="transactionManager" interface="javax.transaction.TransactionManager" />
<reference id="recoverableTxManager" interface="org.apache.geronimo.transaction.manager.RecoverableTransactionManager" availability="mandatory" />
<reference id="platformTxManager" interface="org.springframework.transaction.PlatformTransactionManager" availability="mandatory"/>
<bean id="oracleXaDataSource" class="oracle.jdbc.xa.client.OracleXADataSource" destroy-method="close">
<property name="user" value="dbuser" />
<property name="password" value="dbpassword" />
<property name="URL" value="dburl" />
</bean>
<bean id="connectionFactoryOracleAQ" class="oracle.jms.AQjmsFactory" factory-method="getXAQueueConnectionFactory">
<argument value="oracleXaDataSource" />
</bean>
<bean id="oracleaqJcaPooledConnectionFactory" class="org.apache.activemq.jms.pool.JcaPooledConnectionFactory" init-method="start"
destroy-method="stop">
<property name="idleTimeout" value="0"/>
<property name="name" value="aq.default"/>
<property name="maxConnections" value="1"/>
<property name="connectionFactory" ref="connectionFactoryOracleAQ"/>
<property name="transactionManager" ref="transactionManager"/>
</bean>
<bean id="resourceManager-AQ" class="org.apache.activemq.jms.pool.GenericResourceManager"
init-method="recoverResource">
<property name="connectionFactory" ref="connectionFactoryOracleAQ"/>
<property name="transactionManager" ref="recoverableTxManager"/>
<property name="resourceName" value="aq.default"/>
<property name="userName" value="${primary.datasource.user}"/>
<property name="password" value="${primary.datasource.password}"/>
</bean>
<bean id="oracleaqJmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="oracleaqJcaPooledConnectionFactory"/>
<property name="transactionManager" ref="platformTxManager"/>
<property name="transacted" value="false"/>
</bean>
<bean id="oracleaq" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="oracleaqJmsConfig" />
</bean>
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="route1">
<from uri="vm:route1" />
<log message="Message to the oracle Aq:queue1-- ${body}" />
<to uri="oracleaq:queue:queue1?jmsMessageType=Text" pattern="InOnly"/>
</route>
</camelContext>
Could you please help me identifying what is the issue. The exception is given l
2017-02-27 12:14:11,613 | WARN | loyer-4-thread-1 | PooledConnectionFactory | 9037 - org.apache.activemq.activemq-osgi - 5.11.0.redhat-621084 | Create pooled connection during start failed. This exception will be ignored.
javax.jms.JMSException: Error while attempting to add new Connection to the pool
at org.apache.activemq.jms.pool.PooledConnectionFactory.createJmsException(PooledConnectionFactory.java:267)
at org.apache.activemq.jms.pool.PooledConnectionFactory.createConnection(PooledConnectionFactory.java:226)
at org.apache.activemq.jms.pool.PooledConnectionFactory.createConnection(PooledConnectionFactory.java:205)
at org.apache.activemq.jms.pool.PooledConnectionFactory.start(PooledConnectionFactory.java:291)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[:1.7.0_25]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)[:1.7.0_25]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)[:1.7.0_25]
at java.lang.reflect.Method.invoke(Method.java:606)[:1.7.0_25]
at org.apache.aries.blueprint.utils.ReflectionUtils.invoke(ReflectionUtils.java:299)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BeanRecipe.invoke(BeanRecipe.java:956)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BeanRecipe.runBeanProcInit(BeanRecipe.java:712)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BeanRecipe.internalCreate2(BeanRecipe.java:824)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BeanRecipe.internalCreate(BeanRecipe.java:787)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.di.AbstractRecipe$1.call(AbstractRecipe.java:79)[15:org.apache.aries.blueprint.core:1.4.4]
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)[:1.7.0_25]
at java.util.concurrent.FutureTask.run(FutureTask.java:166)[:1.7.0_25]
at org.apache.aries.blueprint.di.AbstractRecipe.create(AbstractRecipe.java:88)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintRepository.createInstances(BlueprintRepository.java:247)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintRepository.createAll(BlueprintRepository.java:183)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintContainerImpl.instantiateEagerComponents(BlueprintContainerImpl.java:682)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintContainerImpl.doRun(BlueprintContainerImpl.java:377)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintContainerImpl.run(BlueprintContainerImpl.java:269)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintExtender.createContainer(BlueprintExtender.java:294)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintExtender.createContainer(BlueprintExtender.java:263)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintExtender.modifiedBundle(BlueprintExtender.java:253)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$Tracked.customizerModified(BundleHookBundleTracker.java:500)[9:org.apache.aries.util:1.1.0]
at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$Tracked.customizerModified(BundleHookBundleTracker.java:433)[9:org.apache.aries.util:1.1.0]
at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$AbstractTracked.track(BundleHookBundleTracker.java:725)[9:org.apache.aries.util:1.1.0]
at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$Tracked.bundleChanged(BundleHookBundleTracker.java:463)[9:org.apache.aries.util:1.1.0]
at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$BundleEventHook.event(BundleHookBundleTracker.java:422)[9:org.apache.aries.util:1.1.0]
at org.apache.felix.framework.util.SecureAction.invokeBundleEventHook(SecureAction.java:1127)[org.apache.felix.framework-4.4.1.jar:]
at org.apache.felix.framework.util.EventDispatcher.createWhitelistFromHooks(EventDispatcher.java:696)[org.apache.felix.framework-4.4.1.jar:]
at org.apache.felix.framework.util.EventDispatcher.fireBundleEvent(EventDispatcher.java:484)[org.apache.felix.framework-4.4.1.jar:]
at org.apache.felix.framework.Felix.fireBundleEvent(Felix.java:4429)[org.apache.felix.framework-4.4.1.jar:]
at org.apache.felix.framework.Felix.startBundle(Felix.java:2100)[org.apache.felix.framework-4.4.1.jar:]
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:976)[org.apache.felix.framework-4.4.1.jar:]
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:963)[org.apache.felix.framework-4.4.1.jar:]
at io.fabric8.agent.service.Agent$BaseDeployCallback.startBundle(Agent.java:482)[86:io.fabric8.fabric-agent:1.2.0.redhat-621084]
at io.fabric8.agent.service.Deployer$3.call(Deployer.java:935)[86:io.fabric8.fabric-agent:1.2.0.redhat-621084]
at io.fabric8.agent.service.Deployer$3.call(Deployer.java:930)[86:io.fabric8.fabric-agent:1.2.0.redhat-621084]
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)[:1.7.0_25]
at java.util.concurrent.FutureTask.run(FutureTask.java:166)[:1.7.0_25]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)[:1.7.0_25]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)[:1.7.0_25]
at java.lang.Thread.run(Thread.java:724)[:1.7.0_25]
Caused by: oracle.jms.AQjmsException: Error creating the db_connection
at oracle.jms.AQjmsDBConnMgr.getConnection(AQjmsDBConnMgr.java:625)
at oracle.jms.AQjmsDBConnMgr.<init>(AQjmsDBConnMgr.java:458)
at oracle.jms.AQjmsXAConnection.<init>(AQjmsXAConnection.java:129)
at oracle.jms.AQjmsXAConnectionFactory.createXAConnection(AQjmsXAConnectionFactory.java:212)
at org.apache.activemq.jms.pool.XaPooledConnectionFactory.createConnection(XaPooledConnectionFactory.java:79)
at org.apache.activemq.jms.pool.PooledConnectionFactory$1.makeObject(PooledConnectionFactory.java:108)
at org.apache.activemq.jms.pool.PooledConnectionFactory$1.makeObject(PooledConnectionFactory.java:88)
at org.apache.commons.pool.impl.GenericKeyedObjectPool.addObject(GenericKeyedObjectPool.java:1748)
at org.apache.activemq.jms.pool.PooledConnectionFactory.createConnection(PooledConnectionFactory.java:222)
... 43 more
Caused by: java.lang.NullPointerException
at oracle.jms.AQjmsGeneralDBConnection.getProviderKey(AQjmsGeneralDBConnection.java:99)
at oracle.jms.AQjmsGeneralDBConnection.<init>(AQjmsGeneralDBConnection.java:77)
at oracle.jms.AQjmsDBConnMgr.getConnection(AQjmsDBConnMgr.java:541)
... 51 more
I think i got what the issue is. The aqapi.jar that i am using from oracle 11.2 client has got the bug. The class AqjmsGeneralDBConnection is not initializing the m_dbConn object for the QAConnection (constructor with XAConnection as argument) and trying to access the getURL() on the m_dbConn object which is null. I tried using the aqapi13.jar from 10.2.0 version and it works
AQjmsGeneralDBConnection(AQjmsDBConnMgr paramAQjmsDBConnMgr, Connection paramConnection, boolean paramBoolean1, boolean paramBoolean2)
throws JMSException
{
this.m_connMgr = paramAQjmsDBConnMgr;
this.m_dbConn = paramConnection;
this.m_isExternal = paramBoolean1;
this.m_force = paramBoolean2;
this.providerKey = getProviderKey();
}
AQjmsGeneralDBConnection(AQjmsDBConnMgr paramAQjmsDBConnMgr, XAConnection paramXAConnection, boolean paramBoolean1, boolean paramBoolean2)
throws JMSException
{
this.m_connMgr = paramAQjmsDBConnMgr;
this.m_xaConn = paramXAConnection;
this.m_isExternal = paramBoolean1;
this.m_force = paramBoolean2;
this.providerKey = getProviderKey();
}
private String getProviderKey()
throws JMSException
{
try
{
OracleConnection localOracleConnection = (OracleConnection)this.m_dbConn;
**String str1 = localOracleConnection.getURL();**
int i = str1.indexOf('#');
String str2;
if (i < 0)
{
if ((!"jdbc:oracle:kprb:".equals(str1)) && (!"jdbc:default:connection:".equals(str1))) {
AQjmsError.throwEx(112);
}
str2 = "jdbc:oracle:kprb:";
}
else
{
str2 = str1.substring(i);
}
return str2.toUpperCase();
}
catch (SQLException localSQLException)
{
throw new AQjmsException(localSQLException);
}
}

Retry mechanism using Camel and ActiveMq - Retry Policy gets ignored

I am working on a retry mechanism using camel and activeMq. What I want to do is to start a retry mechanism if one of the servers I am calling is down, add the request into my queue and from hour to hour resend it to the server. Everything works fine except my Retry Policy that seems to be ignored (my requests are resent when they get into my queue and they are never added into the DLQ after the number of retries is reached)
My configuration looks as follows (Values are readed from a .cfg file):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${activemq.broker.url}"/>
<property name="userName" value="${activemq.broker.username}"/>
<property name="password" value="${activemq.broker.password}"/>
<property name="redeliveryPolicy" ref="policy"/>
</bean>
<bean id="policy" class="org.apache.activemq.RedeliveryPolicy">
<property name="queue" value="*"/>
<property name="initialRedeliveryDelay" value="${activemq.redelivery.delay}"/>
<property name="redeliveryDelay" value="${activemq.redelivery.delay}"/>
<property name="useExponentialBackOff" value="false"/>
<property name="maximumRedeliveries" value="${activemq.number.of.redeliveries}"/>
</bean>
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="maxConnections" value="8"/>
<property name="connectionFactory" ref="jmsConnectionFactory"/>
</bean>
<bean id="jmsTransactionManager" class="org.springframework.jms.connection.JmsTransactionManager">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
</bean>
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
<property name="transactionManager" ref="jmsTransactionManager"/>
<property name="transacted" value="true"/>
<property name="cacheLevelName" value="CACHE_CONSUMER"/>
<property name="concurrentConsumers" value="8"/>
</bean>
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig"/>
</bean>
Camel route that calls my service:
<route id="addRegistrationRoute">
<from uri="direct:addRegistrationRoute"/>
<to uri="cxf:bean:addRegistrationEndpoint"/>
<onException>
<exception>java.net.ConnectException</exception>
<onWhen>
<el>${in.headers['previousRoute'] != 'registrationRetryRoute'}</el>
</onWhen>
<handled>
<constant>true</constant>
</handled>
<setBody>
<simple>${headers.request}</simple>
</setBody>
<removeHeaders pattern="*"/>
<to uri="activemq:queue:registrationRetryQueue"/>
<stop/>
</onException>
<onException>
<exception>org.apache.cxf.interceptor.Fault</exception>
<onWhen>
<el>${in.headers['previousRoute'] != 'registrationRetryRoute'}</el>
</onWhen>
<handled>
<constant>true</constant>
</handled>
<setBody>
<simple>${headers.request}</simple>
</setBody>
<removeHeaders pattern="*"/>
<to uri="activemq:queue:registrationRetryQueue"/>
<stop/>
</onException>
<onException>
<exception>javax.xml.soap.SOAPFault</exception>
<handled>
<constant>true</constant>
</handled>
</onException>
</route>
<route id="registrationRetryRoute">
<from uri="activemq:queue:registrationRetryQueue"/>
<setHeader headerName="previousRoute">
<simple>registrationRetryRoute</simple>
</setHeader>
<to uri="direct:addRegistrationRoute"/> <!-- Back to the initial flow. -->
</route>
If somebody can please tell me what I have did wrong in configuring activeMq I will be really thankful!
Regards,
Roxana
ActiveMQ pushes messages into DLQ only if you are throwing an error from your consumers (or message listeners). So try to catch your exception and throw it back so that retry policy will be enabled accordingly.

Need help setting variable in Camel

I am trying to set a variable inside of my camel code so I can call this variable when I log my route execution. This variable needs to be set from an xpath statement.
Below is the code that is not working and I suspect that I need to set a variable that is equal to my xpath statement that is found in the log message but I don't know how to do that.
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/blueprint"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
<bean id="activemq"
class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="brokerURL" value="tcp://localhost:61616"/>
<property name="userName" value="user"/>
<property name="password" value="password"/>
</bean>
<camelContext id="blueprintContext" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<route id="Test_Message_Content_Route">
<from uri="activemq:queue:FirstQueue?username=user&password=password&concurrentConsumers=1&maxConcurrentConsumers=5"/>
<choice>
<when>
<xpath>//destination[text()='TEST']</xpath>
<log message="Test route invoked"/>
<split>
<xpath resultType="java.lang.String">//message_payload/text()</xpath>
<log message="Routed $xpath{//id/text()} to TEST QUEUE"/>
<to uri="activemq:queue:TestQueue?username=user&password=password"/>
</split>
</when>
<when>
<xpath>//destination[text()='DEV']</xpath>
<log message="Dev route invoked"/>
<split>
<xpath resultType="java.lang.String">//message_payload/text()</xpath>
<log message="Routed $xpath{//id/text()} to DEV QUEUE"/>
<to uri="activemq:queue:DevQueue?username=user&password=password"/>
</split>
</when>
<otherwise>
<log message="Sending message to DL Queue"/>
<to uri="activemq:queue:DLQueue?username=user&password=password"/>
</otherwise>
</choice>
</route>
</camelContext>
</blueprint>
I now have this working by using setHeader in my camel context like the following:
<setHeader headerName="id"><xpath>//id/text()</xpath></setHeader>
<log message="Routed ${header.id} to Test queue"/>

Apache Camel + spring remoting + jax-ws + multiple parameters

I have following camel route:
<route id="myRoute">
<from uri="cxf:bean:TestEndpoint />
<process ref="TestProcessor" />
<to uri="bean:TestWS?method=doSomething" />
</route>
where TestWS:
<bean id="TestWS" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="serviceInterface" value="org.example.TestWS />
<property name="wsdlDocumentUrl" value="http://localhost:8080/TestWSImplService/TestWSImpl?wsdl" />
<property name="namespaceUri" value="http://org.example" />
<property name="serviceName" value="TestWSImplService" />
<property name="portName" value="TestWSImplPort" />
</bean>
and TestWS:
#WebService(targetNamespace = "http://org.example")
public interface TestWS {
public String doSomething(Object param1, Object param2);
}
Could you tell me what TestProcessor should return in order to proper call TestWS with multiple parameters?
Thanks
You need to add multiParameterArray=true option to the endpoint to the bean [1] URI.
<to uri="bean:TestWS?method=doSomething&multiParameterArray=true" />
Then your processor should set body as an array of parameters you want to pass to the service:
exchange.getIn().setBody(new Object[]{"param1", "param2"});
[1] https://camel.apache.org/bean.html

Managing JMS transaction with Spring

I'm trying to manage JMS transaction with Spring and HornetQ.
This is the code I wrote:
public void receive() {
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
Message msg = jmsTemplate.receive(queue);
boolean success = false;
if (msg != null) {
try {
success = handleMessage(msg);
if (success) {
msg.acknowledge(); // session is still open within the transaction
}
} catch (JMSException e) {
transactionManager.rollback(status);
}
if (success)
transactionManager.commit(status);
else
transactionManager.rollback(status):
}
}
I'm doing a synchronous read from the queue, with timeout set to 0, since I don't wanna block on the read. Because of this I have to check if something was actually received.
This is an excerpt of my applicationContext.xml:
<bean id="inVMConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:/ConnectionFactory</value>
</property>
</bean>
<bean id="cachedConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="inVMConnectionFactory" />
</bean>
<bean id="producer" class="it.ubiquity.gestoreprofilazione.onweb.OnWebProducer" scope="singleton">
<property name="queue" ref="retryQueue" />
<property name="connectionFactory" ref="cachedConnectionFactory" />
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="cachedConnectionFactory" />
<property name="sessionTransacted" value="true" />
<property name="sessionAcknowledgeMode" value="#{T(javax.jms.Session).CLIENT_ACKNOWLEDGE}" />
<property name="pubSubDomain" value="false" />
<property name="receiveTimeout" value="# {T(org.springframework.jms.core.JmsTemplate).RECEIVE_TIMEOUT_NO_WAIT}" />
</bean>
<bean id="jmsTransactionManager" class="org.springframework.jms.connection.JmsTransactionManager">
<property name="connectionFactory" ref="cachedConnectionFactory" />
</bean>
<bean id="consumer" class="it.ubiquity.gestoreprofilazione.onweb.OnWebConsumer" scope="singleton">
<property name="queue" ref="retryQueue" />
<property name="jmsTemplate" ref="jmsTemplate" />
<property name="transactionManager" ref="jmsTransactionManager" />
</bean>
The problem I have is quite strange: the first time I receive a message, handleMessage fail, so I rollback the transaction. Then nothing more happens. If I check with the JMX console, I can see there's one message on the queue. Now, if I restart JBoss, the messages is receive again and again, as expected.
Maybe there's something wrong with my configuration, but why it works after a reboot?
HornetQ 2.2.10
JBoss 5.1.0
Spring 3.1.2
UPDATE
With debugging enabled I see the first time:
DEBUG [org.springframework.jms.connection.JmsTransactionManager]
(baseScheduler-1) Creating new transaction with name [null]:
PROPAGATION_REQUIRED,ISOLATION_DEFAULT
and after the first rollback, on subsequent receive and rollback I see:
DEBUG [org.springframework.jms.connection.JmsTransactionManager]
(baseScheduler-1) Participating in existing transaction
Instead, after restarting JBoss, I read that the transaction is actually rolled back:
DEBUG [org.springframework.jms.connection.JmsTransactionManager]
(baseScheduler-1) Initiating transaction rollback 2012-11-05
09:54:14,436 DEBUG
[org.springframework.jms.connection.JmsTransactionManager]
(baseScheduler-1) Rolling back JMS transaction on Session
So, why the rollback it's not happening the first time, and as soon I restart the server it happens all the time? What am I doing wrong?
Ok, finally I've managed to understand my mistake :)
In the outer if's else I should have committed the transaction. That's why the mechanism works after restarting JBoss: there is no transaction hanging on.

Resources