Correct usage of JPA in jsp application - java

I'm trying to develop a simple JSP based web application with JPA and would like to know the correct usage for developing one.
In my sample application I have two JSP pages and a simple Java class to perform database operations. Both the JSP files use this Java class to perform DB operations.
I've annotated this class with #Stateless and injected an Entity manager as follows:
#PersistenceContext(unitName = "myjpa")
EntityManager em;
In my persistence.xml I've set the following property:
<property
name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform"
/>
I'm calling the class in JSP using JNDI (as the class is annotated for a stateless session bean) as follows:
InitialContext ic = new InitialContext();
Sample sample = (Sample) ic.lookup("java:app/" + application.getContextPath() + "/Sample");
I'm facing the following scenarios:
When I try to use a transaction em.getTransaction().begin()/commit() for insert and update, it says can not use transaction with JTA case.
So in the constructor code of my Java class I use the following code:
Properties properties = new Properties();
properties.put("javax.persistence.transactionType", "RESOURCE_LOCAL");
emf = Persistence.createEntityManagerFactory("myjpa",properties);
em = emf.createEntityManager();
I tried to use transactions like em.getTransaction().begin()/commit().
But in this case the pages become very slow after 2-3 database update and load operations. Though I'm not getting any exception. Overall in my table I'm having less than 25 records.
To me it seems as if it is waiting internally for some operation to complete.
At the same time I also feel that the way I'm using JPA is wrong and hence soliciting advice for the correct approach for doing even simple web apps with JSP and JPA.
While I'm still exploring Java EE, in case you have any specific reference for such cases I'll like to read and look them too.

You should always strive to use JTA transactions which means the container will handle the transaction demarcations. In your case if you want to handle transactions by your self, you need to define it as a bean managed transaction. So in your EJB class, after the #Stateless annoattions, you should define the following annotation;
#TransactionManagement(TransactionManagementType.BEAN)
The usual best practice is to let the container handle the transactions, unless there is some explicit reason for you to use Bean managed transactions.

At the same time I also feel that the way I'm using JPA is wrong
Your usage indeed seems wrong. If you're using a (stateless) session bean you do not have to fiddle with em.getTransaction().begin()/commit() and you definitely don't have to use code such as Persistence.createEntityManagerFactory.
You also don't have to set the property org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform.
A session bean automatically manages the transaction for you, and within a Java EE AS (such as JBoss AS) you don't have to configure any transaction manager or similar things.
An example:
#Stateless
public class UserDAO {
#PersistenceContext
private EntityManager entityManager;
public void add(User user) {
entityManager.persist(user);
}
}
As for the persistence.xml file, something like the following should be enough to get started:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
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">
<persistence-unit name="somePU">
<jta-data-source>java:app/someDS</jta-data-source>
</persistence-unit>
</persistence>
Some more examples:
http://jdevelopment.nl/sample-crud-app-with-jsf-and-richfaces
http://arjan-tijms.omnifaces.org/2011/08/minimal-3-tier-java-ee-app-without-any.html

Related

Exception using EntityManager and Glassfish v3 - IllegalStateException: Attempting to execute an operation on a closed EntityManager

I work in a project that uses JavaEE. I work with Glassfish servers version 3. I'm frequently having a problem (not always) in my singleton EJB's that use an EntityManager instance. A lot of times, I get this error:
[timestamp] [http-thread-pool-8080(49)] ERROR com.sun.xml.ws.server.sei.TieHandler.serializeResponse Attempting to execute an operation on a closed EntityManager.
java.lang.IllegalStateException: Attempting to execute an operation on a closed EntityManager.
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.verifyOpen(EntityManagerImpl.java:1662) ~[org.eclipse.persistence.jpa.jar:2.3.4.v20130626-0ab9c4c]
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:643) ~[org.eclipse.persistence.jpa.jar:2.3.4.v20130626-0ab9c4c]
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:532) ~[org.eclipse.persistence.jpa.jar:2.3.4.v20130626-0ab9c4c]
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.find(EntityManagerWrapper.java:320) ~[container-common.jar:3.1.2.1]
The log goes on, but I just showed the top of it. The next line of the log was the call to an WebService deployed in the same server. And when this error happens, it is always originated by a call to a WebService deployed in the same server that performs a find in the database using the method 'find' from the entityManager instance.
The entity manager is being injected outside of the bean in the #PostConstruct of a #WebService annotated class, using the line '(EntityManager)new InitialContext().lookup("java:comp/env/persistence/etc");' This is the class that receives all the incoming requests and decides which bean should be called, based on request.
Right after receiving a request, this class calls the respective singleton bean, based on the request, passing the injected EntityManager to the respective bean.
I understand that the EntityManager is closed when I try to perform the operation and that is indeed the problem. However, I thought this opening and closing of the EntityManager was managed automatically. Apparently it doesn't work that way. I'm not closing the EntityManager directly anywhere in the code either.
I'm not seeing any reasonable solution to approach this problem. All I find in online resources is that it may be a Glassfish bug and restart the server generally works. Nothing concrete to solve the problem.
Some of the information present in the PersistenceUnit configured in the persistence.xml file I'm using is presented below.
<persistence-unit> name="XXX" transaction-type="JTA"
<provider>org.eclipse.persistence.jpa.PersistenceProvider></provider>
<jta-data-source>jdbc/YYY</jta-data-source>
<properties>
<property name="eclipselink.target-database" value="Oracle"/>
<property name="eclipselink.cache.shared.default" value="false"/>
<property name="eclipselink.cache.size.default" value="0"/>
<property name="eclipselink.cache.type.default" value="None"/>
<property name="eclipselink.weaving.internal" value="false"/>
<property name="toplink.target-database" value="Oracle"/>
<property name="eclipselink.session.customizer"
value="aaa.bbb.ccc.IsolateEmbeddablesCustomizer"/>
</properties>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
</persistence-unit>
Do you have any idea on how to solve this problem and did any of you also got the same error?
Thank you.
I think the the problem lies just here:
The entity manager is being injected outside of the bean in the
#PostConstruct of a #WebService annotated class, using the line
'(EntityManager)new
InitialContext().lookup("java:comp/env/persistence/etc");' ...
Container provides EntityManagers from some pool it maintains. EMs have some lifecycle and they can become invalid at some point of time. Normally (explained a bit later) this would not be a problem since usually EMs are injected in a managed way.
But you initialize it once in #PostConstruct to some variable and when EM pointed by that variable gets invalid it is not re-initialized or so because it is no managed by container the way meant to be.
I think you can get around if this problem by just checking if EM is invalid and doing the lookup again if reference is not valid. But I stress: that is not the correct way.
passing the injected
EntityManager to the respective bean.
Do not pass the EM. Initialize EM in the bean that uses it. You will not have any savings by passing the one and only instance. On the contrary it can make the performance worse. Let the container handle the optimization of creating of EMs.
So , normally you would be doing something like this in your beans (not passing the EM but managing it on a bean):
#PersistenceContext(unitName="XXX") // "unitName" might not be needed
private EntityManeger em; // if you use only one persistence unit
to make EM managed correctly. That way container makes sure it is always valid.
If you have correctly constructed beans that you let container to initialize by for example #Injecting those to your #WebService this should be possible.
If for some reason it is not possible then you might still do a JNDI lookup in the bean but then I am quite sceptic about functionality of any JTA transactions or so.

java.lang.ClassCastException,Getting Entitymanager Via JNDI Lookup

I am new to JPA and developing a webapp(J2EE) where the webapp is in Tomcat so I can't use #PersistenceContext. I decided to use a Helper class and everything was going fine. Then I decided to implement JNDI for connection pooling and I managed to get Datasource.
The Helper Class looks like the following:
try {
Context initCtx = new InitialContext();
entityManager = //class cast exception
(EntityManager)initCtx.lookup(
"java:/comp/env/jdbc/LCDS"
);
DataSource ds= (DataSource)initCtx.lookup(
"java:/comp/env/jdbc/LCDS"
);
System.out.println(ds.getConnection()+"Cool");
//jdbc:mysql://localhost:3306/XXXXXXX, UserName=root#localhost, MySQL-AB JDBC DriverCool
emf=(EntityManagerFactory) source.getConnection(); //class cast exception
emf = Persistence.createEntityManagerFactory("XXXX"); //working version
}
The error is:
ava.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.BasicDataSource cannot be cast to javax.persistence.EntityManager
I don't know where I am getting wrong. I am not able to get EntityManagerFactory or EntityManager via JNDI lookup. I tried #Resource(name="jdbc/LCDS") and #PersistenceUnit(name="jdbc/LCDS").
To use a JNDI datasource in JPA, this should be specified in the persistence.xml, something like:
<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">
<persistence-unit name="..." transaction-type="RESOURCE_LOCAL">
<non-jta-data-source>java:/comp/env/jdbc/LCDS</non-jta-data-source>
...
Then you just have to create your EntityManagerFactory via Persistence#createEntityManagerFactory(String). If you want to recycle the EntityManagerFactory, this should be done outside of JNDI (e.g. as a ServletContext attribute). This is because Tomcat is not a Java EE server, only a servlet container: he is not able to inject the persistence unit.
UPDATE
JNDI access to persistence unit is not possible due to Tomcat limitations. See JPA Tomcat limitations. You will have to use emf = Persistence.createEntityManagerFactory("UNIT NAME").
Sorry for misleading answer. I've tested that on WebSphere Liberty, didn't have Tomcat at hand.
If you need that functionality check WebSphere Liberty, which is as fast and lightweight as Tomcat, but is fully Java EE Web profile compliant. It has lots of useful features like JPA, EJBLite, JAX-RS already available if needed, without fighting with additional libraries configuration.
UPDATE END
I've checked on WebSphere Liberty, you need to create reference to lookup your persistence unit via JNDI. You have two options to create that:
Use annotation at the class level
In any of your servlets you need to define annotation using the follownig:
#PersistenceUnit(name="JPATestRef", unitName="UnitName")
public class JPATester extends HttpServlet {
...
Use entry in web.xml
<persistence-unit-ref>
<persistence-unit-ref-name>JPATestRef</persistence-unit-ref-name>
<persistence-unit-name>UnitName</persistence-unit-name>
</persistence-unit-ref>
Then you access it using the following code:
try {
InitialContext ctx = new InitialContext();
System.out.println("looking EntityManagerFactory:");
EntityManagerFactory emf2 = (EntityManagerFactory) ctx.lookup("java:comp/env/JPATestRef");
System.out.println("emf:2" + emf2);
} catch (NamingException e) {

How to get jpa datasource properties from Entity Manager

Hi everybody
I was wondering if it's possible to get database connection properties through entity manager.
My persistence.xml looks like this
<persistence ...>
<persistence-unit name="default" transaction-type="JTA">
<jta-data-source>DatasourceForTestSystem</jta-data-source>
<class> some.package.and.some.Class </class>
...
</persistence-unit>
</persistence>
I want something like
String host = em.getSomeFunction().getProperties().get("server");
String database = em.getSomeFunction().getProperties().get("database");
or
String url = em.getSomeFunction().getConnectionPool().getURL();
where url is something like jdbc:oracle:thin:#1.2.3.4:5678:database.
I'm using JDeveloper 12c with EclipseLink, an Oracle database and NO Hibernate.
Does somebody know how to get information about the connection properties?
Kind regards,
Stefi
-- UPDATE --
#Kostja: thx again for your help but as I mentioned in my post I do not use Hibernate at all.
I already tried to use the Connection.class like this
java.sql.Connection conn = em.unwrap(java.sql.Connection.class);
from here. I always got a NPE for the Connection as well as for getSession() in this statement
((JNDIConnector)em.unwrap(JpaEntityManager.class)
.getSession().getLogin().getConnector()).getName();
from here.
I'm quiet confused why any of these solutions work for me. Maybe I'm missing something :-(
The farthest you can go with JPA is to query the properties of the EntityManagerFactory or the Connection. The list of available properties varies between providers and between different version of a single provider.
Access the properties of the EMF like this:
Map<String,Object> props = emf.getProperties();
Getting your hands on the Connection is a bit more involved and depends on the JPA implementation. This could work for Hibernate, courtesy #Augusto:
cast the EntityManagerFactory to HibernateEntityManagerFactory,
call getSessionFactory() and cast it to SessionFactoryImpl, call getConnectionProvider()
connectionProvder.getConnection();

JPA Unknown Source

I'm creating my first JPA application using NetBeans. I'm unable to make the persistence work. The connection to database works well, when I run the application the database tables got created. But when I try to create EntityManagerFactory:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("PISProjektPU");
I get:
INFO: javax.persistence.PersistenceException: [PersistenceUnit: PISProjektPU] Unable to build EntityManagerFactory
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:677)
at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:126)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:78)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
at cz.vutbr.fit.pis.spravaTechniky.service.TestManager.<init>(TestManager.java:28)
at cz.vutbr.fit.pis.spravaTechniky.service.__EJB31_Generated__TestManager__Intf____Bean__.<init>(Unknown Source)
...
My persistence.xml file looks like this (generated by NetBeans, I didn't change anything):
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" 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">
<persistence-unit name="PISProjektPU" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/myslq_spravaTechniky</jta-data-source>
<class>cz.vutbr.fit.pis.spravaTechniky.data.TestEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
</properties>
</persistence-unit>
</persistence>
and it's located here:
src/conf/persistence.xml
build/web/WEB-INF/classes/META-INF/persistence.xml
I searched the forum and found some tips how to remove this error, but I was unable to make it work. I tried to add these two lines to Manifest.mf:
Meta-Persistence: META-INF/persistence.xml
JPA-PersistenceUnits: PISProjektPU
I tried to move the persistence.xml file to all possible locations. I also added all libraries that seemed like they might be useful, when I go to Properties/Libraries, I see:
Java EE 6 API Library
Hibernate
Java-EE-GlassFish-v3
EclipseLink(JPA 2.0)
EclipseLink-GlassFish-v3
Hibernate JPA
JSF 2.0
Java EE Web 6 API Library
Persistence
I'm sure I'm doing some stupid simple mistake, but after a day trying to make this work I am unable to see where is the problem. To be honest right now I'm just totally confused about where to put which file or how to configure everything, so I'm randomly trying different things. I will be thankful for any advice!
Edit:
Thanks for the suggestion. My test classes actually look like this:
Class TestManager:
#Stateless
public class TestManager {
#PersistenceContext
private EntityManager em;
public void save(TestEntity t) {
em.merge(t);
}
public void remove(TestEntity t) {
em.remove(em.merge(t));
}
public void create(TestEntity t) {
em.persist(t);
}
#SuppressWarnings("unchecked")
public List<TestEntity> findAll() {
return em.createQuery("SELECT t FROM TestEntity t").getResultList();
}
}
Class TestBean:
#Named(value="testBean")
#Dependent
public class TestBean {
#EJB
private TestManager testManager;
/** Creates a new instance of TestBean */
public TestBean() {
}
public List<TestEntity> getEntities() {
return this.testManager.findAll();
}
}
I'm calling the TestBean.getEntities method:
...
<h:dataTable value="#{testBean.entities}" var="entity">
...
This causes the following exception:
javax.ejb.EJBException
at com.sun.ejb.containers.BaseContainer.processSystemException(BaseContainer.java:5119)
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5017)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4805)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2004)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1955)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:198)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:84)
at $Proxy141.findAll(Unknown Source)
at cz.vutbr.fit.pis.spravaTechniky.service.__EJB31_Generated__TestManager__Intf____Bean__.findAll(Unknown Source)
at cz.vutbr.fit.pis.spravaTechniky.back.TestBean.getEntities(TestBean.java:27)
...
I tried to replace the #PersistenceContext with #EJB, but got javax.ejb.EJBException: javax.ejb.CreateException: Could not create stateless EJB.
try to use this one
#EJB
EntityManager em;
em.persist(someobject);
instead of factory, if you need to use factory , i suggest you to repeat steps of setting up the persistance of entities in your IDE
Several things to correct here:
First, you are mixing Hibernate and EclipseLink in the same application (why??) you should just use one of them, choose between Hibernate or EclipseLink as both are implementations of the same standard: JPA (and you will need to choose the JPA API from one of those implementations).
Try to replace the #EJB annotation for a #Inject one. With the stack you are using that one should work.
Using the "dependent pseudo-scope" (by means of the #Dependent annotation) is the same as not establishing a scope at all (no annotation). Remove the #Dependent annotation from your bean class and place there a #RequestScoped (#SessionScoped, #ApplicationScoped or whatever scope your bean should have).
In the end I made JPA work just by using one of the example projects in NetBeans (File > New Project > Samples > Java Web > JSF JPA). I used this as a base for my project. I am not sure what I was doing wrong but at least everything worked fine then. Anyway, thanks for the help!

JPA EntityManager big memory problems

I am encountering some problems with a web app that uses Spring, Hibernate and JPA. The problems are very high memory consumption which increases over time and never seems to decrease. They most likely stem from an incorrect usage of the EntityManager. I have searched around but I haven't found something for sure yet.
We are using DAOs which all extend the following GenericDAO where our ONLY EntityManager is injected:
public abstract class GenericDAOImpl<E extends AbstractEntity<P>, P> implements
GenericDAO<E, P> {
#PersistenceContext
#Autowired
private EntityManager entityManager;
[...]
The generic DAO is used because it has methods to get entities by ID and so on which would be a pain to implement in all ~40 DAOs.
The EntityManager is configured as a Spring bean in the following way:
<bean class="org.springframework.orm.jpa.JpaTransactionManager"
id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" />
<bean
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="entityManager" factory-bean="entityManagerFactory"
factory-method="createEntityManager" scope="singleton" />
The biggest problem I think is using this shared EntityManager for everything. In the services classes, we are using the #Transactional annotation for methods which require a transaction. This flushes the EntityManager automatically from what I read, but does is different from clearing, so I guess the objects are still in memory.
We noticed an increase in memory after each automatic import of data in the DB which happens every day (~7 files of 25k lines each, where a lot of linked objects are created). But also during normal functioning, when retrieving lots of data (let's say 100-200 objects at a time for a request).
Anyone has any idea how I could improve the current situation (because it's kind of bad at this point...)?
Edit: Have run a profiler on the deployed app and this is what it found:
One instance of "org.hibernate.impl.SessionFactoryImpl" loaded by "org.apache.catalina.loader.WebappClassLoader # 0xc3217298" occupies 15,256,880 (20.57%) bytes. The memory is accumulated in one instance of "org.hibernate.impl.SessionFactoryImpl" loaded by "org.apache.catalina.loader.WebappClassLoader # 0xc3217298".
This is probably the EntityManager is not cleared?
I'm inclined to agree with your assessment. EntityManagers aren't really designed to be used as singletons. Flushing the EntityManager doesn't clear anything from memory, it only synchronizes entities with the database.
What is likely happening is the EntityManager is keeping reference to all of the objects in the persistence context and you're never closing the context. (This guy had a similar issue.) Clearing it will indeed remove all references from EntityManager to your entities, however, you should probably re-evaluate how you use your EntityManager in general if you find yourself constantly having to call clear(). If you are just wanting to avoid LazyInitializationExceptions, consider the OpenSessionInViewFilter from Spring*. This allows you to lazily load entities while still letting Spring manage the lifecycle of your beans. Lifecycle management of your beans is one of the great advantages of the Spring Framework, so you need to make sure that overriding that behavior is really what you want.
There are indeed some cases where you want a long-lived EntityManager, but those cases are relatively few and require a great deal of understanding to implement properly.
*NOTE: OpenSessionInView requires great care to avoid the N+1 problem. It's such a big issue that some call Open Session in View an AntiPattern. Use with caution.
Edit
Also, you don't need to annotate #PersistenceContext elements with #Autowired as well. The #PersistenceContext does the wiring itself.
The non JEE compliant application server, you should not be using #Autowired/#PersistenceContext private EntityManager entityManager;!
What you should be doing is something like this:
class SomeClass {
#PersistenceUnit private EntityManagerFactory emf;
public void myMethod() {
EntityManager em = null;
try {
em = emf.createEntityManager();
// do work with em
}
} catch (SomeExceptions e) {
// do rollbacks, logs, whatever if needed
} finally {
if (em != null && em.isOpen()) {
// close this sucker
em.clear();
em.close();
}
}
}
Some notes:
This applies to Non Full JEE app server with Spring + Hibernate
I've tested it with JDK 1.7 and 1.8, no difference in terms of leaks.
Regular Apache Tomcat is not true JEE app server (TomEE is however)
List of Java EE Compliant App Servers
You should delete #Autowired annotation from above private EntityManager entityManager; and remove entityManager bean definition from your context definition file. Also, if you don't use <context:annotation-config/> and <context:component-scan/> XML tags you must define PersistenceAnnotationBeanPostProcessor bean in your context.

Categories