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) {
Related
I am creating a Drools stateful session as described in the JBPM persistence documentation:
http://docs.jboss.org/jbpm/v5.1/javadocs/org/drools/persistence/jpa/JPAKnowledgeService.html
However, I came across the following exception
javax.persistence.TransactionRequiredException: joinTransaction has been called on a resource-local EntityManager which is unable to register for a JTA transaction.
My code is :
EntityManagerFactory emf = Persistence.createEntityManagerFactory("metadata.model");
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
env.set(EnvironmentName.TRANSACTION_MANAGER, TransactionManagerServices.getTransactionManager());
env.set(EnvironmentName.TRANSACTION, TransactionManagerServices.getTransactionManager());
KieServices ks = KieServices.Factory.get();
KieContainer kContainer = ks.getKieClasspathContainer();
KieBase kBase = kContainer.getKieBase();
StatefulKnowledgeSession kSession = JPAKnowledgeService.newStatefulKnowledgeSession(kBase, null, env);
The exception is thrown at the last line. Beforehand, I have bound the JDBC JTA Datasource as described in the aforementioned documentation.
PoolingDataSource ds = new PoolingDataSource();
ds.setUniqueName("jdbc/BitronixJTADataSource");
ds.setClassName("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource");
ds.setMaxPoolSize(3);
ds.setAllowLocalTransactions(true);
ds.getDriverProperties().put("user", "root");
ds.getDriverProperties().put("password", "****");
ds.getDriverProperties().put("URL", "jdbc:mysql://localhost:3306/metadatadb");
ds.init();
I am using the EclipseLink persistence provider alongside the MySQL JDBC driver.
Finally, I have made it work. The most important mistake I was making was that I was trying to use EclipseLink as JPA provider. This approach will not work, since besides the custom persistency classes, Drools uses two other persistency-annotated classes: org.drools.persistence.info.SessionInfo and org.drools.persistence.info.WorkItemInfo. These two contain Date fields which are not annotated with the JPA Temporal annotation. They appear to be tailored specifically for Hibernate.
Another important aspect that came to my attention is the need to add the following line after setting the environment variable:
env.set(EnvironmentName.OBJECT_MARSHALLING_STRATEGIES,
new ObjectMarshallingStrategy[] {
new JPAPlaceholderResolverStrategy(domainEnv),
new SerializablePlaceholderResolverStrategy(
ClassObjectMarshallingStrategyAcceptor.DEFAULT) });
This is performed in order to announce your intention to persist the current session state using JPA.
The exception I mentioned above was, however, due to the fact that EclipseLink was creating a "ResourceLocal" transaction wrapper even though JTA was explicitly specified in persistence.xml. This is due to the fact that there was no target-server property specified. Consequently, there were no external transaction controllers attached to the database session that was created and the wrapper that was provided simply couldn't support the joinTransaction operation. To work around this issue, add the following line to your persistence.xml file:
<property name="eclipselink.target-server" value="JBoss"/>
and before initializing the datasource, add:
Configuration conf = TransactionManagerServices.getConfiguration();
conf.setJndiUserTransactionName("java:/TransactionManager");
Of course, I am presuming that BTM is being used.
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
Helo masters, I have to create a JNDI Datasource dynamically, I tried to do it with a listener called SetupApplicationListener. Here is the beginning of WEB-LIB/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee">
<display-name>pri-web</display-name>
<!-- Listeners -->
<listener>
<listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
</listener>
<listener>
<listener-class>myapp.SetupApplicationListener</listener-class>
</listener>
The code of the listener:
public class SetupApplicationListener implements ServletContextListener {
public static Log LOG = null;
public void contextInitialized(ServletContextEvent ctx){
try {
createOracleDataSource();
.....
}
}
private void createOracleDataSource() throws SQLException, NamingException {
OracleDataSource ds = new OracleDataSource();
ds.setDriverType(...);
ds.setServerName(...);
ds.setPortNumber(...);
ds.setDatabaseName(...);
ds.setUser(...);
ds.setPassword(...);
new InitialContext().bind("java:comp/env/jdbc/myDS", ds);
}
.....
}
And there is the error:
[ERROR] 29/01/2013 09:44:50,517 (SetupApplicationListener.java:86) -> Error
javax.naming.NamingException: Context is read only
at org.apache.naming.NamingContext.checkWritable(NamingContext.java:903)
at org.apache.naming.NamingContext.bind(NamingContext.java:831)
at org.apache.naming.NamingContext.bind(NamingContext.java:171)
at org.apache.naming.NamingContext.bind(NamingContext.java:187)
at org.apache.naming.SelectorContext.bind(SelectorContext.java:186)
at javax.naming.InitialContext.bind(InitialContext.java:359)
at myapp.SetupApplicationListener.createOracleDataSource(SetupApplicationListener.java:102)
Can I set the read-only properties of the Context to "true"? Thanks! :)
Tomcat 6.0
Oracle 11g
jdk1.5
EDIT: Don't need to be dynamically, i have to define a jndi datasource internally I can't modify the server files because it is a shared server. It must be jndi because other modules use it in that way, thanks.
If you need to create a datasource dynamically is there really any need for a JNDI lookup? JNDI is designed to make the connection external to the application, while in your scenario its tightly coupled to the application due to a legitimate requirement. Why not just use a JDBC connection?
You need to create a ServletContextListener and there you can make the InitialContext writable - it's not the way it should be done, but if you really need it, this is one way you can do it.
This also works with Java Melody!
protected void makeJNDIContextWritable(ServletContextEvent sce) {
try {
Class<?> contextAccessControllerClass = sce.getClass().getClassLoader().loadClass("org.apache.naming.ContextAccessController");
Field readOnlyContextsField = contextAccessControllerClass.getDeclaredField("readOnlyContexts");
readOnlyContextsField.setAccessible(true);
Hashtable readOnlyContexts = (Hashtable) readOnlyContextsField.get(null);
String context = null;
for (Object key : readOnlyContexts.keySet()) {
String keyString = key + "";
if (keyString.endsWith(sce.getServletContext().getContextPath())) {
context = keyString;
}
}
readOnlyContexts.remove(context);
} catch (Exception ex) {
ex.printStackTrace();
}
}
I haven't got this problem before since I usually defined JNDI in application server(tomcat, weblogic and etc). Just like what Kevin said, this is exactly what JNDI was designed for; separating datasource config from your source code and retrieving JNDI resources through lookup and inject;
Back to your question, I think tomcat has every strict rules on modifying JNDI at runtime. In another word, you cannot re-bind or remove jndi from Context. If you go through the tomcat specification you will probably see some thing about jndi lookup but no re-bind.
From section EE.5.3.4 of the EE 6 platform specification (JSR 316):
The container must ensure that the application component instances
have only read access to their naming context. The container must
throw the javax.naming.OperationNotSupportedException from all the
methods of the javax.naming.Context interface that modify the
environment naming context and its subcontexts.
Note that "their naming context" in this section is referring to java:comp.
I solved this problem when found that I was closing environmentContext object
For example:
Context context=new InitialContext();
Context environmentContext=(Context) context.lookup("java:comp/env");
And my code was:
environmentContext.close();
After removing close function from environmentContext problem was solded for me;
I also had this problem, but being new to Tomee, I didn't know that there is a simple solution. When I deployed my web app to the webapps folder, the app worked fine, but when I deployed it to a service folder, I got the same abort. The problem was that the folder name did not match the war name (minus the .war). Once I fixed that, the app worked fine. Make sure the war name, folder name and service name are identical. This problem produces several different errors, including Context is read only and Error merging Java EE JNDI entries.
I solved this issue by setting useNaming="false" in my context.xml.
From the documentation:
useNaming : Set to true (the default) to have Catalina enable a JNDI InitialContext for this web application that is compatible with Java2 Enterprise Edition (J2EE) platform conventions.
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!
I have DataSource which is configured on Tomcat 6 in context.xml as MyDataSource.
And I'm fetching it the following way:
DataSource dataSource;
try {
dataSource = (DataSource) new InitialContext().lookup("java:comp/env/MyDataSource");
} catch (NamingException e) {
throw new DaoConfigurationException(
"DataSource '" + url + "' is missing in JNDI.", e);
}
Everything works fine. Now I'm exporting this code to Jboss AP 6. and I configured my dataSource and its connection pool as local-tx dataSource under the same name.
When I'm executing the code above, I'm getting NamingException exception. after some investigation I've found that correct way to call my DataSource under Jboss is
dataSource = (DataSource) new InitialContext().lookup("java:/MyDataSource");
Can anybody explain me why should I omit "comp/env" in my JNDI path under Jboss?
The portable approach for defining data sources is to use a resource reference. Resource references enable you to define the JNDI name for your data source, relative to your application naming context (java:comp/env), and then map that logical reference to the physical resource defined in the application server, whose JNDI name is proprietary to the application server vendor. This approach enables your code and assembly to be portable to any compliant application server.
Step 1: Declare and Lookup Resource Reference
Option 1
This can be done by declaring a resource-ref in your web deployment descriptor (WEB-INF/web.xml):
<resource-ref>
<description>My Data Source.</description>
<res-ref-name>jdbc/MyDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Within your code, you can then lookup this resource using the JNDI name java:comp/env/jdbc/MyDataSource:
dataSource = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/MyDataSource");
This JNDI name will not change regardless of the server where the application is deployed.
Option 2
Alternatively, starting in Java EE 5 (Servlet 2.5), this can be done even easier within your code using the #Resource annotation. This eliminates the need for configuring the resource-ref in your web deployment descriptor (web.xml) and prevents the need to perform an explicit JNDI lookup:
public class MyServlet extends HttpServlet {
#Resource(name = "jdbc/MyDataSource")
private DataSource dataSource;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// dataSource may be accessed directly here since the container will automatically
// inject an instance of the data source when the servlet is initialized
}
This approach has the same results as the previous option, but cuts down on the boilerplate code and configuration in your assembly.
Step 2: Map Resource Reference to Data Source
Then, you will need to use your application server's proprietary approach for mapping the resource reference to the physical data source that you created on the server, for example, using JBoss's custom deployment descriptors (WEB-INF/jboss-web.xml):
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<resource-ref>
<res-ref-name>jdbc/MyDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<jndi-name>java:/MyDataSource</jndi-name>
</resource-ref>
</jboss-web>
Or, for example, using Tomcat's context.xml:
<Resource name="jdbc/MyDataSource" . . . />
You can add to your data source definition the 'jndi-name' tag:
jndi-name - the JNDI name under which the DataSource should be bound.
You can find data source documentation on JBoss wiki: ConfigDataSources