Skip to content

Commit 66dcabe

Browse files
committed
Fix NullPointerException when using mongodb+srv scheme
JAVA-3167
1 parent d76c796 commit 66dcabe

File tree

5 files changed

+56
-17
lines changed

5 files changed

+56
-17
lines changed

driver-core/src/main/com/mongodb/internal/connection/AbstractMultiServerCluster.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333

3434
import java.util.ArrayList;
3535
import java.util.Collection;
36-
import java.util.Collections;
3736
import java.util.HashSet;
3837
import java.util.Iterator;
3938
import java.util.List;
@@ -91,6 +90,7 @@ MongoException getSrvResolutionException() {
9190
}
9291

9392
protected void initialize(final Collection<ServerAddress> serverAddresses) {
93+
ClusterDescription currentDescription = getCurrentDescription();
9494
ClusterDescription newDescription;
9595

9696
// synchronizing this code because addServer registers a callback which is re-entrant to this instance.
@@ -101,12 +101,7 @@ protected void initialize(final Collection<ServerAddress> serverAddresses) {
101101
}
102102
newDescription = updateDescription();
103103
}
104-
fireChangeEvent(new ClusterDescriptionChangedEvent(getClusterId(), newDescription, createInitialDescription()));
105-
}
106-
107-
private ClusterDescription createInitialDescription() {
108-
return new ClusterDescription(getSettings().getMode(), ClusterType.UNKNOWN, Collections.<ServerDescription>emptyList(),
109-
getSettings(), getServerFactory().getSettings());
104+
fireChangeEvent(new ClusterDescriptionChangedEvent(getClusterId(), newDescription, currentDescription));
110105
}
111106

112107
@Override

driver-core/src/main/com/mongodb/internal/connection/BaseCluster.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.bson.BsonTimestamp;
4343

4444
import java.util.ArrayList;
45+
import java.util.Collections;
4546
import java.util.Deque;
4647
import java.util.Iterator;
4748
import java.util.List;
@@ -86,6 +87,8 @@ abstract class BaseCluster implements Cluster {
8687
this.serverFactory = notNull("serverFactory", serverFactory);
8788
this.clusterListener = getClusterListener(settings);
8889
clusterListener.clusterOpening(new ClusterOpeningEvent(clusterId));
90+
description = new ClusterDescription(settings.getMode(), ClusterType.UNKNOWN, Collections.<ServerDescription>emptyList(),
91+
settings, serverFactory.getSettings());
8992
}
9093

9194
@Override

driver-core/src/main/com/mongodb/internal/connection/SingleServerCluster.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,12 @@ private void publishDescription(final ServerDescription serverDescription) {
103103
if (clusterType == ClusterType.UNKNOWN && serverDescription != null) {
104104
clusterType = serverDescription.getClusterType();
105105
}
106-
ClusterDescription oldDescription = getCurrentDescription();
106+
ClusterDescription currentDescription = getCurrentDescription();
107107
ClusterDescription description = new ClusterDescription(ClusterConnectionMode.SINGLE, clusterType,
108108
serverDescription == null ? Collections.<ServerDescription>emptyList() : singletonList(serverDescription), getSettings(),
109109
getServerFactory().getSettings());
110110

111111
updateDescription(description);
112-
fireChangeEvent(new ClusterDescriptionChangedEvent(getClusterId(), description,
113-
oldDescription == null ? getInitialDescription() : oldDescription));
114-
}
115-
116-
private ClusterDescription getInitialDescription() {
117-
return new ClusterDescription(getSettings().getMode(), getSettings().getRequiredClusterType(),
118-
Collections.<ServerDescription>emptyList(), getSettings(), getServerFactory().getSettings());
112+
fireChangeEvent(new ClusterDescriptionChangedEvent(getClusterId(), description, currentDescription));
119113
}
120114
}

driver-core/src/test/unit/com/mongodb/internal/connection/BaseClusterSpecification.groovy

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ import com.mongodb.MongoTimeoutException
2626
import com.mongodb.MongoWaitQueueFullException
2727
import com.mongodb.ReadPreference
2828
import com.mongodb.ServerAddress
29+
import com.mongodb.connection.ClusterDescription
2930
import com.mongodb.connection.ClusterId
31+
import com.mongodb.connection.ClusterType
3032
import com.mongodb.connection.Server
3133
import com.mongodb.connection.ServerConnectionState
3234
import com.mongodb.connection.ServerDescription
@@ -54,6 +56,41 @@ class BaseClusterSpecification extends Specification {
5456
private final List<ServerAddress> allServers = [firstServer, secondServer, thirdServer]
5557
private final TestClusterableServerFactory factory = new TestClusterableServerFactory()
5658

59+
def 'should have current description immediately after construction'() {
60+
given:
61+
def clusterSettings = builder().mode(MULTIPLE)
62+
.hosts([firstServer, secondServer, thirdServer])
63+
.serverSelectionTimeout(1, MILLISECONDS)
64+
.serverSelector(new ServerAddressSelector(firstServer))
65+
.build()
66+
def cluster = new BaseCluster(new ClusterId(), clusterSettings, factory) {
67+
@Override
68+
protected void connect() {
69+
}
70+
71+
@Override
72+
protected ClusterableServer getServer(final ServerAddress serverAddress) {
73+
throw new UnsupportedOperationException()
74+
}
75+
}
76+
77+
expect: 'the description is initialized after construction'
78+
cluster.getCurrentDescription() == new ClusterDescription(clusterSettings.getMode(), ClusterType.UNKNOWN, [], clusterSettings,
79+
factory.getSettings())
80+
81+
when: 'the description is accessed before initialization'
82+
cluster.getDescription()
83+
84+
then: 'a MongoTimeoutException is thrown'
85+
thrown(MongoTimeoutException)
86+
87+
when: 'a server is selected before initialization'
88+
cluster.selectServer { def clusterDescription -> [] }
89+
90+
then: 'a MongoTimeoutException is thrown'
91+
thrown(MongoTimeoutException)
92+
}
93+
5794
def 'should get cluster settings'() {
5895
given:
5996
def clusterSettings = builder().mode(MULTIPLE)

driver-core/src/test/unit/com/mongodb/internal/connection/DnsMultiServerClusterSpecification.groovy

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import com.mongodb.connection.ClusterSettings
2323
import com.mongodb.event.ClusterListener
2424
import spock.lang.Specification
2525

26+
import java.util.concurrent.TimeUnit
27+
2628
import static com.mongodb.connection.ClusterConnectionMode.MULTIPLE
2729
import static com.mongodb.connection.ClusterType.SHARDED
2830
import static com.mongodb.connection.ServerType.SHARD_ROUTER
@@ -61,6 +63,7 @@ class DnsMultiServerClusterSpecification extends Specification {
6163
def cluster = new DnsMultiServerCluster(new ClusterId(),
6264
ClusterSettings.builder()
6365
.addClusterListener(clusterListener)
66+
.serverSelectionTimeout(1, TimeUnit.MILLISECONDS)
6467
.srvHost(srvHost)
6568
.mode(MULTIPLE)
6669
.build(),
@@ -70,12 +73,19 @@ class DnsMultiServerClusterSpecification extends Specification {
7073
initializer != null
7174
1 * dnsSrvRecordMonitor.start()
7275

76+
when: 'the current description is accessed before initialization'
77+
def description = cluster.getCurrentDescription()
78+
79+
then: 'the description is not null'
80+
description != null
81+
7382
when: 'the listener is initialized with an exception'
7483
initializer.initialize(exception)
84+
description = cluster.getCurrentDescription()
7585

7686
then: 'the description includes the exception'
77-
cluster.getCurrentDescription().getServerDescriptions() == []
78-
cluster.getCurrentDescription().getSrvResolutionException() == exception
87+
description.getServerDescriptions() == []
88+
description.getSrvResolutionException() == exception
7989

8090
when: 'the listener is initialized with servers'
8191
initializer.initialize([firstServer, secondServer] as Set)

0 commit comments

Comments
 (0)