Changing default settings for JMS messaging in Camel - apache-camel

I've found only a way to specify JMS settings directly on end points, but I would like to change default values, so that we do not have to remember to set the same value on each endpoint.
Below there are few examples of properties which I would like to set globally:
from("jms:topic:xyx?concurrentConsumers=1") I would be good to have an option to set different concurrentConsumers value for queues and topics.
from("jms:queue:abc?receiveTimeout=60000&concurrentConsumers=1")
Enable transaction for each JMS Message, so I do not have to call from(...).transacted()

You can always define your components as a bean and reuse them everywhere. In your case, you can have:
<bean id="activemq"
class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="concurrentConsumers" value="1"/>
<property name="transacted" value="true"/>
</bean>

Related

Hybris interceptor is not getting triggered

I create ValidateInterceptor in below path and created bean in custombackoffice-backoffice-spring.xml
C:\hybris\bin\custom\custombackoffice\backoffice\src\com\custom\backoffice\interceptor\CustomAppeasementUserValidateInterceptor.java
bean is as below
<bean id="customAppeasementUserValidateInterceptor" class="de.hybris.platform.servicelayer.interceptor.impl.InterceptorMapping">
<property name="interceptor" ref="customAppeasementUserValidateInterceptor" />
<property name="typeCode" value="Appeasement" />
</bean>
when I modify particular model in backoffice and click on the save button, debugger never goes to interceptor it directly saves the model.
NOTE :- I can't write this interceptor in customcore because we can not import below services in custom core
import com.hybris.cockpitng.core.user.AuthorityGroupService;
import com.hybris.cockpitng.core.user.impl.AuthorityGroup;
Why the interceptor is not getting triggered?
The bean-id and the mapper bean-id are the same. Change either one. Ideally, it should be like-
<bean id="customAppeasementUserValidateInterceptorMapping" class="de.hybris.platform.servicelayer.interceptor.impl.InterceptorMapping">
<property name="interceptor" ref="customAppeasementUserValidateInterceptor" />
<property name="typeCode" value="Appeasement" />
</bean>
Notice the new id for the mapping bean i.e. customAppeasementUserValidateInterceptorMapping.

QPID Connection factory properties

My system is based on camel and use Apache QPID 0.37.0 to consume messages from a remote AMQPS sever. Our system authenticates via a client certificate. Thus I have this piece of configuration:
<bean id="jmsConnectionFactory" class="org.apache.qpid.jms.JmsConnectionFactory">
<constructor-arg name="remoteURI" value="amqps://some-location:5671?transport.keyStoreLocation=/very/long/path/nnn-openssl.p12&transport.keyStorePassword=*******&transport.trustStoreLocation=/very/long/path/server.keystore&transport.trustStorePassword=*******"/>
</bean>
This is just working fine. However, configuring key/trust store this way (i.e. in the URI) has several drawbacks:
First, it is not easy to read and maintain.
Some components log the URI, so the paths (I can live with it) and the passwords (ouch...) get logged.
I know it's possible to configure via a system property (javax.net.ssl.keyStore, and son on), but it's not an option because different modules may use different key and trust store, and we want to keep them in separate files.
Is there a way to configure those transport properties of JmsConnectionFactory in a different way ?
Something like:
<bean id="jmsConnectionFactory" class="org.apache.qpid.jms.JmsConnectionFactory">
<constructor-arg name="remoteURI" value="amqps://some-location:5671"/>
<property name="transport.keyStoreLocation" value="/very/long/path/nnn-openssl.p12"/>
...
</bean>
Note that this factory is used in a JMSConfig, which in turn is used within an AMQPComponent:
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration" >
<property name="connectionFactory" ref="jmsConnectionFactory" />
...
</bean>
<bean id="amqp" class="org.apache.camel.component.amqp.AMQPComponent">
<property name="testConnectionOnStartup" value="true"/>
<property name="configuration" ref="jmsConfig" />
...
</bean>
The short answer is no, that's all that class supports. However you could write a configuration bean which has the properties you require, and have that create the bean. Off the top of my head, something like this:
#Configuration
public class QpidConfiguration {
// Add setters for these
private String host;
private int port = 5671;
private String keyStore;
private String keyStorePassword;
private String trustStoreLocation;
private String trustStorePassword;
#Bean
public JmsConnectionFactory createConnectionFactory() {
return new JmsConnectionFactory("amqps://" + host" + ":" + port + "?transport.keyStoreLocation=" + keyStoreLocation + "&transport.keyStorePassword=" + keyStorePassword + "&transport.trustStoreLocation=" + trustStoreLocation + "&transport.trustStorePassword=" + trustStorePassword);
}
}
You probably want to add some parameter validation in there to be safe.
You can then define the bean using more convenient properties.
<bean id="jmsConnectionFactory" class="com.example.QpidConfiguration">
<property name="host" value="some-location"/>
<property name="keyStoreLocation" value="/very/long/path/nnn-openssl.p12"/>
...
</bean>
You can also leverage encrypted property placeholders, if your heart so desires.

Came jmsComponent: what's the difference setting the exception Listener in different beans?

I set up a jms component with spring like this way:
<bean id="jmsConnectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>
<bean id="cachedConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="jmsConnectionFactory"/>
<property name="sessionCacheSize" value="10"/>
<property name="exceptionListener" ref="exceptionListener"/>
</bean>
<bean id="jmsConfig"
class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="cachedConnectionFactory"/>
<property name="concurrentConsumers" value="10"/>
</bean>
I notice that all these 4 beans have exceptionListener property. So I wonder what's the difference setting exceptionListener in different beans.
During my test, only setting in CachingConnectionFactory can work, it can go into my ExceptionListener, while in other cases, the exception will be logged somewhere else, but can't go into my code, the exception is like below.
WARN CachingConnectionFactory.onException(322) - Encountered a JMSException - resetting the underlying JMS Connection
javax.jms.JMSException: java.io.EOFException
at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:54)
at org.apache.activemq.ActiveMQConnection.onAsyncException(ActiveMQConnection.java:1983)
at org.apache.activemq.ActiveMQConnection.onException(ActiveMQConnection.java:2002)
at org.apache.activemq.transport.TransportFilter.onException(TransportFilter.java:101)
at org.apache.activemq.transport.ResponseCorrelator.onException(ResponseCorrelator.java:126)
at org.apache.activemq.transport.TransportFilter.onException(TransportFilter.java:101)
at org.apache.activemq.transport.TransportFilter.onException(TransportFilter.java:101)
at org.apache.activemq.transport.WireFormatNegotiator.onException(WireFormatNegotiator.java:160)
at org.apache.activemq.transport.AbstractInactivityMonitor.onException(AbstractInactivityMonitor.java:314)
at org.apache.activemq.transport.TransportSupport.onException(TransportSupport.java:96)
at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:200)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.EOFException
at java.io.DataInputStream.readInt(DataInputStream.java:392)
at org.apache.activemq.openwire.OpenWireFormat.unmarshal(OpenWireFormat.java:275)
at org.apache.activemq.transport.tcp.TcpTransport.readCommand(TcpTransport.java:221)
at org.apache.activemq.transport.tcp.TcpTransport.doRun(TcpTransport.java:213)
at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:196)
... 1 more
I can't understand how this works, please give some explanation or hint.
org.springframework.jms.connection.CachingConnectionFactory.exceptionListener set the org.apache.activemq.ActiveMQConnectionFactory.exceptionListener , so this is the same.
org.apache.camel.component.jms.JmsConfiguration.exceptionListener set up the org.springframework.jms.listener.AbstractMessageListenerContainer.exceptionListener
Set the JMS ExceptionListener to notify in case of a JMSException
thrown by the registered message listener or the invocation infrastructure.
so it is nearly the same use of that listener at any level but it is better to set it at the org.apache.camel.component.jms.JmsConfiguration.exceptionListener level to be managed by the spring Container.

Camel - using custom jmsOperations: cannot be cast to org.apache.camel.component.jms.JmsConfiguration$CamelJmsTemplate

I want to use a custom jmsOperations, when I try that I get a class cast exception: cannot be cast to org.apache.camel.component.jms.JmsConfiguration$CamelJmsTemplate
Config :
<bean id="jmsErf" class="org.apache.camel.component.jms.JmsComponent">
<property name="jmsOperations" ref="myJmsTemplate" />
<property name="preserveMessageQos" value="true"/>
<property name="explicitQosEnabled" value="false"/>
<property name="testConnectionOnStartup" value="true"/>
<!--property name="useMessageIDAsCorrelationID" value="true" / WARNING! Do not use this as we need to copy only in the beginning not everywhere -->
<property name="transactionManager" ref="jpaTransactionManager" />
<property name="transacted" value="true" />
</bean>
<bean name="myJmsTemplate" class="blabla.MyJmsTemplate">
<property name="connectionFactory">
<bean class="jms.MQConnectionFactory">
<property name="queueManagerName" value="${Queue.My.manager}" />
<property name="throwOnInvalidMessageProperty" value="false" />
</bean>
</property>
</bean>
Sample class I created
MyJmsTemplate extends org.springframework.jms.core.JmsTemplate implements
org.springframework.jms.core.JmsOperations { .. no code :)
Why I'm trying jmsOperations:
I just need to have original JMSPriority maintained. Yes I did try preserveQoS explicitQoS [various combinations of enablingetc.. it either sets all priority to 4; or priority remains zero despite setting eg=6 priority]. by creating my own jmsOperations and explictly transfering JMSPriority value.
Exception trace:
Caused by: org.apache.camel.FailedToCreateProducerException: Failed to
create Producer for endpoint:
Endpoint[jmsErf://queue:MQDEV.MYQ.ERROR]. Reason:
java.lang.ClassCastException: blabla.MyJmsTemplate cannot be cast to
org.apache.camel.component.jms.JmsConfiguration$CamelJmsTemplate at
org.apache.camel.component.jms.JmsProducer.testConnectionOnStartup(JmsProducer.java:458)
at
org.apache.camel.component.jms.JmsProducer.doStart(JmsProducer.java:469)
at
org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:60)
at
org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:62)
at
org.apache.camel.impl.ProducerCache.doGetProducer(ProducerCache.java:387)
... 115 more Caused by: java.lang.ClassCastException:
bla.MyJmsTemplate cannot be cast to
org.apache.camel.component.jms.JmsConfiguration$CamelJmsTemplate at
org.apache.camel.component.jms.JmsProducer.testConnectionOnStartup(JmsProducer.java:447)
... 119 more
Can anyone point me to jmsOptions usage in camel?
What Camel version do you use?
You should use a custom messageConverter if you want to map to/from JMS messages yourself.
And the JMSPriority ought to be preserved if you set preserveMessageQos=true.

how to do corrleationId copying at route level? and only if CorrelationID is not filled

My Usecase (in camel):
if incoming message has correlationId (say clientCorrId) => leave as such, do nothing, as clientCorrId is used by client to map response.
if incoming message do not have correlationId => take messageId and put it in correlationId (at route level, not in every route that uses "jms" component)
Copying correlationId should be done only at a route level
How to do corrleationId copying at route level? (not globally as in useMessageIDAsCorrelationID as below)
<bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="jmsConnectionFactory" />
<!--property name="useMessageIDAsCorrelationID" value="true" / WARNING! Do not use this as we need to copy only in the beginning not everywhere -->
<property name="transactionManager" ref="jpaTransactionManager" />
<property name="transacted" value="true" />
</bean>
I want to avoid having a separate bean code like this to copy correlationId ONLYIF it is empty:
if (EMPTY_MSG_ID.equals(currentCorrId)) {
log.info("No corrId set, setting msgId to corrid :" + msgId);
outHeader.put(correlationIdKey, msgId);
} else {
outHeader.put(correlationIdKey, currentCorrId);
log.info("CorrId already set: " + currentCorrId);
}
You can use an interceptor to intercept from jms endpoints, and add the missing id if needed. See http://camel.apache.org/intercept

Resources