ejb3-using-2-persistence-units-within-a-transaction - jpa

I am having problems connecting to 2 persistence units from within the same transaction using following tech stack,
WLS 10.3.x, Eclipselink 2.1, Oracle 11g JDBC driver, Informix 10 JDBC driver
Using inputs from this SO post I made the oracle datasource XA compliant and the Informix ds "Emulate 2-phase commit" and things started to work. However, now I am getting a strange problem.
I am using standalone java client to invoke my ejb 3 SLSB which in turn invokes the JPA entities. The problem I am facing is it works the first time, the second time it does not throw any exception but does not update the data in either databases and the 3rd time it throws an exception stating "Transaction has already been committed" as if the application server JTA transaction manager is holding on to the original transaction context. Please note these 3 invocations are separate and sequential wherein every invocations completes with the client exiting the client process. The problem is very consistent and happens in the exact same sequence every time I restart the app server.
Appreciate any input!

<persistence-unit name="TopLinkDB" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/oracleDS</jta-data-source>
<class>com.home.domain.Property</class>
<properties>
<property name="eclipselink.target-server" value="WebLogic_10" />
</properties>
</persistence-unit>
<persistence-unit name="TopLinkINFO" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/infoDS</jta-data-source>
<class>com.home.domain.GlobalNumber</class>
<properties>
<property name="eclipselink.target-server" value="WebLogic_10" />
</properties>
</persistence-unit>

Related

Usage of Hibernate OGM with cloud MongoDB Atlas M0 (Free Tier)

I am trying to use MongoDB Atlas M0 (Free Tier) for my JAVA EE application, now I am using:
Local MongoDB database (v4.0.4)
Hibernate Core "hibernate-core 5.3.6.Final"
Hibernate OGM "hibernate-ogm-mongodb 5.3.1.Final"
Java application server WildFly 15.0.0.Final.
With a local database a pair MongoDB and Hibernate OGM works like a charm, but when I tried to connect Hibernate with Mongo Atlas on free tier to test cloud database, I am was not able to have a working connection, because mongodb driver throws an exception com.mongodb.MongoSocketReadException: Prematurely reached end of stream
I will provide two versions of my persistence.xml, first is working fine with localhost and second is what I used to connect to cloud.
working localhost version:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence 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_2.xsd"
version="2.2">
<!-- ### MongoDB HIBERNATE OGM PERSISTENCE UNIT ### -->
<persistence-unit name="PersistenceUnitNoSQL" transaction-type="JTA">
<provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
<class>org.companyname.model.UserEntity</class>
<class>org.companyname.model.ItemEntity</class>
<properties>
<property name="hibernate.ogm.datastore.provider" value="mongodb"/>
<property name="hibernate.ogm.datastore.host" value="localhost:27017"/>
<property name="hibernate.ogm.datastore.database" value="databasename"/>
<property name="hibernate.ogm.datastore.create_database" value="true"/>
</properties>
</persistence-unit>
</persistence>
not working atlas cloud version:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence 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_2.xsd"
version="2.2">
<!-- ### MongoDB HIBERNATE OGM PERSISTENCE UNIT ### -->
<persistence-unit name="PersistenceUnitNoSQL" transaction-type="JTA">
<provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
<class>org.companyname.model.UserEntity</class>
<class>org.companyname.model.ItemEntity</class>
<properties>
<property name="hibernate.ogm.datastore.provider" value="mongodb"/>
<property name="hibernate.ogm.datastore.host" value="cluster0-clustername-shard-00-00-raa4n.mongodb.net:27017,cluster0-clustername-shard-00-01-raa4n.mongodb.net:27017,cluster0-clustername-shard-00-02-raa4n.mongodb.net:27017"/>
<property name="hibernate.ogm.datastore.database" value="databasename"/>
<property name="hibernate.ogm.datastore.create_database" value="true"/>
<property name="hibernate.ogm.datastore.username" value="atlas-user-name"/>
<property name="hibernate.ogm.datastore.password" value="atlas-user-password"/>
<property name="hibernate.ogm.mongodb.authentication_mechanism" value="SCRAM_SHA_1"/>
</properties>
</persistence-unit>
</persistence>
Like a host I used replica sets URIs from "standard connection string" from helping window in the Atlas account, because with "short SRV connection string" Hibernate throws org.hibernate.service.spi.ServiceException: OGM000072: Unable to configure datastore provider, so I think there is no support of this type of connection yet.
So with this last persistence.xml configuration I had following error:
20:02:01,094 INFO [org.mongodb.driver.cluster] (ServerService Thread Pool -- 78) Cluster description not yet available. Waiting for 30000 ms before timing out
20:02:01,175 INFO [org.mongodb.driver.cluster] (cluster-ClusterId{value='5c5497a97aea6111622c7540', description='null'}-cluster0-clustername-shard-00-02-raa4n.mongodb.net:27017)
Exception in monitor thread while connecting to server cluster0-clustername-shard-00-02-raa4n.mongodb.net:27017: com.mongodb.MongoSocketReadException: Prematurely reached end of stream
at com.mongodb.internal.connection.SocketStream.read(SocketStream.java:112)
at com.mongodb.internal.connection.InternalStreamConnection.receiveResponseBuffers(InternalStreamConnection.java:570)
at com.mongodb.internal.connection.InternalStreamConnection.receiveMessage(InternalStreamConnection.java:441)
at com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:295)
at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:255)
at com.mongodb.internal.connection.CommandHelper.sendAndReceive(CommandHelper.java:83)
at com.mongodb.internal.connection.CommandHelper.executeCommand(CommandHelper.java:33)
at com.mongodb.internal.connection.InternalStreamConnectionInitializer.initializeConnectionDescription(InternalStreamConnectionInitializer.java:106)
at com.mongodb.internal.connection.InternalStreamConnectionInitializer.initialize(InternalStreamConnectionInitializer.java:63)
at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:127)
at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:117)
at java.lang.Thread.run(Thread.java:748)
Hibernate tries to connect to each shard (00-00, 00-01, 00-02), but with all throws this exception.
What I tried to do to fix the problem:
using mongo-java-driver version 3.9.1 instead of Hibernate 3.6.3 built-in, but both drivers work with the same problem
my IP is added (my app is deployed from my laptop) to my atlas account IP Whitelist
I am able to connect fine to cluster from Mongo Shell and MongoDB Compass
I had a doubts about "hibernate.ogm.mongodb.authentication_mechanism", but "SCRAM_SHA_1" and "BEST" didn't worked for me
and finally I tried to make a connection to the cluster from Java directly (without Hibernate)
with
MongoClient mongoClient = MongoClients.create("mongodb+srv://atlas-user-name:atlas-user-password#cluster0-clustername-raa4n.mongodb.net/test?retryWrites=true");
or
MongoClient mongoClient = MongoClients.create("mongodb://atlas-user-name:atlas-user-password#cluster0-clustername-shard-00-00-raa4n.mongodb.net:27017,cluster0-clustername-shard-00-01-raa4n.mongodb.net:27017,cluster0-clustername-shard-00-02-raa4n.mongodb.net:27017/test?ssl=true&replicaSet=Cluster0-clustername-shard-0&authSource=admin&retryWrites=true");
and both cases worked fine, I was able to make a connection and to use the database without problems.
So my problem is why Hibernate throws this kind of exception?
It's possible that something is not right in the way Hibernate OGM creates the client.
I think the easier way to check this now for you is to override the MongoDBDatastoreProvider and provide an initialized MongoClient.
You can do this by extending MongoDBDatastoreProvider and overriding the method createMongoClient. Something like:
package org.myprojects;
import org.hibernate.ogm.datastore.mongodb.impl.MongoDBDatastoreProvider;
public class MYCustomMongoDBDatastoreProvider extends MongoDBDatastoreProvider {
#Override
protected MongoClient createMongoClient(MongoDBConfiguration config) {
return MongoClients.create(...);
}
}
then use the property OgmProperties.DATASTORE_PROVIDER to use your datastore provider:
hibernate.ogm.datastore.provider = org.myprojects.MYCustomMongoDBDatastoreProvider
In this example I'm setting it in the hibernate.properties file but you can set it where it makes more sense for your project.
EDIT: Additional explanations about the error.
I think the problems is that we are not using the factory to create the mongo client.
EDIT 2: The problem might be caused by a lack of support for SSL.
An issue has been created and contains more information
Got the same problem. I, additionally, enabled SSL and the connection was success:
<property name="hibernate.ogm.mongodb.driver.sslEnabled" value="true"/>

How to create tables from entity classes in JPA on server Startup?

I am supposed to check for existence of tables on server startup. If they did not exist I have to create them using entity classes. Is this even possible?
I am using Eclipse and my server is wildfly10. I am connecting to Oracle 11g xe but I don't think it is database that is causing issues
Anyway, this is what I have done so far
My 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="Lab5">
<properties>
<property name="javax.persistence.schema-generation.database.action" value="create"/>
</properties>
</persistence-unit>
</persistence>
Without above property my database query throws Exception. But what is really strange, is that with this property query returns empty list, but table does not exist in database.
Also, I noticed warning showing on server startup
HHH000431: Unable to determine H2 database version, certain features may not work
I tried various fixes for this warning found on stackoverflow and other sites but they did not help. I don't even know if this is related to my problem
JPA 2.1 made DDL generation a part of the specification. You can use the "javax.persistence.schema-generation.database.action" persistence property with a "create" value to have 2.1 providers create the database schema for you during deployment. JPA can be used to generate or even run custom scripts should you need to modify the table creation/tear down and population process.
The problem you are likely encountering is your persistence unit does not specify a datasource, leaving it up to the container to figure out which you want to connect to, and Wildfly must be defaulting to an H2 database. The tables will be setup in this database, but not the Oracle XE database you are expecting - which is why queries return no values and yet in your console, the tables don't even exist.
You need to setup a datasource to your database in the server, and then point your persistence unit to it using the <non-jta-data-source> or <jta-data-source>. Your persistence.xml is incomplete, so I would urge you to look at a demo persistence unit first.
This will likely depend on the implementation you're including with your project. Assuming you're using hibernate for persistence, you'll need to add the following:
...
<persistence-unit ...>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
...
<properties>
<property name = "hibernate.hbm2ddl.auto" value="create" />
...
</properties>
</persistence-unit>
Note that this will assume that your connection is formed with a user having the required privileges in the db for table creation. Take a look at the hibernate docs here.

How to create H2 table before adding records in JPA

My project involves JPA and following in my persistence.xml file
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="rest-jpa">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<jta-data-source>java:/comp/env/jdbc/restDB</jta-data-source>
<class>org.wso2.as.ee.Student</class>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
</properties>
</persistence-unit>
</persistence>
My H2 database is a in memory database.
It gives an error of table not found when I try to find for a record before adding one. I think that the table is created only when I add a record to the database. How can I create the table before any record is added?
You can make use of following JPA properties:
Generates and executes DROP TABLE and CREATE TABLE scripts everytime you run the application:
javax.persistence.schema-generation.database.action=drop-and-create
Loads some predefined data after creating database:
javax.persistence.sql-load-script-source="META-INF/loadData.ddl"
Creating schema should not be delayed until an entity is used (at least in case of using JPA), so you can use JPA properties which guarantee this behaviour. If you still find this behaviour occuring, you should make a bug ticket at your JPA provider bugtracker.

WebSphere Application Server V8.0.0.5 JPA Unable to persist

I have a code that works perfectly on WAS 7 but fail when i run it in WAS 8.0.0.5. I am using JPA 2.0 with openJPA as my provider. Calling persist on my em throws a nested exception. Has anyone ever managed to write a JPA program in WAS 8.0.0.5
here is the Exception
WTRN0074E: Exception caught from before_completion synchronization operation: org.apache.openjpa.persistence.PersistenceException: DB2 SQL Error: SQLCODE=-204, SQLSTATE=42704, SQLERRMC=.OPENJPA_SEQUENCE_TABLE, DRIVER=3.58.81 {prepstmnt -1559269434 SELECT SEQUENCE_VALUE FROM .OPENJPA_SEQUENCE_TABLE WHERE ID = ? FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=?]}
The SQLCODE=-204 points that something is missing. The log keeps printing THAKHANI.OPENJPA_SEQUENCE_TABLE which makes think that maybe the table is missing. You could also check to make sure the DB2 user that JPA is using has permissions to create tables and run SELECT statements on them.
I manage to resolve the problem by selecting Identity as my primary key generation mechanism when generating entities from tables. I also add the following in my persistence.xml.
<properties>
<!-- OpenJPA specific properties -->
<property name="openjpa.TransactionMode" value="managed"/>
<property name="openjpa.ConnectionFactoryMode" value="managed"/>
<property name="openjpa.jdbc.DBDictionary" value="db2"/>
<property name="openjpa.jdbc.Schema" value=<SchemaName>/>
</properties>

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.