I am using Jackrabbit to store files (data store) and Hibernate almost everything else. I do not know alot of transactions etc. but I know that I want a global transaction for these two so that an exception rolls back everything. At the moment the database stuff is rolled back, but Jackrabbit isn't.
I am using Spring 3.2. I have deployed the Jackrabbit JCA adapter to JBoss (7.1.1). I have these lines in the config xml:
<bean id="txManager"
class="org.springframework.transaction.jta.JtaTransactionManager"></bean>
<tx:annotation-driven transaction-manager="txManager"
proxy-target-class="true"/>
However that isn't enough it seems. Could somebody give me some clues to what I need to read about/where to find information on this? I need to roll back everything if something happens to one of the resource providers.
This was quite tricky to set up. One gotcha was the spring automagically uses 'transactionManager' as a default name which caused problems. It is definitely worth the effort though as synchronising mismatched data sources would soon become a nightmare.
Here is my sample config that worked for me. Of course now we would probably use #Configuration instead of the xml. This worked using, Spring Data, JTA, MySQL with XA driver and Neo4j. Neo4j specific things have been omitted.
Spring Data may also help you here.
Here is a starter...
<tx:annotation-driven transaction-manager="xaTransactionManager" />
<bean id="xaTransactionManager" class="some.type.of.ChainedTransactionManager">
<constructor-arg>
<list>
<ref bean="jpaTransactionManager"/>
<ref bean="otherTransactionManager"/>
</list>
</constructor-arg>
</bean>
<bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="localContainerEntityManagerFactoryBean"/>
</bean>
<bean id="otherTransactionManager" class="other.type.of.jta.TransactionManager">
<property name="transactionManager" ref="otherTransactionManagerService"/>
</bean>
Related
I've got a Spring Integration flow which uses an inbound gateway to get messages from an IBM MQ queue:
<int-jms:inbound-gateway id="InputGateway"
request-destination="RequestQueue"
request-channel="RequestChannel"
reply-channel="ReplyChannel"
/>
However I'm not capable of assigning security settings. In particular, I need an username, password and userAuthenticationMQCSP = false (for reasons beyond the scope of this post, I won't get into details but my broker will throw a MQRC = 2009 otherwise).
I've followed the IBM guide to connect with jmsTemplate and works just fine. This uses the official Spring boot starter from IBM MQ which will kindly create a connection factory and will autoconfigure it with some defaults from application.properties:
ibm.mq.queueManager=myQMName
ibm.mq.channel=myChannel
ibm.mq.connName=myhostname(myPort)
ibm.mq.user=username
ibm.mq.password=*******
ibm.mq.userAuthenticationMQCSP=false
Now, back to the Spring Integration case. According to the int-jms:inbound-gateway spec, a connectionFactory will be injected to the gateway, by name (attribute: connection-factory) which is set up to be "jmsConnectionFactory" by default
By default, all of the JMS adapters that require a reference to the
ConnectionFactory automatically look for a bean named
jmsConnectionFactory. That is why you do not see a connection-factory
attribute in many of the examples. However, if your JMS
ConnectionFactory has a different bean name, you need to provide that
attribute.
I don't see any way to set up a predictable name for the connection factory that I can plug into the int-jms:inbound-gateway.
Now, taking a different approach, as per this example I've created my connectionFactory with an adecuate name:
<bean id="jmsConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="transportType" value="1"/>
<property name="queueManager" value="myQMName"/>
<property name="hostName" value="myhostname"/>
<property name="port" value="myPort" />
<property name="channel" value="myChannel"/>
</bean>
But now I need somewhere to put the credentials and the security parameters. Looking at the example above, it looks like I need to plug something like:
<bean id="secureJmsConnectionAdapter" class="**yourpackages.SecureJMSConnectionAdapter**">
<property name="targetConnectionFactory" ref="${jms.mq.connection.factory}" />
<property name="userName" value="${jms.username}"/>
<property name="pwdAlias" value="${jms.alias}"/>
</bean>
However it is unclear to me how to implement this SecureJMSConnectionAdapter.
Additionally, if I set up my own connection factory, I will lose all of MQ boot starter automagic thanks to this annotation on the MQAutoConfiguration class:
#ConditionalOnMissingBean(value=javax.jms.ConnectionFactory.class)
Any ideas on how to put these pieces together?
EDIT: Just to avoid any possible red herrings to anyone, the MQRC2009 was irrelevant to ibm.mq.userAuthenticationMQCSP=false.
Some of my old projects I used a bean like this:
<bean id="jmsQueueConnectionFactory"
class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="jmsConnectionFactory"/>
<property name="username" value="${jms.username}"/>
<property name="password" value="${jms.alias}"/>
</bean>
Should work well as a wrapper for your com.ibm.mq.jms.MQQueueConnectionFactory, but you have to use this jmsQueueConnectionFactory in the target components.
Although it looks like the mentioned IBM MQ JMS Spring doesn't that for us properly exposing a jmsConnectionFactory bean. You can rely on the default from Spring Integration in this case or use that jmsConnectionFactory explicitly for the connection-factory.
Also with Spring Boot you should consider to go away from XML configuration and give a chance for Spring Integration Java DSL: https://docs.spring.io/spring-integration/docs/5.1.7.RELEASE/reference/html/#java-dsl
Trying to test file lock mechanism in spring boot application by starting two instances of same application pointing to same source path which contains 10 files. Expecting only one instance should process a file and once processed it will be deleted from source. Same file should not be processed by other instance.So added Niolocker to the scanner. Tested in both windows and linux environments.But in windows, facing below exception in both the instances... In Linux, same file is polled/processed by both instances. No impact in Linux. Have implemented the below logic to acquire lock.
Please suggest on this.
Windows exception:
java.io.IOException: The process cannot access the file because another process has locked a portion of the file
Linux:
Both instance poller picks the same file and processing it
<file:inbound-channel-adapter id="filesInChannel" directory="file:${base.path}" auto-startup="false" scanner="recursiveScanner" auto-create-directory="true">
<integration:poller id="poller" max-messages-per-poll="${max.messages.per.poll}" fixed-rate="${message.read.frequency}" task-executor="pollingExecutor">
<integration:transactional transaction-manager="transactionManager" />
</integration:poller>
</file:inbound-channel-adapter>
<bean id="inboundFilter" class="org.springframework.integration.file.filters.CompositeFileListFilter">
<constructor-arg>
<list>
<bean class="org.springframework.integration.file.filters.AcceptOnceFileListFilter"/>
<bean class="org.springframework.integration.file.filters.RegexPatternFileListFilter">
<constructor-arg value="${file.type}"/>
</bean>
</list>
</constructor-arg>
</bean>
<bean id="inboundChannelNioLocker" class="org.springframework.integration.file.locking.NioFileLocker" />
<bean id="recursiveScanner" class="org.springframework.integration.file.RecursiveDirectoryScanner">
<property name="filter" ref="inboundFilter" />
<property name="locker" ref="inboundChannelNioLocker"/>
</bean>
The NioLocker is really operation system dependent and doesn't guarantee exclusive access to the file. Well, only Windows does that for us properly.
I even start considering to deprecate and remove it altogether from the Framework. It causes too much confuses for target users...
Instead of file locker you need to consider to use a FileSystemPersistentAcceptOnceFileListFilter based on the shared ConcurrentMetadataStore. So, this way really only one instance will pick up the file for processing. All others will skip it and move on to the next files.
See Reference Manual for more info.
I have a server application. Now I'm using Spring not only to inject dependencies, but also to config my application. Something like this:
<bean id="server" class="foo.bar.Server">
<property name="host" value="${config.host}"/>
<property name="someBean">
<ref bean="someBean"/>
</property>
</bean>
My colleague sad that configuring application in Spring is not obvious and we should avoid this. I see logic in his words, because Spring is for dependence injection and server port is not dependency, isn't it? But for me configuring application is Spring is very convenient and obvious. Is my colleague right?
Configuring in Spring is simple, clear and maintainable.
This way you can easily create several instances with different properties.
I read about using
<context:component-scan base-package="tld.mydomain.business">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
and annotate my service beans with #Service("myService"), and thought great, I'll do that, since I'm already doing that with my controllers. My usual service bean configuration looks like
<bean id="userService" parent="txProxyTemplate">
<property name="target">
<bean class="tld.mydomain.business.UserServiceImpl"/>
</property>
<property name="proxyInterfaces" value="tld.mydomain.business.UserService"/>
</bean>
so now that I generate them, how do I wrap them in a Hibernate proxy such as TransactionProxyFactoryBean? Or is there a better way to do that as well?
I have not yet gone all the way and used #Repository as well, is that required?
Cheers
Nik
Using TransactionProxyFactoryBean is not encouraged in modern Spring applications, although it still works. The typical approach nowadays is to annotate classes with #Transactional, and then stick this element in your application context file:
<tx:annotation-driven transaction-manager="txManager"/>
This and other strategies are discussed in great depth in the reference document, and there's even a side note about TransactionProxyFactoryBean.
There's no need for
<context:include-filter type="annotation"expression="org.springframework.stereotype.Service"/>
Spring will register #Service, #Repository, #Component... once they are found in the base package.
Like #Rob said either use #Transactional or <aop:config>...</aop:config> to handle your transactions at the service level.
If you have two different resources that need to be in the same transaction, then you will need to use JTA. See my answer to an earlier question here. Your config would need to look something like:
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName" value="appserver/jndi/path" />
</bean>
Where appserver/jndi/path would need to be replaced with the JNDI path of the JTA transaction manager that comes with your application server (although you can use a standalone JTA transaction manager such as JOTM as well). Typical paths as mentioned in the 2.5.x API are:
"java:comp/UserTransaction" for Resin 2.x, Oracle OC4J (Orion), JOnAS (JOTM), BEA WebLogic
"java:comp/TransactionManager" for Resin 3.x
"java:appserver/TransactionManager" for GlassFish
"java:pm/TransactionManager" for Borland Enterprise Server and Sun Application Server (Sun ONE 7 and later)
"java:/TransactionManager" for JBoss Application Server
I'm having trouble starting a transaction with Hibernate and MySQL while running in JUnit. I'm getting a HibernateException which states: "No TransactionManagerLookup specified". I believe this error is because I don't have a proper configuration setting for hibernate.transaction.manager_lookup_class.
I see that under the namespace of org.hibernate.transaction there are quite a few different lookup classes that I could use. All of the documentation that I could find on these was very vague. My question is what is the appropriate one for MySQL?
I do it with Spring and its transaction managers. Works perfectly.
To fix this I needed to make the following changes.
Changed the hibernate.cfg.xml => hibernate.current_session_context_class from jta to thread.
Changed the transaction manager to
org.springframework.orm.hibernate3.HibernateTransactionManager
in the bean configuration.
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" >
<property>
<bean>