Search code examples
mongodbhibernatejakarta-eehibernate-ogmmongodb-atlas

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:[email protected]/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?


Solution

  • 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