I need to handle transactions with OSGI applications under Karaf(I am using ServiceMix 7.0). All logic is under camel route.
First, I receive Web Requests and process it in route, make transformations and then I need to start transaction : call storedProcedures in Oracle, call another web service and if call to web service is successfull I need to commit stored procedure invocation, otherwise rollback. May be using container managed transactions as in EJB or JTA.
Camel doesn't have out of box components for calling stored procedure. So I am using org.springframework.jdbc.object.StoredProcedure. And now I don't know how to make SP invokation with transactional context.
Here is what you can do:
from("direct:mainRoute")
.transacted()
.to("direct:invokeService")
.to("sql-stored:SUBNUMBERS(INTEGER ${headers.num1},INTEGER ${headers.num2},OUT INTEGER resultofsub)
You will also need to add TransactionManager to the context.
<!-- spring transaction manager -->
<!-- this is the transaction manager Camel will use for transacted routes -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
For more details on Camel SQL stored proc Component refer to:
http://camel.apache.org/sql-stored-procedure.html
Related
I have an old application which handle JMS messages with ActiveMQ 5.8.0 and some JNDI remote topic connected to this ActiveMQ.
I have a connector like that :
<bean class="org.apache.activemq.network.jms.JmsConnector">
<property name="outboundTopicConnectionFactory" ref="jmsConnectionFactoryTo" />
<property name="outboundClientId" value="${remote.clientId}" />
<property name="jndiOutboundTemplate" ref="jndiTemplateTo" />
<property name="preferJndiDestinationLookup" value="true" />
<property name="inboundTopicBridges">
<list>
<bean class="org.apache.activemq.network.jms.InboundTopicBridge">
<property name="inboundTopicName" value="${remote.topic.to}"/>
<property name="localTopicName" value="${local.topic.to}"/>
<property name="consumerName" value="${remote.consumer.name}"/>
<property name="selector" value="${remote.selector}"/>
</bean>
</list>
</property>
</bean>
It works great, but now, for some technical reasons (strict JMS 1.1), I need to use "ConnectionFactory" instead of "TopicConnectionFactory".
With the actual configuration, I'm stuck because ActiveMQ seems to use "TopicConnectionFactory" instead of "ConnectionFactory", and my new class "MyConnectionFactoryImpl" implements "ConnectionFactory" now :
nested exception is org.springframework.beans.ConversionNotSupportedException:
Failed to convert property value of type 'com.webmethods.jms.impl.MyConnectionFactoryImpl'
to required type 'javax.jms.TopicConnectionFactory'
for property 'outboundTopicConnectionFactory';
nested exception is java.lang.IllegalStateException:
Cannot convert value of type [com.webmethods.jms.impl.MyConnectionFactoryImpl]
to required type [javax.jms.TopicConnectionFactory] for property 'outboundTopicConnectionFactory':
no matching editors or conversion strategy found
In "org.apache.activemq.network.jms.JmsConnector" class, it use everywhere "TopicConnectionFactory", which is not recommended anymore in JMS 1.1.
EDIT :
According to #Justin Bertram, I need to use Camel instead of ActiveMQ embedded bridge. But I can't find any example of XML configuration which I can use to replace my actual two beans JMSConnector. Which is the simple way to do this keeping my XML config files ?
As the documentation for the JMS to JMS Bridge (i.e. org.apache.activemq.network.jms.JmsConnector) states:
ActiveMQ provides bridging functionality to other JMS providers that implement the JMS 1.0.2 and above specification.
In other words, the whole goal of the JMS to JMS Bridge is to use the JMS 1.0.2 interface(s). Changing it so that it only used JMS 1.1 would defeat the purpose.
The documentation also states that you should use Camel instead of the JMS to JMS Bridge:
Warning, try Camel first!
Note that we recommend you look at using Apache Camel for bridging ActiveMQ to or from any message broker (or indeed any other technology, protocol or middleware) as its much easier to:
keep things flexible; its very easy to map different queue/topic to one or more queues or topics on the other provider
perform content based routing, filtering and other Enterprise Integration Patterns
allows you to work with any technology, protocol or middleware, not just JMS providers
Therefore I recommend you use Camel instead of org.apache.activemq.network.jms.JmsConnector.
I would think that having your code return a TopicConnectionFactory would be the simplest solution. Even the JMS 2.0 specification provides the TopicConnectionFactory. No matter what version of ActiveMQ you are using, you certainly have the option of using the TopicConnectionFactory in your code and providing that to your bridge.
Note that the Camel route:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="mqseries:Foo.Bar"/>
<to uri="activemq:Cheese"/>
</route>
</camelContext>
has no error handling. For example, if the 'to' endpoint is down, this route will read from the 'from' endpoint and just throw the messages on the floor. Furthermore, if the 'to' component is not configured to use a caching/pooling connection factory, then a new JMS connection will be created for each message sent. This has poor performance and can result in many sockets in the TIME_WAIT state. Bottom line - beware trivial Camel routes.
How transacted() in camel DSL is related to transacted="true" of JMSComponent.
Will that make any sense, if transacted property of JMSComponent is set to "true" along with transacted() in camel DSL ?
transacted="true" in JMS component configuration makes your JMS consumer transacted. So this is required if you want to make sure you don't lose messages.
However, you have multiple options to enable transactions (see the Camel docs for details).
Use local JMS transactions
Use your own Spring transaction manager
The Camel DSL transacted() is only necessary if you go with the second option, it references a SpringTransactionPolicy (for example PROPAGATION_REQUIRED). If it is present in your route, Camel is looking for a Spring transaction manager to use.
If you use option 1 (what is simpler in configuration and perfectly suitable if you only talk to a single JMS broker), you don't need the Camel DSL transacted() and your JMS consumer routes are nevertheless transactional.
Addition due to comments
To use option 1, you only have to set transacted="true" and lazyCreateTransactionManager="false" on your Camel ActiveMQComponent. You must not configure a Spring transaction manager (if you do, you end up with two tx managers!)
If you want to be transactional between multiple JMS brokers or a broker and a Database, you would either need XA transactions or you have to implement compensation logic to handle the edge cases when using simple transactions with each system involved.
I have a SOAP/REST service implemented in CXF inside Red Hat JBoss Fuse (in a Fabric).
I need to protect it with Basic Authentication, and credentials must be checked on a LDAP server.
Can this be done without a custom interceptor?
Can I maybe use the container JAAS security (configured with LDAP) to protect the service the same way I can protect the console?
Yes the container JAAS security realm can be used to protect a web service.
An example is here.
The example page doesn't explain the implementation, but a quick look at the blueprint.xml file reveals the following configuration:
<jaxrs:server id="customerService" address="/securecrm">
<jaxrs:serviceBeans>
<ref component-id="customerSvc"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref component-id="authenticationFilter"/>
</jaxrs:providers>
</jaxrs:server>
<bean id="authenticationFilter" class="org.apache.cxf.jaxrs.security.JAASAuthenticationFilter">
<!-- Name of the JAAS Context -->
<property name="contextName" value="karaf"/>
</bean>
So it's just a matter of configuring a JAAS authentication filter.
"karaf" is the default JAAS realm for the container: users are defined in etc/users.properties
To define more realms, info is here.
To have users on LDAP, see here.
The answer above is correct, but please note that for more recent versions of Fuse (past 6.1), the "rank" in the LDAP configuration must be greater than 100 in order to override the default karaf realm.
Also, with current patches applied, in Fuse 6.2.X, connection pooling for the LDAP connections can be enabled:
<!-- LDAP connection pooling -->
<!-- http://docs.oracle.com/javase/jndi/tutorial/ldap/connect/pool.html -->
<!-- http://docs.oracle.com/javase/jndi/tutorial/ldap/connect/config.html -->
context.com.sun.jndi.ldap.connect.pool=true
</jaas:module>
</jaas:config>
This is very important for high volume web-services. A connection pool is maintained to the LDAP server. This both avoids connection creation overhead and having closing sockets lingering in TIME-WAIT state.
as stated, is there a simple way to monitor Camel's vm incoming messages to the embedded broker ?
<bean id="jms" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost?broker.persistent=false" />
</bean>
Thanks!
Your question isn't quite clear on what you would like to monitor.
-You could log what you send to the broker and read from it.
-You could connect to jmx to view a bunch of processing information.
-If you are on the FUSE platform there is a management console that exposes the jmx endpoints to a web url.
-You could also setup JBoss operations network to poll all of your jmx info and do trending on the data.
If I didn't cover the use case you had in mind please update your question with some details and ping me in a comment so I can get back to you.
I have configured Quartz endpoint for the scheduling requirement. However currently in my route configuration, trigger information is hard coded in the XML configuration file. As per the requirement, trigger information needs to come from DB.
<camel:route>
<camel:from uri="quartz://commandActions/MSFI?cron=15+17+13+?+*+MON-SUN+*" />
<camel:bean ref="userGateway" method="generateCommand" />
<camel:to uri="wmq:SU.SCHEDULER" />
</camel:route>
Quartz documentation says Jobs and triggers can be stored in database and are accessed using JDBCJobStore. Is it possible to configure Camel Quartz endpoint to use JDBCJobStore? I tried to find out an example but couldn't find. If someone has implemented this before, kindly share an example.
Thanks,
Vaibhav
Yeah see the quartz documentation how to configure it to use a jdbc job store. You can do this using a quartz.properties file, which you can tell Camel to use.
See the Camel side part here: http://camel.apache.org/quartz at the section Configuring quartz.properties file