In java EE 6: When could I change properties on EntityManager? - jpa

I want to use proxy authentication to an Oracle Express database in a simple web app with java EE 6 on Glassfish. Eclipselink 2.3.0 doc here says:
If a JEE and JTA managed EntityManager is used, specifying a proxy user/password can be more difficult, as the EntityManager and JDBC connection is not under the applications control. The persistence unit properties can still be specified on the EntityManager. As long as this is done before the EntityManager has established a database connection, this will still work.
My code is as below, but I guess the database connection is already established when the #Postconstruct init() method is called, since the last property is not changed from default true to false.
Also, I get ORA-00942: table or view does not exist from the save() method. The user pool in the jdbc connection pool defined in glassfish-resources.xml has not acces to the tables, as has proxy user user_a.
#Stateless
public class Boundary {
#PersistenceContext EntityManager em;
#PostConstruct
private void init() {
em.setProperty("eclipselink.oracle.proxy-type", OracleConnection.PROXYTYPE_USER_NAME);
em.setProperty(OracleConnection.PROXY_USER_NAME, "pool[user_a]");
em.setProperty(OracleConnection.PROXY_USER_PASSWORD, "pool");
em.setProperty(OracleConnection.PROXY_ROLES, "pool_user");
em.setProperty("eclipselink.jdbc.exclusive-connection.mode", "Always");
em.setProperty("eclipselink.jdbc.exclusive-connection.is-lazy", "false");
}
public void save() {
em.merge(new AnEntity());
}
}
I have not much experience here, but it would be really useful if proxy authentication could be made that simple, so I spent some time trying.
In a JavaEE managed context, is it possible to set properties on an EntityManager before it gets connected?
My persistence.xml:
<?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="ProxyUserPU" transaction-type="JTA">
<jta-data-source>SecondTry</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<properties>
<property name="eclipselink.target-database" value="Oracle"/>
<property name="eclipselink.jdbc.exclusive-connection.is-lazy" value="true"/>
</properties>
</persistence-unit>
</persistence>

I don't think PostConstruct is the correct place for this.
A new EntityManager is bound to the persistence context on every transaction boundary, so you need to set these property at the start of every transactional SessionBean method. You could probably also use SessionEvents in EclipseLink to configure the properties.
If you properties are fixed, you could also put them in your persistence.xml.
See,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/Auditing#Use_Oracle_proxy_authentication_to_allow_a_shared_connection_pool_and_a_user_context

Related

JPA Exception : No externally managed transaction is currently active for this thread

Exception is thrown when trying to Insert/Update/Delete with executeUpdate(). Select query works fine.I have tried all the suggestions from previous similar error mentioned in stack-overflow. Appreciate any guidance.
Environment : Websphere Liberty : 17.0.0.2, Eclipselink 2.6.4, JPA 2.1
Features enabled on Liberty server
<featureManager>
<feature>adminCenter-1.0</feature>
<feature>beanValidation-1.1</feature>
<feature>cdi-1.2</feature>
<feature>concurrent-1.0</feature>
<feature>ejbLite-3.2</feature>
<feature>el-3.0</feature>
<feature>jsf-2.2</feature>
<feature>jsp-2.3</feature>
<feature>localConnector-1.0</feature>
<feature>servlet-3.1</feature>
<feature>jpa-2.1</feature>
<!--The following features are available in Liberty base and above. -->
<feature>jaxb-2.2</feature>
</featureManager>
Peristence.xml
<?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="BlueeCron" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/BlueeUPMDataSource</jta-data-source>
<mapping-file>META-INF/queries.xml</mapping-file>
<class>com.bcbsnc.providers.models.BlueEReqst</class>
<class>com.bcbsnc.providers.models.BlueERespn</class>
<properties>
<property name="eclipselink.logging.level" value="ALL" />
<property name="eclipselink.logging.level.sql" value="FINE" />
<property name="eclipselink.logging.parameters" value="true" />
</properties>
</persistence-unit>
#Stateless
#Repository("emJPADao")
public class JPADao {
EntityManager entityManager = Persistence.createEntityManagerFactory("BlueeCron").createEntityManager();
public Integer purgeBxTables() {
Integer rowsDeleted = 0;
try {
Integer noOfDays = Integer.parseInt(this.getConfigurationData("PurgeBXTablesPeriod"));
rowsDeleted = entityManager.createNamedQuery("PURGE_BX_TABLES").setParameter("noOfDays", getTimeStamp(noOfDays, false)).executeUpdate();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(entityManager.isOpen())
entityManager.close();
}
}
}
Logs at server startup
Launching defaultServer (WebSphere Application Server 17.0.0.2/wlp-1.0.17.cl170220170523-1818) on IBM J9 VM, version pwa6480sr4fp5-20170421_01 (SR4 FP5) (en_US)
[AUDIT ] CWWKF0012I: The server installed the following features: [jsp-2.3, ejbLite-3.2, servlet-3.1, jsf-2.2, beanValidation-1.1, ssl-1.0, jndi-1.0, jca-1.7, jdbc-4.2, localConnector-1.0, appSecurity-2.0, jaxrs-2.0, restConnector-1.0, el-3.0, jaxrsClient-2.0, concurrent-1.0, wmqJmsClient-2.0, jaxb-2.2, json-1.0, jpaContainer-2.1, adminCenter-1.0, cdi-1.2, distributedMap-1.0, jpa-2.1].
[AUDIT ] CWWKF0011I: The server defaultServer is ready to run a smarter planet.
[EL Info]: server: 2017-10-19 10:23:13.215--ServerSession(1864654006)--Detected server platform: org.eclipse.persistence.platform.server.was.WebSphere_Liberty_Platform.
S
Exception :
[err] javax.persistence.TransactionRequiredException:
Exception Description: No externally managed transaction is currently active for this thread
[err] at org.eclipse.persistence.internal.jpa.transaction.JTATransactionWrapper.throwCheckTransactionFailedException(JTATransactionWrapper.java:94)
[err] at org.eclipse.persistence.internal.jpa.transaction.JTATransactionWrapper.checkForTransaction(JTATransactionWrapper.java:54)
[err] at org.eclipse.persistence.internal.jpa.EntityManagerImpl.checkForTransaction(EntityManagerImpl.java:2054)
[err] at org.eclipse.persistence.internal.jpa.QueryImpl.executeUpdate(QueryImpl.java:291)
[err] at com.bcbsnc.providers.dao.JPADao.purgeBxTables(JPADao.java:49)
The executeUpdate() method requires for the EntityManager to be enlisted with a transaction - a global transaction in this case since you have defined a JTA-type persistence unit. You have chosen to use JPA's JSE bootstrapping approach (using Persistence.createEntityManagerFactory() instead of injection via #PersistenceContext or #PersistenceUnit) -- while I don't endorse using the JSE bootstrapping method in an EE application, it's not dis-allowed by the spec.
However, I believe the problem you are hitting is the fact that what you have effectively here is an application-managed persistence context, and thus your application is responsible for its enlistment with the global transaction (which would have been begun automatically by the EJB container when purgeBxTables() was called, as I do not see any annotations declaring it as a bean-managed-transaction session bean) which requires calling EntityMangager.joinTransaction().
An application-managed EntityManager will only join the global transaction automatically when the EntityManager is first created. Which is not the case for your application since the EntityManager is created when the bean class is constructed. Otherwise, the joinTransaction() method invocation is required in order for an EntityManager to join a new transaction.
Your application will need to call em.joinTransaction() before you call executeUpdate().
Using a container managed persistence context (using #PersistenceContext to inject an EntityManager) would have had the EntityManager automatically join the global transaction (unless you override the default Transaction SynchronizationType to UNSYNCHRONIZED.)

Multiple persistence units in Wildfly?

Is it possible to have two persistence units in a Wildfly (9.0.2) application?
I get "WFLYJPA0061: Persistence unitName was not specified and there are 2 persistence unit definitions in application deployment deployment "jasper-web.war". Either change the application deployment to have only one persistence unit definition or specify the unitName for each reference to a persistence unit."
I have unitName specified in the #PeristenceContext annotations. I read somewhere I could disable
<!--
<subsystem xmlns="urn:jboss:domain:jpa:1.1">
<jpa default-datasource="" default-extended-persistence-inheritance="DEEP"/>
</subsystem>
-->
in standalone.xml. This removed the error message, but also disabled injection of entityManagers (null pointer referencing them in code)
I have tried to split the persistence units over two different ejb-jars, each with their own persistence.xml, but as they're still included in the same war, Wildfly still complains.
The the two persistence units are used with hibernate, one with a postgresql database and one with a ucanaccess driver for ms access. They both work separately.
here an example of what works in our wildfly 8.x/9.x ejb app:
First of all define all the classes for each persistence-unit in the persistence.xml, unlisted classes can be turned off to disable autodiscovery.
persistence.xml
<?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="primary">
<jta-data-source>java:jboss/datasources/primary_ds</jta-data-source>
<class>whatever.primary.model.SomeEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties> ... </properties>
</persistence-unit>
<persistence-unit name="secondary">
<jta-data-source>java:jboss/datasources/secondary_ds</jta-data-source>
<class>whatever.secondary.model.AnotherEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties> ... </properties>
</persistence-unit>
</persistence>
If you use JBoss Developer Studio ignore the warning (it is only an eclipse flaw):
Multiple persistence units defined - only the first persistence unit will be recognized
Resources.java
package whatever.util;
import javax.annotation.Resource;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.sql.DataSource;
public class Resources {
#Produces
#PersistenceContext(unitName = "primary")
private EntityManager emPrimary;
#Produces
#PersistenceContext(unitName = "secondary")
private EntityManager emSecondary;
#Produces
#Resource(lookup = "java:jboss/datasources/primary_ds")
private DataSource dsPrimary;
#Produces
#Resource(lookup = "java:jboss/datasources/secondary_ds")
private DataSource dsSecodnary;
}
Dao primary example
package whatever.dao;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
#Stateless
public class DaoPrimaryExample {
#PersistenceContext(unitName = "primary")
private EntityManager em;
public void create(SomeEntity entity) {
em.persist(entity);
}
}
Dao secondary example
package whatever.dao;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
#Stateless
public class DaoSecondaryExample {
#PersistenceContext(unitName = "secondary")
private EntityManager em;
public void create(AnotherEntity entity) {
em.persist(entity);
}
}
IMPORTANT: If you plan to use booth persistence units in same transaction than XA datasources should be used.
Adding this option for a persitence unit in the persistence.xml fixed the issue for me:
<property name="wildfly.jpa.default-unit" value="true"/>
As John Ament pointed out the error message actually indicates an injection point without unitName (that I had forgotten about in my source...) As soon as I got rid of that, everything worked as it should. I also got a bit confused googling this problem, when I actually found some old issues in jboss AS where this actually seems to have been a problem, once.

In JBoss/WildFly should I enable JTA on data source to use with JPA?

In JBoss/WildFly, when configuring a data source, there is a JTA option, which is disabled by default:
<datasource jta="false" jndi-name="java:/wt/testds" pool-name="testds" enabled="true" use-ccm="false">
...
</datasource>
Now I want to associate this data source with JPA using JTA transaction type:
<?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="test" transaction-type="JTA">
<jta-data-source>java:/wt/testds</jta-data-source>
</persistence-unit>
</persistence>
Do I also need to enable JTA on the data source?
Yes, of course you need to enable JTA on a datasource if you want to have jta transactions!
Your XML/JBoss/Wildfly config file will look like this:
<datasource jta="true" ...
In our webapp persistence-unit, the datasource looks like this:
<jta-data-source>java:jboss/datasources/CoreDS</jta-data-source>
The transaction-type="JTA" isn't necessary, at least not in my setup (Wildfly 8.1).
In your Java code you can go like this to use transactions:
#TransactionManagement(TransactionManagementType.CONTAINER) // class level
public class ...
...
#PersistenceContext(unitName = "CoreJPA")
EntityManager em;
#Resource
private EJBContext ejbContext;
...
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) // method level
public void doSomething(...)
And if you need to rollback, you do this:
try {
...
} catch (Throwable t) {
log.error("Exception in create work order: " + t.getMessage());
ejbContext.setRollbackOnly();
throw t;
}
There are a lot of resources about this that can be found using Google.
I've just experienced a problem related to this issue.
I was running a container managed transaction involving approximately 20,000 inserts into a MySQL database.
The transaction failed randomly, sometimes after around 3,500 inserts, other times after around 6,000 inserts, etc.
After investigation I found that the JTA option on the WildFly datasource definition was set to false.
Changing this setting to true fixed the problem, so I would agree with #user3472929 that JTA should be set to true in the datasource definition unless you have some specific reason not to.
I think you should use jta. And if you set jta to false in the container configuration file, jta will be disabled for JPA, so the transaction-type for JPA will be "RESOURCE_LOCAL", which has some nasty side effect. By the way, jta is true in the container configuration file by default.

How to detach an entity (JPA 2.0/EclipseLink/JBoss)

I need to detach some entity objects from the database to make them unmanaged. I use EclipseLink persistence provider, which method EntityManager.detach() is exactly one I need. The problem is that JBoss throws at runtime following exception (when execution passes to detach()):
javax.ejb.EJBTransactionRolledbackException: Unexpected Error
java.lang.NoSuchMethodError: javax.persistence.EntityManager.detach(Ljava/lang/Object;)V
Other methods like persist, merge, find work fine. I tried Hibernate and know that its Session provides a special method evict(), which detaches entity, but EclipseLink has no such method.
Example of using detach():
#PersistenceContext(unitName="Course7-ejbPU")
protected EntityManager manager;
(...)
Query query;
List<Message> resultList;
query = manager.createNamedQuery("Message.getUserInputMessageList");
query.setParameter("login", login);
query.setMaxResults(5);
resultList = query.getResultList();
for (Message message : resultList)
if (message.getContent().length() > 50)
{
manager.detach(message);
message.setContent(message.getContent().substring(0, 50) + "...");
}
Persistence.xml:
<?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="Course7-ejbPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>java:/Course7ds</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.target-server" value="JBoss"/>
</properties>
</persistence-unit>
</persistence>
Library with provider data is included into ear archive.
EclipseLink version is 2.2.0 (tested with 2.3.2 - no difference), JBoss server version 5.1.0. Any suggestions will be appreciated.
This exception shows that you're not using JPA2, but JPA1. You should probably use a more recent version of JBoss, that ships with JPA2.
You compiled your code with JPA 2.0 classes, but you run it with JPA 1.0. This is why the JVM doesn't find the detach method.
In reaction to your comment: no, the detach method is not useless for JPA 1.0 user: it's just it has not been created yet. You can however erase all the L1 cache by calling clean() on the entitymanager, which will detach all your managed entities...
You can still be able to detach an entity by using persistence provider specific code.
It is not because the entity manager does not provide a function yet, that the jpa providers hasn't implemented it yet.
If you can couple a little bit your code to your jpa provider:
You can call the em.getDelegate() method that will return you an EclipseLink entity manager implementation (check in debug the returned value and cast it) which may perhaps give you the possibility to detach your entity.
The method may not be named detach() -> for Hibernate it's evict().

Persistence.createEntityManagerFactory() in Java EE ignores JTA source

I have a perfectly working application client deployed to a GlassFish v2 server inside an ear with some EJBs, Entities, etc. I'm using eclipselink.
Currently I have in my persistence.xml:
<persistence-unit name="mysource">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/mysource</jta-data-source>
<class>entities.one</class>
<class>entities.two</class>
...
<properties>
<property name="eclipselink.target-server" value="SunAS9"/>
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
And this works fine when I inject the EntityManager into the EJB:
#PersistenceContext(unitName="mysource")
private EntityManager em;
Now I have a requirement to dynamically switch persistence units/databases.
I figure I can get an EntityManager programatically:
em = Persistence.createEntityManagerFactory("mysource").createEntityManager();
but I get the following error:
Unable to acquire a connection from driver [null], user [null] and URL [null]
Even "overriding" javax.persistence.jtaDataSource" to "jdbc/mysource" in a Map and calling createEntityManagerFactory("mysource", map) doesn't make a difference.
What am I missing?
You are trying to circumvent the container with creating an entity manager programmatically and this means you'll most probably create a non-JTA data source (as it's outside the container, the transaction type should be RESOURCE_LOCAL), thus your original config is useless.
Try injecting an entity manager with a different unitName property or create a RESOURCE_LOCAL transaction type persistence unit.