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

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"/>

Related

Cannot get openjpa tools to run from the command line

What I did:
download and extract the latest openjpa release (3.0.0)
download the mariadb jdbc driver jar and copy it to the same directory where openjpa-all-3.0.0.jar is located
inside the same directory, create a subdirectory META_INF and a file META-INF/persistence.xml with the following contents:
<?xml version="1.0"?>
<persistence version="1.0">
<persistence-unit name="openjpa">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<properties>
<property name="openjpa.ConnectionURL" value="jdbc:mariadb://localhost:3306/databasename"/>
<property name="openjpa.ConnectionDriverName" value="org.mariadb.jdbc.Driver"/>
<property name="openjpa.ConnectionUserName" value="dbuser"/>
<property name="openjpa.ConnectionPassword" value="dbpassword"/>
<property name="openjpa.DynamicEnhancementAgent" value="false"/>
<property name="openjpa.RuntimeUnenhancedClasses" value="supported"/>
<property name="openjpa.Log" value="SQL=TRACE"/>
<property name="openjpa.ConnectionFactoryProperties" value="PrettyPrint=true, PrettyPrintLineLength=120, PrintParameters=true, MaxActive=10, MaxIdle=5, MinIdle=2, MaxWait=60000"/>
</properties>
</persistence-unit>
create an empty directory src as a sub-directory of where the openjpa and mariadb driver jars are
ran the following command:
java -cp ./:openjpa-all-3.0.0.jar:mariadb-java-client-2.4.0.jar:openjpa-all-3.0.0.jar org.apache.openjpa.jdbc.meta.ReverseMappingTool -pkg some.package -d ./src
Instead of getting any kind of output, or an error related to generation, I get:
8 INFO [main] openjpa.Tool - The reverse mapping tool will run on the database. The tool is gathering schema information; this process may take some time. Enable the org.apache.openjpa.jdbc.Schema logging category to see messages about schema data.
Exception in thread "main" <openjpa-3.0.0-r422266:1833209 fatal user error> org.apache.openjpa.util.UserException: The persistence provider is attempting to use properties in the persistence.xml file to resolve the data source. A Java Database Connectivity (JDBC) driver or data source class name must be specified in the openjpa.ConnectionDriverName or javax.persistence.jdbc.driver property. The following properties are available in the configuration: "org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl#f248234b".
at org.apache.openjpa.jdbc.schema.DataSourceFactory.newDataSource(DataSourceFactory.java:71)
at org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl.createConnectionFactory(JDBCConfigurationImpl.java:850)
at org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl.getConnectionFactory(JDBCConfigurationImpl.java:733)
at org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl.getDataSource(JDBCConfigurationImpl.java:879)
at org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl.getDataSource2(JDBCConfigurationImpl.java:921)
at org.apache.openjpa.jdbc.schema.SchemaGenerator.<init>(SchemaGenerator.java:86)
at org.apache.openjpa.jdbc.meta.ReverseMappingTool.run(ReverseMappingTool.java:2027)
at org.apache.openjpa.jdbc.meta.ReverseMappingTool.run(ReverseMappingTool.java:2005)
at org.apache.openjpa.jdbc.meta.ReverseMappingTool.run(ReverseMappingTool.java:1882)
at org.apache.openjpa.jdbc.meta.ReverseMappingTool$1.run(ReverseMappingTool.java:1863)
at org.apache.openjpa.lib.conf.Configurations.launchRunnable(Configurations.java:762)
at org.apache.openjpa.lib.conf.Configurations.runAgainstAllAnchors(Configurations.java:747)
at org.apache.openjpa.jdbc.meta.ReverseMappingTool.main(ReverseMappingTool.java:1858)
What am I doing wrong?
I tried variations of this, by adding -p persistence.xml#openjpa, -p #openjpa and -connectionDriverName org.mariadb.jdbc.Driver to the command line, but it made no difference.

Table not found with H2

My Java EE application cannot find tables. I am using WildFly (as the application server) and H2 (as the DB, in the embedded mode).
The error is:
org.h2.jdbc.JdbcSQLException: Table "MY_TABLE" not found
Look at my table creation:
create table "MY_TABLE" (
-- ...
);
See how my entity is defined:
#Entity
#Table(name = "MY_TABLE")
public class MyTable {
// ...
}
This is how I call JPA (this causes the exception):
#PersistenceContext
private EntityManager entityManager;
// ...
entityManager.find(MyTable.class, 1);
My persistence.xml is:
<persistence-unit name="myapp" transaction-type="JTA">
<jta-data-source>java:jboss/datasources/myappDS</jta-data-source>
</persistence-unit>
And the standalone.xml in my WildFly:
<datasource jndi-name="java:jboss/datasources/myappDS" pool-name="myappDS" enabled="true" use-java-context="true">
<connection-url>jdbc:h2:~/myapp;SCHEMA=PUBLIC</connection-url>
<driver>h2</driver>
</datasource>
<drivers>
<driver name="h2" module="com.h2database.h2">
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
</drivers>
Everything looks good so why the exception? Do I need to flush something? Or set schema somewhere?
If I configure another datasource (having the same DB structure) in WildFly (for example Postgres), everything works fine. That would mean that the datasource configuration is the place causing the error.
(Yes, I am totally sure the DB is not empty and the connection URL is correct as I have tried it from an SQL client.)
Are you running the application as a different user than you are testing to connect with? In that case the the ~ in the connection path will resolve to different home folders, and thus different databases.
Otherwise I would suggest connecting with the Shell in the h2 jar file and run show tables to verify that the table exists and with the correct casing. Start the shell by running:
java -cp h2*.jar org.h2.tools.Shell
Where do you store your script for the table creation? Is it in classpath of the application?
In my test setup I let hibernate generate the tables on startup (and dropping it on shutdown) and using an import.sql script for the test-data generation, which is in the folder src/main/resources.
<persistence-unit name="myapp" transaction-type="JTA">
<jta-data-source>java:jboss/datasources/myappDS</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
</properties>
</persistence-unit>

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

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.

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

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>