Skip to content

Commit dc3329a

Browse files
committed
Allow library authors to extend the handshake metadata.
JAVA-2266
1 parent 1289597 commit dc3329a

27 files changed

+574
-109
lines changed

config/checkstyle-exclude.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444

4545
<suppress checks="ParameterNumber" files="Connection"/>
4646
<suppress checks="ParameterNumber" files="DefaultServer"/>
47+
<suppress checks="ParameterNumber" files="DefaultClusterFactory"/>
48+
<suppress checks="ParameterNumber" files="DefaultClusterableServerFactory"/>
4749

4850
<!--Legacy code that has not yet been cleaned-->
4951
<suppress checks="FinalClass" files="AggregationOptions"/>

driver-async/src/main/com/mongodb/async/client/MongoClients.java

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.mongodb.async.client;
1818

1919
import com.mongodb.ConnectionString;
20+
import com.mongodb.client.MongoDriverInformation;
2021
import com.mongodb.client.gridfs.codecs.GridFSFileCodecProvider;
2122
import com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider;
2223
import com.mongodb.connection.Cluster;
@@ -66,7 +67,7 @@ public static MongoClient create() {
6667
* @return the client
6768
*/
6869
public static MongoClient create(final MongoClientSettings settings) {
69-
return new MongoClientImpl(settings, createCluster(settings, getStreamFactory(settings)));
70+
return create(settings, null);
7071
}
7172

7273
/**
@@ -105,23 +106,52 @@ public static MongoClient create(final String connectionString) {
105106
* @see com.mongodb.connection.SocketSettings.Builder#applyConnectionString(ConnectionString)
106107
*/
107108
public static MongoClient create(final ConnectionString connectionString) {
109+
return create(connectionString, null);
110+
}
111+
112+
/**
113+
* Creates a new client with the given client settings.
114+
*
115+
* <p>Note: Intended for driver and library authors to associate extra driver metadata with the connections.</p>
116+
*
117+
* @param settings the settings
118+
* @param mongoDriverInformation any driver information to associate with the MongoClient
119+
* @return the client
120+
* @since 3.4
121+
*/
122+
public static MongoClient create(final MongoClientSettings settings, final MongoDriverInformation mongoDriverInformation) {
123+
return new MongoClientImpl(settings, createCluster(settings, mongoDriverInformation));
124+
}
125+
126+
/**
127+
* Create a new client with the given connection string.
128+
*
129+
* <p>Note: Intended for driver and library authors to associate extra driver metadata with the connections.</p>
130+
*
131+
* @param connectionString the settings
132+
* @param mongoDriverInformation any driver information to associate with the MongoClient
133+
* @return the client
134+
* @throws IllegalArgumentException if the connection string's stream type is not one of "netty" or "nio2"
135+
* @see MongoClients#create(ConnectionString)
136+
*/
137+
public static MongoClient create(final ConnectionString connectionString, final MongoDriverInformation mongoDriverInformation) {
108138
MongoClientSettings.Builder builder = MongoClientSettings.builder()
109-
.clusterSettings(ClusterSettings.builder()
110-
.applyConnectionString(connectionString)
111-
.build())
112-
.connectionPoolSettings(ConnectionPoolSettings.builder()
113-
.applyConnectionString(connectionString)
114-
.build())
115-
.serverSettings(ServerSettings.builder()
116-
.applyConnectionString(connectionString)
117-
.build())
118-
.credentialList(connectionString.getCredentialList())
119-
.sslSettings(SslSettings.builder()
120-
.applyConnectionString(connectionString)
121-
.build())
122-
.socketSettings(SocketSettings.builder()
123-
.applyConnectionString(connectionString)
124-
.build());
139+
.clusterSettings(ClusterSettings.builder()
140+
.applyConnectionString(connectionString)
141+
.build())
142+
.connectionPoolSettings(ConnectionPoolSettings.builder()
143+
.applyConnectionString(connectionString)
144+
.build())
145+
.serverSettings(ServerSettings.builder()
146+
.applyConnectionString(connectionString)
147+
.build())
148+
.credentialList(connectionString.getCredentialList())
149+
.sslSettings(SslSettings.builder()
150+
.applyConnectionString(connectionString)
151+
.build())
152+
.socketSettings(SocketSettings.builder()
153+
.applyConnectionString(connectionString)
154+
.build());
125155
if (connectionString.getStreamType() != null) {
126156
if (connectionString.getStreamType().toLowerCase().equals("netty")) {
127157
builder.streamFactoryFactory(NettyStreamFactoryFactory.builder().build());
@@ -141,7 +171,7 @@ public static MongoClient create(final ConnectionString connectionString) {
141171
if (connectionString.getApplicationName() != null) {
142172
builder.applicationName(connectionString.getApplicationName());
143173
}
144-
return create(builder.build());
174+
return create(builder.build(), mongoDriverInformation);
145175
}
146176

147177
/**
@@ -170,14 +200,15 @@ public static CodecRegistry getDefaultCodecRegistry() {
170200
new GeoJsonCodecProvider(),
171201
new GridFSFileCodecProvider()));
172202

173-
private static Cluster createCluster(final MongoClientSettings settings, final StreamFactory streamFactory) {
203+
private static Cluster createCluster(final MongoClientSettings settings, final MongoDriverInformation mongoDriverInformation) {
204+
StreamFactory streamFactory = getStreamFactory(settings);
174205
StreamFactory heartbeatStreamFactory = getHeartbeatStreamFactory(settings);
175206
return new DefaultClusterFactory().create(settings.getClusterSettings(), settings.getServerSettings(),
176207
settings.getConnectionPoolSettings(), streamFactory,
177208
heartbeatStreamFactory,
178209
settings.getCredentialList(), null, new JMXConnectionPoolListener(), null,
179210
createCommandListener(settings.getCommandListeners()),
180-
settings.getApplicationName());
211+
settings.getApplicationName(), mongoDriverInformation);
181212
}
182213

183214
private static StreamFactory getHeartbeatStreamFactory(final MongoClientSettings settings) {

driver-async/src/test/functional/com/mongodb/async/client/MongoClientsSpecification.groovy

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.mongodb.MongoCredential
2121
import com.mongodb.ReadConcern
2222
import com.mongodb.ServerAddress
2323
import com.mongodb.WriteConcern
24+
import com.mongodb.client.MongoDriverInformation
2425
import com.mongodb.connection.AsynchronousSocketChannelStreamFactoryFactory
2526
import com.mongodb.connection.netty.NettyStreamFactoryFactory
2627
import org.bson.Document
@@ -201,7 +202,8 @@ class MongoClientsSpecification extends FunctionalSpecification {
201202
def 'application name should appear in the system.profile collection'() {
202203
given:
203204
def appName = 'appName1'
204-
def client = MongoClients.create(getMongoClientBuilderFromConnectionString().applicationName(appName).build())
205+
def driverInfo = MongoDriverInformation.builder().driverName('myDriver').driverVersion('42').build()
206+
def client = MongoClients.create(getMongoClientBuilderFromConnectionString().applicationName(appName).build(), driverInfo)
205207
def database = client.getDatabase(getDatabaseName())
206208
def collection = database.getCollection(getCollectionName())
207209
run(database.&runCommand, new Document('profile', 2))
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*
2+
* Copyright 2016 MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb.client;
18+
19+
import com.mongodb.annotations.NotThreadSafe;
20+
21+
import java.util.ArrayList;
22+
import java.util.Collections;
23+
import java.util.List;
24+
25+
import static com.mongodb.assertions.Assertions.isTrue;
26+
import static com.mongodb.assertions.Assertions.notNull;
27+
28+
/**
29+
* The MongoDriverInformation class allows driver and library authors to add extra information about their library. This information is
30+
* then available in the MongoD/MongoS logs.
31+
*
32+
* <p>
33+
* The following metadata can be included when creating a {@code MongoClient}.
34+
* </p>
35+
* <ul>
36+
* <li>The driver name. Eg: {@code mongo-scala-driver}</li>
37+
* <li>The driver version. Eg: {@code 1.2.0}</li>
38+
* <li>Extra platform information. Eg: {@code Scala 2.11}</li>
39+
* </ul>
40+
* <p>
41+
* Note: Library authors are responsible for accepting {@code MongoDriverInformation} from external libraries using their library.
42+
* Also all the meta data is limited to 512 bytes and any excess data will be truncated.
43+
* </p>
44+
*
45+
* @since 3.4
46+
* @mongodb.server.release 3.4
47+
*/
48+
public final class MongoDriverInformation {
49+
private final List<String> driverNames;
50+
private final List<String> driverVersions;
51+
private final List<String> driverPlatforms;
52+
53+
/**
54+
* Convenience method to create a Builder.
55+
*
56+
* @return a builder
57+
*/
58+
public static Builder builder() {
59+
return new Builder();
60+
}
61+
62+
/**
63+
* Convenience method to create a Builder.
64+
*
65+
* @param mongoDriverInformation the mongoDriverInformation to extend
66+
* @return a builder
67+
*/
68+
public static Builder builder(final MongoDriverInformation mongoDriverInformation) {
69+
return new Builder(mongoDriverInformation);
70+
}
71+
72+
/**
73+
* Returns the driverNames
74+
*
75+
* @return the driverNames
76+
*/
77+
public List<String> getDriverNames() {
78+
return driverNames;
79+
}
80+
81+
/**
82+
* Returns the driverVersions
83+
*
84+
* @return the driverVersions
85+
*/
86+
public List<String> getDriverVersions() {
87+
return driverVersions;
88+
}
89+
90+
/**
91+
* Returns the driverPlatforms
92+
*
93+
* @return the driverPlatforms
94+
*/
95+
public List<String> getDriverPlatforms() {
96+
return driverPlatforms;
97+
}
98+
99+
/**
100+
*
101+
*/
102+
@NotThreadSafe
103+
public static final class Builder {
104+
private final MongoDriverInformation driverInformation;
105+
private String driverName;
106+
private String driverVersion;
107+
private String driverPlatform;
108+
109+
/**
110+
* Sets the name
111+
*
112+
* @param driverName the name
113+
* @return this
114+
*/
115+
public Builder driverName(final String driverName) {
116+
this.driverName = notNull("driverName", driverName);
117+
return this;
118+
}
119+
120+
/**
121+
* Sets the version
122+
*
123+
* <p>
124+
* Note: You must also set a driver name if setting a driver version.
125+
* </p>
126+
*
127+
* @param driverVersion the version
128+
* @return this
129+
*/
130+
public Builder driverVersion(final String driverVersion) {
131+
this.driverVersion = notNull("driverVersion", driverVersion);
132+
return this;
133+
}
134+
135+
/**
136+
* Sets the platform
137+
*
138+
* @param driverPlatform the platform
139+
* @return this
140+
*/
141+
public Builder driverPlatform(final String driverPlatform) {
142+
this.driverPlatform = notNull("driverPlatform", driverPlatform);
143+
return this;
144+
}
145+
146+
/**
147+
* @return the driver information
148+
*/
149+
public MongoDriverInformation build() {
150+
isTrue("You must also set the driver name when setting the driver version", !(driverName == null && driverVersion != null));
151+
152+
List<String> names = prependToList(driverInformation.getDriverNames(), driverName);
153+
List<String> versions = prependToList(driverInformation.getDriverVersions(), driverVersion);
154+
List<String> platforms = prependToList(driverInformation.getDriverPlatforms(), driverPlatform);
155+
return new MongoDriverInformation(names, versions, platforms);
156+
}
157+
158+
private List<String> prependToList(final List<String> stringList, final String value) {
159+
if (value == null) {
160+
return stringList;
161+
} else {
162+
ArrayList<String> newList = new ArrayList<String>();
163+
newList.add(value);
164+
newList.addAll(stringList);
165+
return Collections.unmodifiableList(newList);
166+
}
167+
}
168+
169+
private Builder() {
170+
List<String> immutableEmptyList = Collections.unmodifiableList(Collections.<String>emptyList());
171+
driverInformation = new MongoDriverInformation(immutableEmptyList, immutableEmptyList, immutableEmptyList);
172+
}
173+
174+
private Builder(final MongoDriverInformation driverInformation) {
175+
this.driverInformation = notNull("driverInformation", driverInformation);
176+
}
177+
}
178+
179+
private MongoDriverInformation(final List<String> driverNames, final List<String> driverVersions, final List<String> driverPlatforms) {
180+
this.driverNames = driverNames;
181+
this.driverVersions = driverVersions;
182+
this.driverPlatforms = driverPlatforms;
183+
}
184+
}

0 commit comments

Comments
 (0)