JPA2: can an EntityManager not created via EJB injection still use JTA transactions - ejb-3.1

I have the following:
An JAR module, containing a DAO class like so:
public class WhateverDao {
#PersistenceContext(name="pu")
EntityManager entityManager;
public Whatever saveOrUpdate(Whatever entity) {
//entityManager.joinTransaction();
return entityManager.merge(entity);
}
The jar also contains a persistence.xml like so:
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="pu" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>jdbc/jee6Test_mysql_datasource</jta-data-source>
<!-- Entities classes declared here -->
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
</properties>
</persistence-unit>
</persistence>
and an empty beans.xml file.
This jar is used inside a web application (a WAR file), where the DAO is injected into a stateless EJB like so:
#Stateless
#LocalBean
public class WhateverEJBImpl {
#Inject
private WhateverDao whateverDao;
public void saveWhatever(Whatever whatever) throws IOException {
whateverDao.saveOrUpdate(whatever);
}
My issue basicaly is that I can't manage to make this code actually persist something in the database. As far as I understand:
my EntityManager should be "Container Managed" (due to how I configured it in the persistence.xml, and the fact that I obtain it via #PersistenceContext annotation, finally also because the jar is part of a WAR file which is deployed in JBOSS EAP 6.2 - also tried with WebLogic 12c).
The fact that I'm calling it through a stateless EJB means that, by default, there's already a transaction available, so there's no need for me to manage it manually
However, using the above described example simply doesn't persist any data to the db (when calling the EJB saveWhatever method).
What I've also tried tried:
calling entityManager.joinTransaction() before calling entityManager.merge(...) (commented line in the DAO code snippet). This gives the error:
javax.ejb.EJBException: javax.persistence.TransactionRequiredException: No active JTA transaction on joinTransaction call
manually calling entityManager.getTransaction().begin() and commit() (before and after entityManager.merge(...). This gives the error:
javax.ejb.EJBException: java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()
So, my question is, please: How do I:
make it so I can have a separate DAO class, in a separate JAR, that uses EntityManager without programmatically (manually) dealing with transactions
Integrate this DAO-classes-containing jar into a WebApplication that uses EJB so that I can take advantage of JTA and have it auto-manage my transactions (more to the point, I'd like to have the Stateless EJB promised behavior, where JTA takes care of creating a transaction for each of the EJB's method calls)

OK, well, for anyone else experiencing this: if you think everything's correctly setup with your EJBs and JTA, but still JTA transactions don't work, (fail silently, etc), here's how I solved it:
I changed from this persistence unit:
<!-- bad persistence.xml, JTA transactions don't work -->
<persistence-unit name="pu" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>jdbc/jee6Test_mysql_datasource</jta-data-source>
<!-- <class> tags go here -->
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
</properties>
</persistence-unit>
To this one:
<!-- good persistence.xml, JTA transactions work -->
<persistence-unit name="pu" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider> <!-- note change here ->
<jta-data-source>jdbc/jee6Test_mysql_datasource</jta-data-source>
<!-- <class> tags go here -->
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<!-- and removal of <property> here -->
</properties>
</persistence-unit>

Related

Steps to setup distributed transaction management in JBoss

I am trying to implement a distributed transaction (XA) in JBoss EAP 6.2 application server so that multiple datastores can be accessed in a single coordinated atomic transaction. To be more precise, I'd like my transactional service method to write to a database table and to a message queue in such a way that these two operations are either both committed or both rolled back consistently (all or nothing).
My approach is based on the following:
Use Spring JTA Transaction Manager
Configure the entity manager to use an XA JDBC datasource, defined in JBoss application server and accessed via a JNDI name
Use ActiveMQ XA Connection Factory for messaging
The problem I am facing is that only the database operation is rolled back. The message written to ActiveMQ queue is always commited regardless of the transaction being rolled back or not.
Key elements of my configuration:
<tx:jta-transaction-manager/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="xaDataSource" />
...
<property name="jpaProperties">
<props>
...
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</prop>
</props>
</property>
</bean>
<jee:jndi-lookup id="xaDataSource" jndi-name="xaDataSource"/>
<bean id="xaConnectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">
<property name="brokerURL">
<value>tcp://localhost:61616</value>
</property>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="xaConnectionFactory" />
<property name="defaultDestinationName" value="TEST_QUEUE" />
<property name="sessionTransacted" value="true"/>
</bean>
I finally got this working. The key was to configure the JMS connection factory within a JBoss Resource Adapter. Detailed steps below:
1. Install Apache ActiveMQ
Version used: 5.11.3
Detailed install instructions can be found here.
Once ActiveMQ installed, Create a queue named TEST_QUEUE (use admin console: http://127.0.0.1:8161/admin/index.jsp)
2. Set up Spring application context
Key elements:
Use Spring JTA Transaction Manager tag: this will prompt the use of
the app server transaction manager;
Configure the datasource bean to use the XA datasource defined in the app server (see XA JDBC datasource setup);
Wire the jtaDataSource attribute of the Entity Manager Factory to the XA datasource;
Set Hibernate property manager_lookup_class to JBossTransactionManagerLookup;
Configure the connection factory bean to use the XA connection factory bean defined in the app server (see XA Connection Factory setup);
Set property transactedSession of connection factory bean to false.
e
<?xml version="1.0" encoding="UTF-8"?>
<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:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:jms="http://www.springframework.org/schema/jms" xmlns:jee="http://www.springframework.org/schema/jee"
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://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
<jpa:repositories base-package="com.company.app.repository" />
<context:component-scan base-package="com.company.app" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<tx:jta-transaction-manager/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="xaDataSource" />
<property name="packagesToScan" value="com.company.app.domain" />
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</prop>
</props>
</property>
</bean>
<jee:jndi-lookup id="xaDataSource" jndi-name="jdbc/xaDataSource"/>
<bean id="xaConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="activemq/ConnectionFactory" />
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="xaConnectionFactory" />
<property name="defaultDestinationName" value="TEST_QUEUE" />
<property name="sessionTransacted" value="false"/>
</bean>
3. Set up application server (JBoss)
For a distributed transaction to work, all the datasources involved must be of type XA. JBoss supports JDBC XA datasource (xa-datasource tag) out of the box. The XA configuration for JMS datasource is achieved by defining appropriate Resource Adapter.
3.1. XA JDBC datasource
In standalone.xml under <subsystem xmlns="urn:jboss:domain:datasources:1.1"> <datasources> add an XA JDBC datasource:
<xa-datasource jndi-name="java:/jdbc/xaDataSource" pool-name="jdbc/xaDataSource" enabled="true">
<xa-datasource-property name="URL">
jdbc:oracle:thin:#<hostname>:<port_number>/<SID>
</xa-datasource-property>
<xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
<driver>ojdbc6-11.2.0.3.jar</driver>
<security>
<user-name>db_user</user-name>
<password>password</password>
</security>
</xa-datasource>
3.2. XA Conncection Factory
Resource adapters are a concept from the J2EE Connector Architecture (JCA) and are used to interface with Enterprise Information Systems, i.e. systems external to the application server (e.g., relational databases, mainframes, Message-Oriented Middleware, accounting systems, etc.).
First you need to install ActiveMQ RAR (Resource adapter ARchive) in JBoss, by dropping the appropriate RAR file from maven central under \standalone\deployments. Then, in standalone.xml, under <subsystem xmlns="urn:jboss:domain:resource-adapters:1.1"> add the following:
<resource-adapters>
<resource-adapter id="activemq-rar.rar">
<archive>
activemq-rar-5.11.3.rar
</archive>
<transaction-support>XATransaction</transaction-support>
<config-property name="Password">
admin
</config-property>
<config-property name="UserName">
admin
</config-property>
<config-property name="ServerUrl">
tcp://localhost:61616?jms.rmIdFromConnectionId=true
</config-property>
<connection-definitions>
<connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:/activemq/ConnectionFactory" enabled="true" pool-name="ConnectionFactory">
<xa-pool>
<min-pool-size>1</min-pool-size>
<max-pool-size>20</max-pool-size>
<prefill>false</prefill>
<is-same-rm-override>false</is-same-rm-override>
</xa-pool>
</connection-definition>
</connection-definitions>
</resource-adapter>
</resource-adapters>
For further details about installing ActiveMQ RAR in JBoss, refer to RedHat documentation.
4. Make your Service method Transactional
#Service
public class TwoPhaseCommitService {
#Autowired
private EmployeeRepository employeeRepository;
#Autowired
private JmsTemplate jmsTemplate;
#Transactional
public void writeToDbAndQueue() {
final Employee employee = new Employee();
employee.setFirstName("John");
employee.setLastName("Smith");
// persist entity to database
employeeRepository.save(employee);
// write message to TEST_QUEUE
jmsTemplate.send(new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(employee.getFirstName());
}
});
// To test rollback uncomment code below:
// throw new RuntimeException("something went wrong. Transaction must be rolled back!!!");
}
}

Jboss RestEasy web service connection pooling

Getting error
NoSuchMethodError: org.apache.http.impl.conn.DefaultClientConnectionOperator.(Lorg/apache/http/conn/scheme/SchemeRegistry;Lorg/apache/http/conn/DnsResolver;)
Using httpclient-4.2-alpha1.jar
Configuration :
<!-- Rest easy connection pooling -->
<bean id="poolingClientConnectionManager" class="com.auction.acp.rest.impl.ConnectionManager" >
</bean>
<bean id="httpClient" class="org.apache.http.impl.client.DefaultHttpClient" >
<constructor-arg name="conman" ref="poolingClientConnectionManager"> </constructor-arg>
</bean>
When I explore jar this constructor is already there.
First thing which is coming in my mind is some other library [I'm using JBoss] is in use.
Tried with exclusions in jboss-deployment-structure.xml but no luck.
<exclusions>
<module name="org.apache.httpcomponents" />
<module name="org.apache.http.impl.conn" />
</exclusions>
If the constructor exists in the JAR you're "exploring" but JBoss can't find it, it means JBoss is not using the JAR you want it to. I suggest using Logback for logging, as it'll add the name of the JAR to the stacktrace in your logs so you know which JAR JBoss is using.

Why does Persistence.createEntityManagerFactory("transactions-optional") errors when appengine is deployed

I have created an appengine which runs fine and returns records from my Google cloud SQL db in debug mode. When I deploy the appegine and run the endpoint it errors. And the error I get in the appengine log is:
Caused by: org.datanucleus.exceptions.NucleusUserException: There is no available StoreManager of type "jdbc". Make sure that you have put the relevant DataNucleus store plugin in your CLASSPATH and if defining a connection via JNDI or DataSource you also need to provide persistence property "datanucleus.storeManagerType".
Here is a list or the jars in war\WEB-INF\lib directory:
appengine-api-1.0-sdk-1.7.6
appengine-api-labs
appengine-endpoints
appengine-jsr107cache-1.7.6
asm-4.0
com.sun.tools.xjc_2.2.0
com.sun.xml.bind_2.2.0.v201004141950
datanucleus-api-jdo-3.1.3
datanucleus-api-jpa-3.1.3
datanucleus-appengine-2.1.2
datanucleus-core-3.1.3
eclipselink
eclipselink-jpa-modelgen_2.4.1.v20121003-ad44345
gcm-server
geronimo-jpa_2.0_spec-1.0
javax.activation_1.1.0.v201108011116
javax.mail_1.4.0.v201005080615
javax.persistence_2.0.4.v201112161009
javax.xml.bind_2.2.0.v201105210648
javax.xml.stream_1.0.1.v201004272200
jdo-api-3.0.1
json_simple-1.1
jsr107cache-1.1
jta-1.1
org.eclipse.persistence.jpars_2.4.1.v20121003-ad44345
Here is my persistence.xml:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
<persistence-unit name="transactions-optional" transaction-type="RESOURCE_LOCAL">
<provider></provider>
<class>com.example.myapp.Class1</class>
<class>com.example.myapp.Class2</class>
<properties>
<property name="datanucleus.NontransactionalRead" value="true"/>
<property name="datanucleus.NontransactionalWrite" value="true"/>
<property name="javax.persistence.jdbc.driver" value="com.google.appengine.api.rdbms.AppEngineDriver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:google:rdbms://something.com:someproj:someapp/somedb"/>
<property name="javax.persistence.jdbc.user" value=""/>
<property name="javax.persistence.jdbc.password" value=""/>
</properties>
</persistence-unit>
</persistence>
Using:
cloud sql
JPA
Datanucleous v2
SDK 1.7.6
Jre7
As it works fine in debug mode I dont understand what the problem might be as I am new to appengine. Please let me know if you need more information.
Thanks guys.
Make your mind up which JPA provider you're using ... for Cloud SQL (not AppEngine, so you don't need "datanucleus-appengine", nor do you need "datanucleus-api-jdo" either FWIW). You have DataNucleus JPA (version 3 actually, but omitting datanucleus-rdbms jar for some reason, yet CloudSQL needs it), and you have EclipseLink also. You then don't set the persistence provider in persistence.xml so leave it all to chance which one it tries to give you ... and it tries DataNucleus JPA but you haven't included the datanucleus-rdbms jar so you can't persist to an RDBMS without that.

Cloud Foundry + JPA + Spring + EntityManager

I want to deploy a Web based WAR into CloudFoundry using a cloud datasource.
I have defined a bean like this:
<cloud:data-source id="dataSource"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="myPersistenceUnit" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
</bean>
</property>
</bean>
</beans>
....but when i try to deploy I obtain a Java Agent exception :
Cannot apply class transformer without LoadTimeWeaver specified
But i can't specfy a Java Agent whithout uploading a jar instrument agent.....
Any solution??
I'm not that familiar with EclipseLink, so I'm not even sure that the weaver requirement comes from EclipseLink, BUT
One way of doing this would be to deploy your app as a standalone app (i.e. deploy your own tomcat around it), that way you can put the extra weaver jar in lib/.
Have a look at http://blog.cloudfoundry.org/2012/06/18/deploying-tomcat-7-using-the-standalone-framework/ and https://github.com/ericbottard/cloudfoundry-tomcat-7
Also, if you only have one DataSource, you can avoid using the cloudfoundry-specific <cloud:datasource /> namespace by just uploading your regular app and have Cloud Foundry auto reconfigure your app (info here: http://blog.springsource.org/2011/11/04/using-cloud-foundry-services-with-spring-part-2-auto-reconfiguration/) As a matter of fact, this may be the way to have EclipseLink work seamlessly on Cloud Foundry (my guess here)
And of course, there's also the option of switching to another provider that doesn't require class instrumentation, but that's a bit extreme.
Again, I'm not an Eclipse Link guru, so I may be missing something here...

JPA entity manager factory creation failing; JBoss, Hibernate and SQL Server

Running JBoss 5.1, with Hibernate as the JPA provider. Backed with SQL Server 2008.
I'm receiving an error at server startup, which is java.lang.ClassCastException: org.hibernate.dialect.SQLServerDialect cannot be cast to org.hibernate.dialect.Dialect. Pretty clear message, but I'm baffled as to the underlying cause. I have hibernate-core-3.5.1-Final.jar on the classpath, and the necessary class files are present.
This dialect setting was giving no error in the project when it was being used as a property being passed to a Spring AnnotationSessionFactoryBean, but I'm trying to refactor a piece to straight EJB/JPA. For what it's worth, here's my persistence config:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
version="1.0">
<persistence-unit name="[my name here]">
<jta-data-source>java:jdbc/[my name here]</jta-data-source>
<properties>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.EhCacheProvider" />
</properties>
</persistence-unit>
I hate these kind of "here's my config and my stacktrace" questions, but I've been poking around on this for an hour and a half and am failing to come up with any new ideas.
The ClassCastException is caused by having two copies of the javax.persistence APIs in your system. When running on JBoss, you are just not supposed to package persistence jar in your application. Remove all the persistence related jar's from your application and the exception should go away.

Resources