I tried to obtain the TransactionManager in a #Singleton SessionBean - EJB 3.1 - to control the scope of my transaction, because i have to access a database on a #PostConstruct method. If an exception occurrs, I cannot let the Container RollBack because it throws the TransactionRolledbackException: setRollbackOnly called from within a singleton post construct method.
I am using a JTA DataSource and defined the #TransactionManagement(TransactionManagementType.BEAN) to override control of the transaction.
#Resource
private TransactionManager transactionManager;
returns to me a NullPointerException when i try to do a "transactionManager.begin();". Does anyone knows how to solve this ?
UPDATE:
the code i am using is this:
#Startup
#Singleton
#TransactionManagement(TransactionManagementType.BEAN)
public class RuntimeContextEJB
{
#EJB
private RepositoryRecursosExternosFactoryEJB repositoryRecursosExternosFactoryEJB;
#EJB
private MetodologiaIndiceLiquidezFactoryEJB metodologiaIndiceLiquidezFactoryEJB;
#EJB
private FuncaoMatematicaFactoryEJB funcaoMatematicaFactoryEJB;
private boolean bootstrapRunning = false;
private List<String> dadosMercadoMonitorados;
#PersistenceContext(unitName = "crv-persistence-unit")
private EntityManager entityManager;
#Resource
private TransactionManager transactionManager;
#PostConstruct
public void init()
{
// comentário
MotorCalculoContext.setupMotorCalculoContext(repositoryRecursosExternosFactoryEJB, metodologiaIndiceLiquidezFactoryEJB,
funcaoMatematicaFactoryEJB);
carregaDadosMercadoMonitorados();
}
public void sinalizarInicioBootstrap()
{
bootstrapRunning = true;
}
public void sinalizarTerminoBootstrap()
{
bootstrapRunning = false;
}
public boolean isBootstrapRunnnig()
{
return bootstrapRunning;
}
public void carregaDadosMercadoMonitorados()
{
try
{
transactionManager.begin();
this.dadosMercadoMonitorados = (List<String>) entityManager
.createQuery(
"SELECT DISTINCT(p.parametro.codigoDadoMercado) FROM PlanoExecucaoPasso p WHERE p.parametro.codigoDadoMercado <> '' AND p.parametro.codigoDadoMercado <> '0'")
.getResultList();
}
catch (Exception e)
{
}
}
}
I think there should be a JNDI adress to add on the #Resource annotation, one that is specific for WebSphere, but i really can't find wich is.
UPDATE:
why use JNDI on a container managed injection ? Since i am getting a nullpointer exception from a direct injection, tried to use like the ex. on page 305 from OReilly Enterprise Java Beans 3.1 6th edition.
#Resource(mappedName = "java:/TransactionManager")
//mappedName is vendor-specific, and in this case points to an address in JNDI
tried this with no success.
UPDATE
WebSphere is not getting our beans annotations - can't really know why - so the annotation:
#TransactionManagement(TransactionManagementType.BEAN)
was not working. So, edited de ejb-jar.xml and added the following code:
<transaction-type>Bean</transaction-type>
and the UserTransaction worked. Thanks for the answers.
When you have bean managed transaction, you don't use javax.transaction.TransactionManager but instead you use javax.transaction.UserTransaction.
And then you call begin, commit .... etc of UserTransaction interface.
Answer Updated:
1) First of all, as I said, don't use TransactionManager. Use UserTransaction
2) As you wanted to know the JNDI name of the UserTransaction object. It is java:comp/UserTransaction. But you need this only when your component is not managed. ie: Servlet, EJB. That process is called making a manual call to JNDI API
3) Provide commit() or rollback(). None of them is present.
I am looking at your class and it seems alright.
So, where is the problem ? (possibilities)
1) Your class is not treated as EJB (container managed) and which is why injection fails.
2) Transaction service is not started before EJB #Startup or it fails to start.
3) You have JTA Datasource configured in your persistence.xml. In which case, try:
#Resource
private EJBContext context;
userTransaction = context.getUserTransaction();
Note: Please also provide full stack trace and persistence.xml in order to pinpoint exact problem.
You don't need to use the Transaction Manager in programmatic (BMT) session beans, unless you want to suspend() or resume() the associated transaction in some cases, use the UserTransaction instead .
However, you can get a reference to the Transaction Manager in websphere by com.ibm.ws.Transaction.TransactionManagerFactory class using the static method getTransactionManager() .
public TransactionManager getTransactionManager() {
return TransactionManagerFactory.getTransactionManager();
}
Here's some sample code that runs properly using UserTransaction to have control over transactions.
#Singleton
#Startup
#TransactionManagement(TransactionManagementType.BEAN)
public class SampleUT {
Logger logger = Logger.getLogger(SampleUT.class.getName());
#Resource
private UserTransaction ut;
#PostConstruct
public void postConstruct()
{
logger.info("PostConstruct called");
try {
ut.begin();
...
The NullPointerException you're getting is probably related to you trying to use the injected resource inside the Constructor of your EJB. You should be aware that the injected reference is never available until the constructor of the EJB is finished, so if you try to use any injected reference inside the constructor, it will throw a NullPointerException.
Related
Does anyone tried integrating spring-data-jpa with java-ee application?
I'm using glassfish3 as an application container.
I followed an official spring-data-jpa tutorial and created a class:
public class EntityManagerFactoryProducer {
#Produces
#ApplicationScoped
public EntityManagerFactory createEntityManagerFactory() {
return Persistence.createEntityManagerFactory("myPU");
}
public void close(#Disposes EntityManagerFactory entityManagerFactory) {
entityManagerFactory.close();
}
#Produces
#RequestScoped
public EntityManager createEntityManager(EntityManagerFactory entityManagerFactory) {
return entityManagerFactory.createEntityManager();
}
public void close(#Disposes EntityManager entityManager) {
entityManager.close();
}
}
But when I try to deploy my application, I'm getting an exception:
Error occurred during deployment: Exception while preparing the app : Could not resolve a persistence unit corresponding to the persistence-context-ref-name [org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean/entityManager] in the scope of the module called [App]. Please verify your application.. Please see server.log for more details.
Command deploy failed.
What am I missing? Should I also have another configuration file or maybe some xml file?
Since you are in a Java EE Application Container you do not want to create your own Persistence instance. The example from the Spring Data documentation you used is for CDI environmets that do not have built in JPA support. Glasfish creates EntityManagerFactory and EntityManager for you. You only need to republish it as CDI bean. So in your case it is important to use the second example shown in the documentation:
public class EntityManagerProducer {
#Produces
#RequestScoped
#PersistenceContext
private EntityManager entityManager;
}
It's a bit more tricky that what is told in official documentation. To handle properly a Spring Repository in a CDI env, you need to declare:
a dependent entity manager producer
#Produces #Dependent #PersistenceContext
EntityManager entityManager;
a eager repository
#Eager public interface TestRepository extends CrudRepository<TestEntity, Long>
Then you'll be able to #Inject the repository in a CDI managed Bean.
If you don't use the #Dependent and the #Eager annotation, Spring will cause exceptions at the initialization of the repositories, leading to uncatch expcetions on the first request made against it.
References:
Spring Data JPA repositories use in EJB timer causes TransactionRequiredException
Getting a reference to EntityManager in Java EE applications using CDI
I'm trying to move out my project from Seam 3.
Now I'm stuck on JTA transactions after switching off Seam Faces module. There was integrated transaction management. Transactions were begun and commit automatically - without manual commit.
Now when I try to execute EntityManager.persist() or EntityManager.merge(Object entity), I've got error:
JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context)
Is there any way to force JTA to start transaction and commit it transparently?
Ps. Funny thing - some time ago I was looking for solution how to force manual commit/rollback in Seam3.
OK, if I put bean into #Stateless state - then it behaves as I expected.
But...
Isn't it - that if I put application managed EntityManager - then I should manage transaction on my own (method testApplicationJTA() in example below), but if I use container managed EntityManager - then it should work without transaction managing (method testContainterJTA() ) ?
My example:
#Named
#SessionScoped
public class Test implements Serializable {
private static final long serialVersionUID = 1L;
#PersistenceContext
private EntityManager em;
#PersistenceUnit
private EntityManagerFactory emf;
#Resource
private UserTransaction utx;
public void testContainerJTA() {
TestEntity entity = em.find(TestEntity.class, 1L);
entity.setName("dddddd");
em.merge(entity);
}
public void testApplicationJTA() {
EntityManager mgr = emf.createEntityManager();
TestEntity entity = em.find(TestEntity.class, 1L);
entity.setName("fffff");
try {
utx.begin();
mgr.joinTransaction();
mgr.merge(dict);
utx.commit();
} catch (Exception e) {
utx.rollback();
}
mgr.close();
}
}
In my example above method testContainerJTA() doesn't work. Why?
If I'll remove #SessionScoped and put #Stateless then method testApplicationJTA() doesn't work, but testContainerJTA() works. Why?
Should't they work both always - as application managed and container managed?
OK, so it is possible to make CDI bean tansactional - with interceptors :-)
Finally I managed to solve my problem reading this article:
http://smokeandice.blogspot.com/2009/12/cdi-and-declarative-transactions.html
Edit:
From JEE7 there is new #Transactional annotation which takes all JPA actions in CDI bean or method into transaction.
I'm working on a desktop application using Java SE 7. The application uses multiple threads and in each thread that is created a DAO class is injected to gain access to my database. As persistence layer i'm using EclipseLink and JPA. The EntityManager is injected into my DAO class using constructor injection and since it is not thread safe, I went for the approach using a Provder like this:
public PluginInstanceJpaController implements IPluginInstanceDao {
private EntityManager em;
#Injected
public PluginInstanceJpaController(Provider<EntityManager> emp) {
this.em = emp.get();
}
#Transactional
public void create(PluginInstance foo) throws Exception {
em.persist(foo);
}
}
However, the very same EntityManager instance is injected into each DAO. For setting that up I used the JpaPersistModule as it is provided by guice and i'm sure that there are not singletons in my setup so far.
Does anyone know how to tell guice to create a new instance of the EntityManager when injecting?
In another approach I tried custom providers for the EntityManagerFactory and the EntityManager and leaving the JpaPersistModule out of my business. This resulted in a EntityManager instance per DAO, however #Transactional annotated methods were not intercepted then.
I'd appreciate any solution to this issue.
Thanks so far!
--- EDIT ---
The DAO classes are injected into a Runnable that is using them. The Runnable is also provided through a Provider. My module configuration looks something like this:
public class RepositoryModule extends AbstractModule {
#Override
protected void configure() {
// DAO bindings
bind(IObjectStoreDao.class).to(ObjectStoreJpaController.class);
bind(IPluginInstanceDao.class).to(PluginInstanceJpaController.class);
}
#Provides
public PluginMonitor newMonitor(IPluginInstanceDao plugDao, IObjectStoreDao osDao) {
PluginMonitor m = new PluginMonitor();
m.setPluginInstanceDao(plugDao);
m.setObjectStoreDao(osDao);
return m;
}
}
Here PluginMonitor is my Runnable. The Injector itself is created in my main thread... might this have been the issue?
This is very similiar issue: How Guice injects singletons and non-singletons into multiple threads
To your DAO, this should work.
public PluginInstanceJpaController implements IPluginInstanceDao {
private Provider<EntityManager> emProvider;
#Injected
public PluginInstanceJpaController(Provider<EntityManager> emp) {
this.em = emp;
}
#Transactional
public void create(PluginInstance foo) throws Exception {
em.get().persist(foo);
}
}
You should use Jpa Persistence Module or create custom EntityManager provider, which will return new EntityManager for each get() call, also it can be implemented with ThreadLocal to ensure EntityManager will be shared across thread.
I'm not familiar with JPA, but hopefully I can still help :-)
If you look at the source for EntityManagerProvider, you can see there's a ThreadLocal<EntityManager>. So by default, each thread should have its own EntityManager. That leads me to believe the problem is elsewhere. Are you sure that no module is setting the EntityManager to be a singleton? How are you determining that all the EntityManagers are the same object? Each DAO is definitely on its own thread? Can you provide details on how FooDao is configured in your module and how a new FooDao is provided to each thread?
Also, you should be fine to write your constructor as:
#Inject
public FooDao(EntityManager emp) {
this.em = emp;
}
Guice will do the magic for you of determining that EntityManagerProvider provides EntityManager instances, and will call get() on the EntityManagerProvider instance to get an EntityManager to give to your constructor.
In the following code, a Null pointer exception is raised when I try to call beginTransaction method. I thought that JBoss would init my transaction... apparently not :\
What am I missing ?
JBoss 5.1.0.GA
JPA 1
JDK 6
import javax.annotation.Resource;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.transaction.UserTransaction;
public abstract class AbstractDAO {
#PersistenceUnit(unitName = "miniDS")
protected static EntityManagerFactory emf;
#Resource
protected UserTransaction t;
public AbstractDAO() {
}
protected void beginTransaction() throws Throwable {
t.begin();
}
protected void commitTransaction() throws Throwable {
t.commit();
}
protected void rollbackTransaction() throws Throwable {
t.rollback();
}
}
Your AbstractDAO does not seem to be managed. Injection only works in container managed objects. This is not specific to injection of UserTransaction, but injection in general. As result emf is null as well. Java EE specification lists following classes to be able to use injection:
Servlet: servlets, servlet filters, event listeners
JSP: tag handlers, tag library event listeners
JSF: scoped managed beans
JAX-WS: service endpoints, handlers
EJB: beans, interceptors
Managed Beans: managed beans
CDI: CDI-style managed beans, decorators
Java EE Platform: main class (static), login callback handler
Possible workaround are to move injection of resources to managed class or use JNDI lookup.
Your concrete class ConcreteDAO which extends AbstractDAO, should be an ejb, as said by Mikko Maunu and should manage itself transaction (beans that manage transaction themselves BMT), in other words:
#Stateless
#TransactionManagement(TransactionManagementType.BEAN)
public class ConcreteDAO extends AbstractDAO {
...
}
And it be better if you inject EntityManager in your AbstractDAO, and configure JBOSS datasource to manage transaction (local-tx-datasource or xa-datasource).
you can look at JBOSS DS config at:
https://community.jboss.org/wiki/ConfigDataSources
if you want to manage transaction yourself through EntityManager, with entityManagerFactory
EntityManager entityManager = emf.createEntityManager();
entityManager.getTransaction().begin();
you can't use UserTransaction and the JBoss DS should be no-tx-datasource
If you inject your persistence unit, try to get the transaction through the EntityManager.
EntityManager entityManager = emf.createEntityManager();
entityManager.getTransaction().begin();
For more information, have a look here: https://github.com/wicketstuff/core/wiki/How-to-use-#PersistenceUnit-annotation
Let's say I have the following dependencies:
#Configuration
public class MyCfg {
// ...
#Bean
public Session session() {
return sessionFactory().getCurrentSession();
}
}
#Repository
#Transactional
public class MyRepo {
#Autowired
private Session session;
}
sessionFactory() is set up properly. If I inject SessionFactory instead of Session, it works just fine. However, if try and inject Session, it dies with an exception on container bootstrap because there is no session bound to thread.
Since the repository is #Transactional, I know that at run time there will be a session. How can I make it work, so that it injects AOP-initialized Session at run time, but does not try and resolve it when the repo is instantiated?
I would take a look at this bit of Spring documentation regarding bean scopes. Near the bottom they show how to use the #Scope annotation, which you will want to apply to your session() method in MyCfg. It sounds like you would want to use the 'request' value, which will create a new instance of this bean for each HTTP request coming in.
I will also suggest taking a look at the <aop:scoped-proxy/> element for configuration. It is mentioned a couple times in the documentation, and may be useful for what you are trying to do.
This approach will get you into a lot of trouble. Instead of injecting a Session, which you now automatically scopes as a singleton, you should inject the SessionFactory instead. Instances of Session acquired within a #Transactional annotated method will adhere to those transaction rules, eg:
#Transactional(readonly=true)
public List<Person> getPersons() {
Session session = sessionFactory.getCurrentSession();
//find those darn people.
}
#Autowired
private SessionFactory sessionFactory;