how to invoke multiple http webservice in mule flow in transaction? - spring

I am new to mule.
I have a spring-hibernate mule setup. Suppose there are 3 webservice.Aim is to invoke all those webservice in a mule flow so that all 3 will be in a transaction. so that suppose if 3rd webservice fails then the previous 2 will be rolled back automatically.
Here is my code snippet what I tried.
my mule-flow.xml(currently I have only one webservice,kindly let me know how can I add multipe webservice call in flow?)
<spring:beans>
<spring:import resource="classpath:spring-mule.xml"/>
<spring:import resource="classpath:applicationContext-persistence.xml"/>
</spring:beans>
<flow name="addCustomer" doc:name="addCustomer">
<http:inbound-endpoint exchange-pattern="request-response"
address="http://localhost:8081/pos/addCustomer" doc:name="HTTP" />
<cxf:simple-service serviceClass="com.proj.pos.webservice.interfac.CustomerService" doc:name="SOAP"/>
<component ><spring-object bean="customerService"/></component>
</flow>
</mule>
My spring-mule.xml
<bean id="customerService" class="com.proj.pos.webservice.implementation.CustomerServiceImpl">
<property name="cusDao" >
<ref local="customerDao"/>
</property>
</bean>
My:applicationContext-persistence.xml
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521:xe" />
<property name="username" value="xyz" />
<property name="password" value="xyz" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="datasource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
<prop key="hibernate.connection.release_mode">auto</prop>
</props>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="customerDao" class="com.proj.pos.dao.implementation.CustomerDaoImpl">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
my CustomerServiceImpl
#WebService(endpointInterface = "com.proj.pos.webservice.interfac.CustomerService",
serviceName = "CustomerService")
public class CustomerServiceImpl implements CustomerService {
#Autowired
private CustomerDao cusDao;
#Transactional //NOTE:USING THIS ANNOTATION I AM ABLE TO ACHIEVE THE BELOW METHOD //IN TRANSACTION,BUT I BELEIVE THIS FEATURE WILL NOT WORK IF WE HAVE MULTIPLE WEBSERVICE CALL
#Override
public Customer addCustomer(CustomerDto dto) {
Customer customer=new Customer(dto.getCustomerId(), dto.getFname(), dto.getLname(), dto.getAge(), dto.getDateOfBirth(), dto.getAddress());
customer.setCustomerId(cusDao.persist(customer));
return customer;
}
public CustomerDao getCusDao() {
return cusDao;
}
public void setCusDao(CustomerDao cusDao) {
this.cusDao = cusDao;
}
}
Please let me know any solution.Thanks

By seeing your question what I understood is your trying to make 3 web-service calls and you want to make all three calls in a single transaction.
As you are making a call to another system (Web-service in your case) you don't have control to maintain the transaction.
In your case you can use a Scatter gather router to call three web-services if any route(web-service call) is failed it will throw CompositeRoutingException, you can very well catch this exception in your catch exception strategy.
In your catch exception strategy you need to do the roll back activities (make another web-service call or db call which will fulfill your rollback requirement ).

As per my understanding, you have a three or more webservices calls and some db operations. you want to rollback if any service call fails.
Write a spring bean as below for SpringTransactionFactory and set transationManager property (ref from your applicationContext-persistence.xml)
<spring:beans>
<spring:import resource="classpath:spring-mule.xml"/>
<spring:import resource="classpath:applicationContext-persistence.xml"/>
<spring:bean id = "transactionFactory" class = "org.mule.module.spring.transaction.SpringTransactionFactory">
<spring:property ref="transactionManager" name=""></spring:property>
</spring:bean>
</spring:beans>
And add a tansactionfactory ref to inboundEndpoint as below
<http:inbound-endpoint exchange-pattern="request-response"
address="http://localhost:8081/pos/addCustomer" doc:name="HTTP" >
<custom-transaction action="ALWAYS_BEGIN" factory-ref="transactionFactory"/>
</http:inbound-endpoint>
Complete flow will be in single transaction and inclouding dao classes

Related

Call SOAP service asynchronously using Spring

I've to call a SOAP web service asynchronously. Currently, I'm calling it in a synchronous way using Spring webservicetemplate.
Current config is like:
<bean id="interceptedHttpClientBuilder" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="httpClientBuilder" />
<property name="targetMethod" value="addInterceptorFirst"> </property>
<property name="arguments">
<list>
<bean class="org.springframework.ws.transport.http.HttpComponentsMessageSender.RemoveSoapHeadersInterceptor"/>
</list>
</property>
</bean>
<bean id="requestConfigBuilder" class="org.apache.http.client.config.RequestConfig" factory-method="custom">
<property name="socketTimeout" value="120000" />
</bean>
<bean id="requestConfig" factory-bean="requestConfigBuilder" factory-method="build" />
<bean id="httpClient" factory-bean="httpClientBuilder" factory-method="build" />
<bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create">
<property name="defaultRequestConfig" ref="requestConfig" />
</bean>
<bean id="messageSender" class="org.springframework.ws.transport.http.HttpComponentsMessageSender">
<constructor-arg ref="httpClient"></constructor-arg>
</bean>
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="packagesToScan">
<list><value>...</value></list>
</property>
</bean>
<bean id="wsClientSecurityInterceptor"
class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="securementActions" value="UsernameToken" />
<property name="securementUsername"><value>${username}</value></property>
<property name="securementPassword"><value>${password}</value></property>
<property name="securementPasswordType" value="PasswordText" />
</bean>
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="marshaller" ref="jaxb2Marshaller"></property>
<property name="unmarshaller" ref="jaxb2Marshaller"></property>
<property name="defaultUri"><value>${ws.url}</value></property>
<property name="interceptors">
<list>
<ref local="wsClientSecurityInterceptor"/>
</list>
</property>
<property name="messageSender" ref="messageSender"></property>
</bean>
Java call looks like:
MyResponse response = (MyResponse) webServiceTemplate.marshalSendAndReceive(req, new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) {
((SoapMessage) message).setSoapAction("test");
}
});
May I know how can I change it to call the service asynchronously? Or Do I need to use something else in spring to achieve this?
Not sure why you use spring-integration tag in your question, but if we are here, please, definitely take a look into the #MessagingGateway with the Future<> as a return type: https://docs.spring.io/spring-integration/docs/5.0.1.RELEASE/reference/html/messaging-endpoints-chapter.html#async-gateway
The SOAP WebService can be called via Spring Integration <int-ws:outbound-gateway>: https://docs.spring.io/spring-integration/docs/5.0.1.RELEASE/reference/html/ws.html
The samples are here: https://github.com/spring-projects/spring-integration-samples
To be more clear the code might looks like this:
<int:gateway id="mathService"
service-interface="org.springframework.integration.samples.async.gateway.MathServiceGateway"
default-request-channel="requestChannel"
async-executor="executor"/>
Where that MathServiceGateway is like this:
public interface MathServiceGateway {
Future<Integer> multiplyByTwo(int i);
}
The WS call is simple as well:
<int-ws:outbound-gateway request-channel="requestChannel" uri="http://www.w3schools.com/xml/tempconvert.asmx"/>

Reg Spring Batch Transaction

My Requirement is I need to have two datasource connected to Spring Batch Application.
1) One for Spring Batch Jobs and Executions storing
2) One for Business Data Stroing, Processing and Retreiving.
I know that there are lot of solutions for achieving this. But I have achieved by setting the second datasource as primary. The problem is the second datasource is not coming under transaction scope instead it is committing for each sql statement executing expecially through jdbctemplate.
As I can't able to edit my question. I am writing another Post in detail
My Requirement is I need to have two datasource connected to Spring Batch Application.
1) One for Spring Batch Jobs and Executions storing
2) One for Business Data Stroing, Processing and Retreiving.
In env-context.xml I have following configuration
<!-- Enable annotations-->
<context:annotation-config/>
<bean primary="true" id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/DB2XADS"/>
</bean>
<!-- Creating TransactionManager Bean, since JDBC we are creating of type
DataSourceTransactionManager -->
<bean id="transactionManager" primary="true"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- jdbcTemplate uses dataSource -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="batchTransactionManager"
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>
In override-context.xml I have the following code
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- jdbcTemplate uses dataSource -->
<bean id="batchDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/MySqlDS"/>
</bean>
<bean class="com.honda.pddabulk.utility.MyBatchConfigurer">
<property name="dataSource" ref="batchDataSource" />
</bean>
<!-- Use this to set additional properties on beans at run time -->
<bean id="placeholderProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/org/springframework/batch/admin/bootstrap/batch.properties
</value>
<value>classpath:/batch/batch-mysql.properties</value>
<value>classpath:log4j.properties</value>
</list>
</property>
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="ignoreResourceNotFound" value="true"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="order" value="1"/>
</bean>
<!-- Overrider job repository -->
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="databaseType" value="mysql"/>
<property name="dataSource" ref="batchDataSource"/>
<property name="tablePrefix" value="${batch.table.prefix}"/>
<property name="maxVarCharLength" value="2000"/>
<property name="isolationLevelForCreate" value="ISOLATION_SERIALIZABLE"/>
<property name="transactionManager" ref="batchTransactionManager"/>
</bean>
<!-- Override job service -->
<bean id="jobService" class="org.springframework.batch.admin.service.SimpleJobServiceFactoryBean">
<property name="tablePrefix" value="${batch.table.prefix}"/>
<property name="jobRepository" ref="jobRepository"/>
<property name="jobLauncher" ref="jobLauncher"/>
<property name="jobLocator" ref="jobRegistry"/>
<property name="dataSource" ref="batchDataSource"/>
</bean>
<!-- Override job launcher -->
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
<property name="taskExecutor" ref="jobLauncherTaskExecutor" />
</bean>
<task:executor id="jobLauncherTaskExecutor" pool-size="21" rejection-policy="ABORT" />
<!-- Override job explorer -->
<bean id="jobExplorer"
class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
<property name="tablePrefix" value="${batch.table.prefix}"/>
<property name="dataSource" ref="batchDataSource"/>
</bean>
In job-config.xml I have the following code
<context:component-scan base-package="com.honda.*">
<context:exclude-filter type="regex"
expression="com.honda.pddabulk.utility.MyBatch*" />
</context:component-scan>
I have the custom Batch configurer set. Now the problem is when I try to execute queries with jdbctemplate for update and insert it is not under transaction which means #Transactional is not working.
Rather commit is happening for each method call. The example is
#Transactional
public void checkInsertion() throws Exception{
try{
jdbcTemplate.update("INSERT INTO TABLE_NAME(COLUMN1, COLUMN2) VALUES( 'A','AF' );
throw new PddaException("custom error");
}catch(Exception ex){
int count=jdbcTemplate.update("ROLLBACK");
log.info("DATA HAS BEEN ROLLBACKED SUCCESSFULLY... "+count);
throw ex;
}
}
In the above code I am trying to insert data and immediately I am also throwing a exception which means the insert should happen but commit will not. So we will not be able to see any data but unfortunately the commit is happening. Please some one help

Spring transactions doesn't work with Oracle Express

I have a simple standalone application to test transaction management with Spring.
Have Oracle Express Edition.
Run the following to enable XA
grant select on sys.dba_pending_transactions to user_test;
grant select on sys.pending_trans$ to user_test;
grant select on sys.dba_2pc_pending to user_test;
grant execute on sys.dbms_system to user_test;
My Java code is pretty much as follow:
public class DbUpdater
{
private static final ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"spring_transactions.xml"});
private static Logger log = LoggerFactory.getLogger(DbUpdater.class);
#Transactional(propagation=Propagation.REQUIRED, readOnly=false)
public void updateData() {
IMasterDAO ds1 = context.getBean("masterDao", IMasterDAO.class);
log.info("Insert using ds1");
ds1.insert("insert into users values(?,?)", "user1", "John Hamilton");
log.info("Insert using ds1 finished successfully");
throw new RuntimeException("A runtime exception");
}
}
So all the idea is too see transaction rolling back.
I run with several configuration examples and record is committed all the time.
No rollback is performed. No errors nothing, only expected
Exception in thread "main" java.lang.RuntimeException: A runtime exception
at com.test.spring.transation.DbUpdater.updateData(DbUpdater.java:22)
My last config is this:
<bean id="txManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="bitronixTransactionManager" />
<property name="userTransaction" ref="bitronixTransactionManager" />
</bean>
<bean id="btmConfig" factory-method="getConfiguration"
class="bitronix.tm.TransactionManagerServices">
<property name="serverId" value="spring-btm" />
</bean>
<bean id="bitronixTransactionManager" factory-method="getTransactionManager"
class="bitronix.tm.TransactionManagerServices"
depends-on="btmConfig,dataSource"
destroy-method="shutdown" />
<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource"
init-method="init" destroy-method="close">
<property name="className" value="oracle.jdbc.xa.client.OracleXADataSource"/>
<property name="uniqueName" value="myOracleDataSource"/>
<property name="minPoolSize" value="0"/>
<property name="maxPoolSize" value="5"/>
<property name="allowLocalTransactions" value="true"/>
<property name="testQuery" value="select sysdate from dual"/>
<property name="driverProperties">
<props>
<prop key="user">${jdbc.username}</prop>
<prop key="password">${jdbc.password}</prop>
<prop key="URL">${jdbc.url}</prop>
</props>
</property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="masterDao" class="com.test.spring.transation.MasterDAO">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
</beans>
The JDBC template being instantiated via supplied data source, seems to work with its own transaction [there by the automatic begin and commit transaction]. The exception is thrown after that which operates in seperate commit/rollback cycle and hence you see that the writes persisted. To verify it, you can move the code to throw exception in MasterDAO class and examine rollback.

Send JMS Message with Spring JmsTemplate

I have a server that needs to send messages to a separate application. I'm using Spring JmsTemplate, however, I'm having some issues with getting the configuration up and running.
Right now, I'm getting the following exception:
Error creating bean with name 'connectionFactory' defined in ServletContext resource [/WEB-INF/config/application-context.xml]: Invocation of init method failed; nested exception is javax.naming.CommunicationException: Receive timed out [Root exception is java.net.SocketTimeoutException: Receive timed out]
(I can post the full stack trace if you like, but it's just the long version of those nested exceptions.)
The "receive timed out" part makes it sound like it's trying to receive messages, which I don't want to do. Everything here has been pulled together from a couple different examples and SO posts, and I'm having trouble wrapping my head around all of the different parts and what they're doing. In addition to whatever might be causing the error, is there anything I don't need if I'm not receiving messages?
In my JmsQueueSender class (which sends messages):
private JmsTemplate jmsTemplate;
private Destination destination;
public void setConnectionFactory(ConnectionFactory cf) {
jmsTemplate = new JmsTemplate(cf);
}
public void setQueue(Queue queue) {
this.destination = queue;
}
In my application context:
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop>
<!-- <prop key="java.naming.provider.url">jnp://address.com:port</prop> -->
<prop key="java.naming.factory.url.pkgs">org.jboss.naming:org.jnp.interfaces</prop>
</props>
</property>
</bean>
<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate" />
<property name="jndiName" value="ConnectionFactory" />
</bean>
<bean id="jmsQueueConnectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="connectionFactory"/>
<property name="pubSubDomain" value="false" />
</bean>
<bean id="jmsDestinationResolver"
class="org.springframework.jms.support.destination.JndiDestinationResolver">
<property name="jndiTemplate">
<ref bean="jndiTemplate"/>
</property>
<property name="cache">
<value>true</value>
</property>
</bean>
<bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate102">
<property name="connectionFactory" ref="jmsQueueConnectionFactory" />
<property name="destinationResolver" ref="jmsDestinationResolver" />
<property name="pubSubDomain" value="false" />
</bean>
<bean id="jmsSender" class="package.JmsQueueSender">
<property name="queue" value="queue/AlertQueueGIAfterSent" />
<property name="connectionFactory" ref="jmsQueueTemplate" />
</bean>

Spring: How to inject a property with a non-setter method?

Is it possible to inject a property bean through a method with a signature doesn't start with set?
Specifically, I'm trying to use Spring to configure an embedded Jetty instance and I need to be able to inject a servlet bean via an addServlet() method.
I am looking at Jetty/Tutorial/Embedding Jetty documentation. I guess you mean calling ServletContextHandler.addServlet(). You have few choices:
#Configuration (since 3.0)
My favourite approach. You can configure everything using Java!
#Configuration
public class Jetty {
#Bean(initMethod = "start")
public Server server() {
Server server = new Server(8080);
server.setHandler(context());
return server;
}
#Bean
public ServletContextHandler context() {
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.addServlet(servlet(), "/*");
return context;
}
#Bean
public ServletHolder servletHolder() {
return new ServletHolder(helloServlet());
}
#Bean
public HelloServlet helloServlet() {
return new HelloServlet();
}
}
Inheritance/decorating
You can inherit from or wrap original ServletContextHandler class to follow Java bean naming conventions. Of course it requires an extra class, but makes Jetty class Spring-friendly. You can even publish such wrapper or maybe someone already did that?
MethodInvokingFactoryBean
I don't like this approach as it seems too low level. Basically you create a bean that calls arbitrary method with arbitrary arguments:
<bean id="javaVersion" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="servletContextHandler"/>
<property name="targetMethod" value="addServlet"/>
<property name="arguments">
<list>
<ref bean="yourServlet"/>
</list>
</property>
</bean>
just the spring file adapted to Jetty 7. It's possible to add yours contextHandlers...
<bean id="contexts"
class="org.eclipse.jetty.server.handler.ContextHandlerCollection" />
<context:property-placeholder location="src/main/resources/ws.properties" />
<!-- Manually start server after setting parent context. (init-method="start") -->
<bean id="jettyServer" class="org.eclipse.jetty.server.Server"
destroy-method="stop">
<property name="threadPool">
<bean id="ThreadPool" class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<property name="minThreads" value="10" />
<property name="maxThreads" value="50" />
</bean>
</property>
<property name="connectors">
<list>
<bean id="Connector" class="org.eclipse.jetty.server.nio.SelectChannelConnector">
<property name="port" value="8181" />
</bean>
</list>
</property>
<property name="handler">
<bean id="handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
<property name="handlers">
<list>
<ref bean="contexts" />
<bean id="defaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler" />
<bean class="org.eclipse.jetty.servlet.ServletContextHandler"
p:contextPath="/${ws.context.path}">
<property name="sessionHandler">
<bean class="org.eclipse.jetty.server.session.SessionHandler" />
</property>
<property name="servletHandler">
<bean class="org.eclipse.jetty.servlet.ServletHandler">
<property name="servlets">
<list>
<bean class="org.eclipse.jetty.servlet.ServletHolder"
p:name="spring-ws">
<property name="servlet">
<bean
class="org.springframework.ws.transport.http.MessageDispatcherServlet" />
</property>
<property name="initParameters">
<map>
<entry key="contextConfigLocation" value="classpath:/spring-ws-context.xml" />
</map>
</property>
</bean>
</list>
</property>
<property name="servletMappings">
<list>
<bean class="org.eclipse.jetty.servlet.ServletMapping"
p:servletName="spring-ws" p:pathSpec="/*" />
</list>
</property>
</bean>
</property>
</bean>
<bean class="org.eclipse.jetty.server.handler.RequestLogHandler" />
</list>
</property>
</bean>
</property>
</bean>

Resources