[JAVA-2469] Distinguish between error conditions when server selection fails Created: 13/Mar/17  Updated: 14/Mar/17  Resolved: 14/Mar/17

Status: Closed
Project: Java Driver
Component/s: Cluster Management
Affects Version/s: 3.2.1
Fix Version/s: None

Type: New Feature Priority: Major - P3
Reporter: Joshua Matsuoka Assignee: Unassigned
Resolution: Won't Fix Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Hi,

We have an application that uses Mongodb as a backend for storage. We create a MongoClient, get the required MongoDatabase, then test the connection by performing a count command. The problem we're having is if there is no server listening at the specified address, or authentication fails, BaseCluster.selectServer will throw a MongoTimeoutException. We want to distinguish between various error conditions so that the user can be given a meaningful hint as to what can be done, but it seems like the only way to do this would be to do some String matching on the exception message, which we'd like to avoid.

Would it be acceptable to pass the actual ClusterDescription object back with the exception, perhaps as part of a new type of exception (e.g. MongoClusterTimeoutException) so that we have access to the ServerDescriptions and the original exception that ocurred (e.g. MongoSecurityException in the case of failed authentication)?

If not, is there a better way to distinguish between error conditions without needing to do matching on the exception message?



 Comments   
Comment by Jeffrey Yemin [ 14/Mar/17 ]

Glad to hear it. Good luck!

Comment by Joshua Matsuoka [ 14/Mar/17 ]

Hi Jeff,

This should work. Thanks!

Comment by Jeffrey Yemin [ 13/Mar/17 ]

Another possibility is to register a ClusterListener:

import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.ServerAddress;
import com.mongodb.connection.ClusterDescription;
import com.mongodb.connection.ServerDescription;
import com.mongodb.event.ClusterClosedEvent;
import com.mongodb.event.ClusterDescriptionChangedEvent;
import com.mongodb.event.ClusterListener;
import com.mongodb.event.ClusterOpeningEvent;
 
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
 
public class JAVA2469 {
    public static void main(String[] args) throws InterruptedException {
        AwaitingClusterListener clusterListener = new AwaitingClusterListener(ReadPreference.primary());
        MongoClientOptions options = MongoClientOptions.builder()
                                             .addClusterListener(clusterListener)
                                             .build();
        MongoClient client = new MongoClient(new ServerAddress("localhost:27017"), options);
 
        // Wait for a server that satisfies the read preference to become available, or 5 seconds, whichever comes first
        if (!clusterListener.await(5, TimeUnit.SECONDS)) {
            for (ServerDescription cur : clusterListener.getMostRecentDescription().getServerDescriptions()) {
                // Check exceptions here: this check can be as involved as required by the application
                if (cur.getException() != null) {
                    System.out.println("Exception: " + cur.getException());
                    client.close();
                    System.exit(1);
                }
            }
        }
 
        System.out.println("Connected!");
        // proceed with normal application
    }
 
    private static class AwaitingClusterListener implements ClusterListener {
        private final CountDownLatch latch = new CountDownLatch(1);
        private final ReadPreference readPreference;
        private volatile ClusterDescription mostRecentDescription;
 
        private AwaitingClusterListener(final ReadPreference readPreference) {
            this.readPreference = readPreference;
        }
 
        public ClusterDescription getMostRecentDescription() {
            return mostRecentDescription;
        }
 
        @Override
        public void clusterDescriptionChanged(final ClusterDescriptionChangedEvent clusterDescriptionChangedEvent) {
            mostRecentDescription = clusterDescriptionChangedEvent.getNewDescription();
            if (clusterDescriptionChangedEvent.getNewDescription().hasReadableServer(readPreference)) {
                latch.countDown();
            }
        }
 
        public boolean await(final int timeout, final TimeUnit timeUnit) throws InterruptedException {
            return latch.await(timeout, timeUnit);
        }
 
        @Override
        public void clusterOpening(final ClusterOpeningEvent clusterOpeningEvent) {
        }
 
        @Override
        public void clusterClosed(final ClusterClosedEvent clusterClosedEvent) {
        }
    }
}

Generated at Thu Feb 08 08:57:18 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.