JMS Poller Transactional - java

I am using Spring Integration 4.1.5 and trying to do something with transactions, but unfortunately am not able to and could not find working examples. I'm trying to setup a JMS poller that is looking for messages. Once a message is received, a service activator will insert a row into the database, and the message is passed to another service activator. I would like to make the first two pieces, the message pickup & database insert transactional. I do not want the rest of the flow to be transactional. I am using Weblogic as the application container so will be using the WebLogicJtaTransactionManager.
The problem I'm running into is I am unable to make the first two pieces transactional. It's either all, or nothing. I've tried many methods, but I feel like using an advice-chain on the poller is the best bet. I would be able to control which methods would be part of the transaction.
I've seen examples using a message driven listener, but I am using Weblogic and would be using the Work Managers and I believe I must use a poller in order to take advantage of work managers (if that's not the case, I guess that's another question for the future!)
I've taken the xml and simplified it, but besides editing out the package name, the context produces the issue.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
xmlns:file="http://www.springframework.org/schema/integration/file"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:int-sftp="http://www.springframework.org/schema/integration/sftp"
xmlns:int-xml="http://www.springframework.org/schema/integration/xml"
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/file
http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
http://www.springframework.org/schema/integration/sftp
http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/integration/xml
http://www.springframework.org/schema/integration/xml/spring-integration-xml.xsd
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="jtaTransactionManager"
class="org.springframework.transaction.jta.WebLogicJtaTransactionManager">
<property name="transactionManagerName" value="javax.transaction.TransactionManager" />
</bean>
<bean id="insertMessageToDb" class="com.ReadMsgFromAxway" />
<bean id="serviceActivator" class="com.CreateTMDFile" />
<int-jms:inbound-channel-adapter id="jmsDefaultReceiver"
connection-factory="inboundDefaultAdaptorConnectionFactory"
extract-payload="false" destination="inboundAdaptorDefaultListenerQueue"
channel="inboundJMS" acknowledge="transacted">
<int:poller id="poller"
max-messages-per-poll="100" fixed-rate="10">
<int:advice-chain>
<ref bean="txAdvice" />
</int:advice-chain>
</int:poller>
</int-jms:inbound-channel-adapter>
<tx:advice id="txAdvice" transaction-manager="jtaTransactionManager">
<tx:attributes>
<tx:method name="processMessage" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txOperation"
expression="execution(* axway.ReadMsgFromAxway.processMessage(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txOperation" />
</aop:config>
<int:service-activator input-channel="inboundJMS"
output-channel="serviceActivatorChannel" ref="insertMessageToDb" method="processMessage" />
<int:chain input-channel="serviceActivatorChannel" output-channel="nullChannel">
<int:service-activator ref="serviceActivator" />
</int:chain>
</beans>
ReadMsgFromAxway.java
public Message<File> processMessage(Message<?> message) {
//Insert into DB
trackerProcess.insertUpdateMessageTracker(message, "axwayChannel",
"axwayChannel", currentStatusID, null, null);
count++;
int mod = count % 2;
if (mod != 0) {
// pass every 2
String hello = "hey";
} else {
throw new RuntimeException("Testing transactional");
}
Message<File> springMessage = MessageBuilder.createMessage(payloadFile,
messageHeaders);
return springMessage;
}
The XML as is doesn't do anything, whether the runtime exception is thrown, or an exception is thrown at the next service activator component.
If I change the advice attributes to
<tx:method name="*" propagation="REQUIRED"/>
Then the exceptions at the 1st and 2nd service activator causes the rollback.
Oddly enough if I do this
<tx:method name="processMessage" propagation="REQUIRED"/>
<tx:method name="*" propagation="NEVER"/>
Then whether the runtime exception in the 1st service activator, or the 2nd activator is thrown, the message gets rolled back. I would think the pointcut would limit which class would cause the transaction, but I maybe I'm misunderstanding something.
Another note - THis application is housed in an ear file with several other wars. This context starts the entire inbound process, and connects to another war, which contains business logic, via a JMS queue. In the scenario of using method name="*" I saw the exceptions in the business logic war to cause the JMS message of the original inbound message get rolled back too. I was under the impression that the 2nd war would do its processing in another thread, since it receives a message via a queue, and thus not be part of the transaction. Could this be a side effect of JTA, which is container managed?
Thanks!

I'd recommend you to read Dave Syer's article about transaction and there you can find a link in the "More like this".
Right now it looks like you don't understand transactions and AOP at all. You should pay more attention to AOP support in Spring Framework.
In general declarative transactions (#Transactional on method) are the particular cases of AOP advices. The main concept behind any AOP is call stack boundary spawned by the method invocation for which we specify an advice.
But if there is no such a method in the target object, it won't be adviced and wrapped to an AOP proxy. Like in your case for the processMessage when you apply the txAdvice for some internal object around the org.springframework.messaging.Message.MessageSource as a contract of the JmsDestinationPollingSource for that <int-jms:inbound-channel-adapter>.
Instead you can use <transactional> configuration of the <poller>. And right: all the donwstream flow will be covered by transaction.
To finish transaction in this case for that internal
Callable<Boolean> pollingTask = new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
return doPoll();
}
};
around receive() and handleMessage(), you should just finish the method invocation as in regular #Transactional case. For this purpose we should shit the next message handling to the different thread. Just because by default all <channel>s are DirectChannel and tied with the current call stack.
For this purpose you can just use an ExecutorChannel (<int:dispatcher task-executor="threadPoolExecutor"/>) for that your serviceActivatorChannel.
From there you don't need the rest AOP configuration.
Not sure about your second question for an other web app. Looks like it has some logic to rallback its work in case of some inconsistency from your side. But anyway that looks like a different question.

Related

AOP advice on methods other than execute method of spring batch tasklet not being applied

This issue has started after migrating from spring 4.1.2 to 5.0.5, spring batch to 3.0.9 to 4.0.1 and hibernate 4.2.0 to 5.2.16
I have a spring batch tasklet of the format -
public class MyTasklet implements Tasklet {
public RepeatStatus execute(StepContribution arg0, ChunkContext arg1) {
a();
}
public void a(){
//a few hibernate calls here
}
}
Now I want my hibernate transaction boundary to be the method a() [being called from execute] and not the execute() method.
But when I try applying point-cuts to achieve the same I get a message "no transaction in progress". I have provided the sample xml below.
In the aop pointcut -instead of the method name 'a'[i.e public * myPackage.MyTasklet.a(..)], if I use * (i.e public * myPackage.MyTasklet.*(..)] or 'execute'[i.e public * myPackage.MyTasklet.execute(..)] the code works fine. Due to some technical reasons it is important to have the boundary at 'a' due to which I cannot have 'execute' or any other method as the boundary.
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory" />
</bean>
<aop:config>
<aop:pointcut id="Op1"
expression="execution(public * myPackage.MyTasklet.a(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="Op1" />
</aop:config>
This question has been asked hundreds of times here. Your method a() is called internally, but internal method calls are never intercepted by Spring AOP because in that case you actually call this.a(). This does not go through the wrapping dynamic proxy used by Spring AOP. If a() was called from outside, e.e. by another component, it would work. This behaviour is comprehensively documented in the Spring AOP manual.
If you want to intercept internal method calls you have to use AspectJ instead of Spring AOP. How to configure Spring for AspectJ and LTW (load-time weaving) is also documented in the Spring manual.
P.S.: This is completely unrelated to your version upgrades. In older Spring and Spring Batch versions it would be the same. You mixed refactoring (version upgrade) with functional changes, which you should never do. Too many moving targets for debugging. Refactoring means to change the code (or the configuration, in this case) without changing its functionality.

Akka Camel and Spring

I want to combine Akka, Apache Camel, Spring and do not know the way forward for leveraging the three things in the same project.
I was successfully able to
1. write some working code with akka, akka-camel extension and camel routes(Java DSL)
2. use camel and spring (use java DSL but spring for transactions and etc..)
Now I need to combine 1 and 2. Can anyone suggest me the simplest way to achieve this?
EDIT
Some say AKKA no longer supports Spring due to conflict in object instantiation as per the link below
Why spring integration doc for akka exists only for 1.3.1 but not for next versions
Also a similar question is there without a proper solution being presented but the post is about 2 years old
akka-camel 2.2.1 route definition using Spring XML
In one blog post (which I can't get hold of the link right now) a method has been described which is in summary, the actors are defined and used Akka way and what ever the processing Akka actors does to be wired using Spring. But there wasn't any solid example.
I imagine your #2 looks like this:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ctx="http://www.springframework.org/schema/context"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd >
<!-- Camel route configuration -->
<camelContext id = "testCamelRouteContext" xmlns="http://camel.apache.org/schema/spring">
<route id="test_data_webservice">
<from uri="jetty:http://localhost:8888/myTestService"/>
<log logName="HTTP LOG" loggingLevel="INFO" message="HTTP REQUEST: ${in.header.testdata}"/>
<process ref="myTestService"/>
</route>
</camelContext>
<context:annotation-config />
<bean class="com.package.service" id="myTestService"/>
<bean id="genericDao" class="com.dao.Impl">
<property name="dataSource" ref="datasource" />
</bean>
<bean id="testingDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
datasource stuff
</bean>
</beans>
Is it possible that you can get this camel context through Akka? Something like.
Add in your Akka config:
akka.camel.context-provider="myNewContext"
New ContextProvider class:
class myNewContext extends ContextProvider{
override def getContext(system: ExtendedActorSystem): SpringCamelHybridContext
}
I am guessing this is where the bean injection collision between Spring and Akka could occur. I have never used Akka before so my answer is trivial but I wanted to see if I could provide some help to you.
Reviving an old thread.
akka-springctx-camel library is there to make your life painless to integrate Akka, Spring, Camel, CXF etc.
Add artifact :
<dependency>
<groupId>com.github.PuspenduBanerjee</groupId>
<artifactId>akka-springctx-camel</artifactId>
<version>1.0.0</version>
</dependency>
Add Camel Context Provider in Akka config:
akka.camel.context-provider=system.SpringCamelContextProvider
Get hold of ActorSystem :
implicit val system = SpringContextActorSystemProvider.create
Create a custom RouteBuilder[other way could be Akka Consumer]
class CustomRouteBuilder(system: ActorSystem, echoActor: ActorRef)
extends RouteBuilder {
def configure {
from("direct:testEP")
.routeId("test-route")
.to(echoActor)
}
Get Camel(Spring) Context and add routes to it:
val camel = CamelExtension(system)
camel.context.addRoutes(
new CustomRouteBuilder(system, system.actorOf(Props[EchoActor])))
This test case will give you a detailed idea: https://github.com/PuspenduBanerjee/akka-springctx-camel/blob/master/src/test/scala/AkkaSpringCtxTestSpec.scala

#Transactional in the controller

First of all I want to mention that I fully agree to only make the service layer transactional, but sometimes world is not perfect, and right now I´m in the middle of that situation.
Basically I have been assigned into a wonderful project with a legacy code of 4+ years. The thing is that the developers did not follow any pattern where to introduce the bussines logic so you can image multiples services call from the controller and after that some extra call to private method into the controller.
No budget to refactor, and we have many issues with ACID so the only solution that I found is make the controllers transactional and at least then have a full rollback if something in the middle of the request/response go wrong.
The problem is that I cannot make it works. I will describe you my configuration to see if you can help me out guys.
I have a DispatcherServlet that invoke webmvc-config.xml where I have the declaration of the controllers
<context:component-scan base-package="com.greenvalley.etendering.web.controller**" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
Then the contextConfiguration invoke my applicationContext.xml where I have all the rest of my Spring configuration.
After read so many tickets I tried many convination, for example try to declare again my controllers into the application context.
<tx:annotation-driven mode="aspectj"/> I tried with proxy as well
<context:component-scan base-package="com.greenvalley.etendering.web.controller.*" />
But still nothing.
In the configuration of my txManager I dont do nothing fancy, just add the reference to the entityManagerFactory and that´s it
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
In my controller I add the #Transactional, but nothing every time that I made a request to the #transactional class/method I dont see that the breakpoint into JpaTransactionalManager doBegin method stop
any suggestion please!
Regards

Why do we use <cxf:rsServer> as opposed to a plain <jaxrs:server> when using the CXF-RS component?

As a follow-up to this question, I'm still a bit confused about how to properly use the CXF-RS component.
I'm confused why we need the <cxf:rsServer> tag for specifying CXF-RS endpoints (or is there even such a concept?), when I can use the <jaxrs:server> tag perfectly fine.
Here's my configuration XML for both Camel and CXF:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<jaxrs:server id="userService" address="/users">
<jaxrs:serviceBeans>
<bean class="com.example.UserServiceNoop" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" />
</jaxrs:providers>
</jaxrs:server>
<bean id="user" class="org.apache.camel.component.direct.DirectComponent" />
<camel:camelContext id="someCamelContext">
<camel:route id="userServiceRoute">
<camel:from uri="cxfrs:bean:userService" />
<camel:routingSlip>
<camel:simple>user:${header.operationName}</camel:simple>
</camel:routingSlip>
</camel:route>
<camel:route id="userServiceRetrieveUser">
<from uri="user:retrieveUser" />
<!-- Assume this is going to a useful Processor -->
</camel:route>
</camel:camelContext>
</beans>
UserService.java:
package com.example;
/* a bunch of imports... */
public interface UserService {
#GET
#Path(value="/{user.id}")
#Produces({MediaType.APPLICATION_JSON})
public User retrieveUser(
#PathParam("user.id") Integer id
);
}
UserServiceNoop.java
package com.example;
/* a bunch of imports ... */
public class UserServiceNoop implements UserService
{
#Override
public User retrieveUser(Integer id) {
throw new RuntimeException();
}
}
In this example, I'm not using any <cxf:rsServer> tag, yet it works fine. I know it goes through the CXF-RS component, because when I run the application, it doesn't throw any RuntimeExceptions, which is the expected behavior when using CXF-RS (the method implementation in the service class will not be called).
Am I missing something by not using this tag?
As the other answer says, the cxf:rsServer is mainly used to be processed by a Camel route as in the jaxrs:server the processing of the request is done by a classic controller.
For example:
Classic JAXRS server:
You will declare a classic Bean Rest (Controller) and inject a Service inside.
Sample of an XML config (extract):
<jaxrs:server id="deviceServiceSvcV1" address="/device/v1">
<jaxrs:serviceBeans>
<ref component-id="deviceServiceRest" />
</jaxrs:serviceBeans>
<!-- and other providers, interceptors, etc... here -->
</jaxrs:server>
<!-- Service bean -->
<bean id="deviceServiceRest" class="org.mycomp.device.rest.v1.ws.api.DeviceServiceRest">
<property name="deviceService" ref="deviceService" />
</bean>
The Controller class will process the request / response in a classic way (e.g. calling an injected service).
Camel route with cxf:rsServer
Sample of an XML config (extract):
<cxf:rsServer id="rsServer" address="/device/v1"
serviceClass="org.mycomp.device.rest.v1.ws.api.DeviceServiceRest">
<cxf:properties>
<!-- whatever here -->
</cxf:properties>
<!-- and other interceptors, etc... here -->
</cxf:rsServer>
and in the classes:
#Produces({ MediaType.APPLICATION_XML })
#Path("/")
public class DeviceServiceRest {
#GET
public Response listDevicess(
#QueryParam("model") String model,
#QueryParam("sid") String sid,
) {
return null; // never used
}
#GET
#Path("{id}")
public Response getDeviceById(
#PathParam("id") String id,
#QueryParam("model") String model,
#QueryParam("sid") String sid
){
return null; // never used
}
}
The REST Controller has empty methods (returning null) but I think the latest camel-cxf supports now an Interface which is more elegant than having methods returning null.
Now, the request processing can be implemented by a Camel Route like this:
from("cxfrs:bean:rsServer?synchronous=true")
.routeId("cxf-device-rest-v1")
.process( new CheckAuthenticationProcessor())
.choice()
.when(header("operationName").isEqualTo("listDevice"))
.setHeader("backenOperation").constant("list")
.setHeader("backendResource").constant("device")
.endChoice()
.when(header("operationName").isEqualTo("getDeviceById"))
.setHeader("backenOperation").constant("retrieve")
.setHeader("backendResource").constant("device")
.endChoice()
.end()
.bean("requestProcessor")
.to(InOut, backendEndpoint)
.process(checkResponseStatusCode())
.bean(new HttpResponseProcessor())
;
And you can also control the request / response processing as you want from the route.
These are two different kind of implementing a REST API (server side) but in my opinion this is a bit old school as modern framework like spring-boot does not need any of these.
I found the second way a bit too much overkill as I like Camel for integration purpose but using it for a REST API could be subject to discussion.
One use-case I can see is a HTTP REST Web-Service for asynchronous processing, the service responding 202 Accepted and the Camel Route making an integration of the request in asynchronous mode especially when a specific Camel Component can be easily used instead of a complex class (or any need of the EIP patterns).
You use cxf:reserver tag when you want to use CXF endpoint as the consumer of something. Say for example in a complex Apache Camel route or in Spring integration. is used when you are the provider of the endpoint serving requests.

Clarification Request about Declarative Transaction via XML configuration in Spring Framework

I am studying Spring Declarative Transaction via XML configuration reading this article:
http://www.tutorialspoint.com/spring/declarative_management.htm
I am only having some proble to understand well how AOP work in this case, in my Beans.xml configuration file I have:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="create"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="createOperation"
expression="execution(* com.tutorialspoint.StudentJDBCTemplate.create(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation"/>
</aop:config>
So, what exactly means this configuration?
I think that work in the following way (but I am not sure):
The transaction semantics to apply are encapsulated in the definition and I think that, in this case, simply specify that the create() method definied in the StudentDAO interface have to be a transactional behavior (is it right?)
Regarding the meaning of the content of aop:config tag I think that only ensure that the above transactional advice runs for any execution of com.tutorialspoint.StudentJDBCTemplate.create() method
Is it right? Or am I missing something?
Tnx
Andrea
You are right,
aop:pointcut will find out all the joinpoints where advise should be applied, defined with tx:advice.
also tx:advice gives extra tags to filter out these join points using tx:method tags with method attribute.
In above mentioned example,
pointcut will find only one joinpoint, and tx:advice will filter out joinpoints with tx:method's name attribute and apply specified configuration.In example default configuration values will be used.

Categories

Resources