Java EE - Connect EJB to Oracle Database through Glassfish resource - java

I am total newbie in Java and EE especially. I started an EE project that should provide REST API which will handle 2 entities in remote Oracle Database. I am using NetBeans because it is the only way how to accomplish anything in Enterprise Java (as I see it now).
What I've done:
I created JDBC pool in Glassfish (v4.1-13). I can ping the pool successfully. Then I created JDBC Resource for the pool.
I generated Entity classes for the two entities I need to handle.
<persistence version="2.1" xmlns...>
<persistence-unit name="semestralka-ejbPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/dbs</jta-data-source>
<class>cz.ctu.bitjv.kopecj24.semestralka.entities.Food</class>
<class>cz.ctu.bitjv.kopecj24.semestralka.entities.User</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.target-database" value="Oracle"/>
</properties>
</persistence-unit>
</persistence>
I have a stateless EJB which calls entity manager like this:
public FoodServiceBean()
{
this.facade = new FoodFacade(Food.class);
this.facade.setEntityManager(Persistence.createEntityManagerFactory("semestralka-ejbPU").createEntityManager());
}
Then, there is a REST service class that should list the entities from the database.
#Path("food")
public class FoodResource {
#Context
private UriInfo context;
private FoodServiceInterface service;
/**
* Creates a new instance of FoodResource
*/
public FoodResource() {
try {
InitialContext ic = new InitialContext();
service = (FoodServiceInterface) ic.lookup("java:global/semestralka/semestralka-ejb/FoodServiceBean");
} catch (NamingException ex) {...}
}
#GET
#Produces(MediaType.TEXT_PLAIN)
#Path("list")
public String getAll() {
List<Food> foods = service.listAllFood();
...
}
}
Unfortunately, once I request the getAll action (visit localhost:8080/semestralka-war/wr/food/list ) I get this exception:
Warning: StandardWrapperValve[cz.ctu.bitjv.kopecj24.semestralka.rest.ApplicationConfig]: Servlet.service() for servlet cz.ctu.bitjv.kopecj24.semestralka.rest.ApplicationConfig threw exception
javax.naming.NameNotFoundException: dbs not found
Here is a screenshot of the exception screen:

Double check the connection pool name in persistence unit and glassfish server. Also could you update your question with the entities.

I can see that your ejb calling from rest service is wrong. You need to add remote interface name with package path.
Lets say your package path is com.rs.www then your lookup string should be following one :
service = (FoodServiceInterface) ic.lookup("java:global/semestralka/semestralka-ejb/FoodServiceBean!com.rs.www.FoodServiceInterface");
Thanks.

Finally, I've found a solution. Problem was in my FoodServiceBean. I was trying to instantiate the facade in the EJB constructor but the EntityManager is injected after the constructor. So here is code of the Bean that helped me solve the issue.
#Stateless
#EJB(beanInterface=FoodServiceInterface.class, name="FoodServiceBean")
public class FoodServiceBean implements FoodServiceInterface {
#PersistenceContext(unitName="testPU")
private EntityManager em;
private FoodFacade facade;
public FoodServiceBean()
{
}
#PostConstruct
public void init() {
this.facade = new FoodFacade(Food.class);
this.facade.setEntityManager(em);
}
Please note that I changed the name of persistence unit just to be sure there are no typos.
Thanks for the help.

Related

How to execute insert query on deploy of java ee application?

I have a java ee application with a web application and ejb module. There is some tables I want to be populated automatically when deployed. I have the entities set up and the sql file with the queries to be executed.
I feel it may be something to do with the persistence.xml file but not sure what to include. So, how do I get my server(wildfly) to execute the sql queries on deploy, similar to the way that you can specify the persistence.xml to drop and create as the table generation strategy.
If it makes a difference, I am using postgres for my database provider, java ee 7 and wildfly 8.2.0.Final for my server.
The solution I was looking for was like this, it belongs in the persistence.xml properties section.
<property name="javax.persistence.sql-load-script-source" value="META-INF/sql/data.sql" />
Database Schema Creation This link is useful for such techniques.
You could write a class extends from ServletContextListener which calls your method from the contextInitialized() method. You attach the listener to your webapp in web.xml, e.g.
<listener>
<listener-class>com.packages.Listener</listener-class>
</listener>
ServletListener code:
package com.packages;
public class Listener implements javax.servlet.ServletContextListener {
#Override
public void contextInitialized(ServletContext context) {
...
}
}
You can use Spring JDBC DataSource initializer feature or Instead of configuring DataSourceInitializer, you can use spring’s custom element jdbc:initialize-database element where jdbcnamespace xmlns:jdbc is set to http://www.springframework.org/schema/jdbc. You just need to point attribute data-source to the DataSource bean and configure the scripts using the child element jdbc:script and location attribute. For example, we can achieve the same result using the below configuration:
<jdbc:initialize-database data-source="dataSource" enabled="true">
<jdbc:script location="classpath:db-schema.sql" />
<jdbc:script location="classpath:db-load-data.sql" />
</jdbc:initialize-database>
At the very least you could use a servlet ContextListener to populate the database upon context start.
http://docs.oracle.com/javaee/7/api/javax/servlet/ServletContextListener.html
I've done such a trick for prototype applications in the past; just make sure to check if data doesn't already exist to prevent populating the database with duplicate data upon redeployments.
A rough example:
#WebListener
public class MyContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce){
// create manually, inject, whatever you're using
EntityManager em = ...;
Number cnt = (Number) em.createQuery("select count(d) from Data d").getSingleResult();
if(cnt.intValue() == 0){
insertFixtureData(em);
}
}
public void contextDestroyed(ServletContextEvent sce){
}
private void insertFixtureData(EntityManager em){
// insert data
}
}

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) {

joinTransaction has been called on a resource-local EntityManager in JBoss

I have earlier worked with application-managed RESOURCE-LOCAL transaction but now I want to use container-managed JTA transaction. Everything seems to be ok while I am using #Stateless but as soon as I use #Stateful I get an exception as below
javax.ejb.EJBException: javax.persistence.TransactionRequiredException: joinTransaction has been called on a resource-local EntityManager which is unable to register for a JTA transaction.
I am using JBoss eap 6.2 with eclipselink2.5 and Java8 and Oracle.Here are my codes
#Stateful
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class LoginDetailService {
#PersistenceContext(unitName="OracleDB", type=PersistenceContextType.EXTENDED)
protected EntityManager em;
public void addLoginDetails(String email, String pwd){
LoginDetail ld = new LoginDetail(email,pwd);
em.persist(ld);
}
#Remove
public void finished(){}
}
My Servlet code
#WebServlet("/signup")
public class SignUpServlet extends HttpServlet {
#EJB LoginDetailService bean;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String email = "EMAIL",
pwd = "PASSWORD";
bean.addLoginDetails(email, pwd); //exception occurs here
response.getWriter().println("Successful");
}
}
And my persistence.xml file
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="OracleDB" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>java:jboss/jdbc/OracleDB</jta-data-source>
<class>com.entity.Student</class>
<class>com.entity.LoginDetail</class>
<properties>
<property name="eclipselink.logging.level" value="FINEST"/>
</properties>
</persistence-unit>
</persistence>
Plz hekp and guide me where I am going wrong. Thanks
Finally after working a lot, I found the problem. Actually there was no issue with my code, it was because of the JBoss server. I tested the same application with Glassfish4 and it worked perfectly.
REASON
The annotation #EJB has no effect in JBoss. Though you will see that a JNDI binding has occurred with the bean but when you will try tp persist, it wont work.
SOLUTION
To make it work on JBoss instead of #EJB, you will have to do a JNDI lookup and carry out the transaction. But the lookup for some reason failed on my desktop but worked fine on laptop may be due to some weird server configuration.
Another and better solution which I feel is to use another server like Glassfish or WebLogic where #EJB works fine and not a single bit of extra coding.

JPA 2 (Hibernate) persistence context per conversation - closed connection

I'm trying to implement a entitymanager-per-conversation pattern on a stateful proprietary web framework with JBoss 4.3.0 and Hibernate 4.3.5. In short, the goal is:
First HTTP request loads entity A with lazy-loading properties from the database
In second request, the lazy-loading properties of entity A are accessible without e.g. creating a new EntityManager and calling e.g. entityManager.merge(entityA).
Entitymanager-per-conversation seems like the perfect choice. Here's my attempt:
public class EntityManagerHolder {
private static ThreadLocal<EntityManager> entityManager = new ThreadLocal<EntityManager>();
private static EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myPersistence");
private static ConnectionProvider connectionProvider = new MyConnectionProvider();
public static synchronized EntityManager getEntityManager() {
createEntityManagerIfNeeded();
return entityManager.get();
}
public static synchronized void createEntityManagerIfNeeded() {
if (entityManager.get() == null) {
// Start the conversation
EntityManager newEntityManager = entityManagerFactory.createEntityManager();
entityManager.set(newEntityManager);
newEntityManager.getTransaction().begin();
} else {
// Entitymanager is alive but may have lost its connection
EntityManager existingEntityManager = entityManager.get();
SessionImpl session = existingEntityManager.unwrap(SessionImpl.class);
try {
if (session.connection() == null || session.connection().isClosed()) {
session.reconnect(connectionProvider.getConnection());
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
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="myEntityManagerFactory">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<!-- Scan for annotated classes and Hibernate mapping XML files from this JAR -->
<property name="hibernate.archive.autodetection" value="class, hbm" />
<!-- Database connection settings: Use framework connections for database connectivity -->
<property name="hibernate.connection.provider_class" value="foo.bar.MyConnectionProvider"/>
</properties>
</persistence-unit>
</persistence>
When a new HTTP request arrives via the framework, I call EntityManagerHolder.createEntityManagerIfNeeded(). On the second HTTP request, the JDBC connection of the EntityManager has closed and the attempt to revive it via session.reconnect() leads to an exception:
java.lang.IllegalStateException: cannot manually reconnect unless Connection was originally supplied
org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.manualReconnect(LogicalConnectionImpl.java:296)
org.hibernate.internal.SessionImpl.reconnect(SessionImpl.java:478)
I realize I'm probably doing things in a very backwards way, but it would be nice to understand how entitymanager-per-conversation should be implemented. I've found the filter-based Hibernate-specific sample implementation of this pattern, but haven't managed to bend it to my needs yet.
Turns out JBoss was closing the connections. Disabling JBoss from closing JDBC connections would have resolved the issue. However, we wanted to avoid keeping a large number of JDBC connections open for long periods of time.
Best solution found so far is to revive the JDBC connection of the EntityManager, provided that the old connection is closed. I wrote a rough implementation:
EntityManagerFactoryAdapter - Used to reconnect an EntityManager to a new JDBC connection
EntityManagerHolder - Keeps one EntityManager per thread.
At the start of each HTTP request, we invoke EntityManagerHolder.initializeEntityManager(freshJDBCConnectionFromFramework). When the state is removed from the server, we invoke EntityManagerHolder.closeEntityManager(). Persistence.xml no longer has the hibernate.connection.provider_class - we're passing in connections manually.
I'm posting this just in case someone encounters a similar issue. This solution is very unorthodox, I'm hoping to replace it with a better one later.

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!

Categories