Skip to content

Commit dee6397

Browse files
committed
JAVA-806: Add an implemenation of a JNDI ObjectFactory for MongoClient instances
Addresses JAVA-2309
1 parent dc3329a commit dee6397

File tree

5 files changed

+208
-0
lines changed

5 files changed

+208
-0
lines changed

config/codenarc/codenarc.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
<rule-config name='NoDef'>
2424
<property name='doNotApplyToFilesMatching' value='.*Specification.groovy'/>
2525
</rule-config>
26+
<rule-config name='HashtableIsObsolete'>
27+
<property name='doNotApplyToFileNames' value='MongoClientFactorySpecification.groovy'/>
28+
</rule-config>
2629
</ruleset-ref>
2730
<ruleset-ref path='rulesets/design.xml'>
2831
<rule-config name='BuilderMethodWithSideEffects'>
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
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+
18+
package com.mongodb.client.jndi;
19+
20+
import com.mongodb.MongoClient;
21+
import com.mongodb.MongoClientURI;
22+
import com.mongodb.MongoException;
23+
import com.mongodb.diagnostics.logging.Logger;
24+
import com.mongodb.diagnostics.logging.Loggers;
25+
26+
import javax.naming.Context;
27+
import javax.naming.Name;
28+
import javax.naming.RefAddr;
29+
import javax.naming.Reference;
30+
import javax.naming.spi.ObjectFactory;
31+
import java.util.Enumeration;
32+
import java.util.Hashtable;
33+
34+
import static java.lang.String.format;
35+
36+
/**
37+
* An ObjectFactory for MongoClient instances.
38+
*
39+
* @since 3.3
40+
*/
41+
public class MongoClientFactory implements ObjectFactory {
42+
43+
private static final Logger LOGGER = Loggers.getLogger("client.jndi");
44+
45+
private static final String CONNECTION_STRING = "connectionString";
46+
47+
/**
48+
* This implementation will create instances of {@link MongoClient} based on a connection string conforming to the format specified in
49+
* {@link MongoClientURI}.
50+
* <p>The connection string is specified in one of two ways:</p>
51+
* <ul>
52+
* <li>As the {@code String} value of a property in the {@code environment} parameter with a key of {@code "connectionString"}</li>
53+
* <li>As the {@code String} value of a {@link RefAddr} with type {@code "connectionString"} in an {@code obj} parameter
54+
* of type {@link Reference}</li>
55+
* </ul>
56+
*
57+
* Specification of the connection string in the {@code environment} parameter takes precedence over specification in the {@code obj}
58+
* parameter. The {@code name} and {@code nameCtx} parameters are ignored.
59+
*
60+
* If a non-empty connection string is not specified in either of these two ways, a {@link MongoException} is thrown.
61+
* @return an instance of {@link MongoClient} based on the specified connection string
62+
* @throws MongoException
63+
*
64+
* Note: Not all options that can be specified via {@link com.mongodb.MongoClientOptions} can be specified via the connection string.
65+
*/
66+
@Override
67+
public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx, final Hashtable<?, ?> environment)
68+
throws Exception {
69+
70+
// Some app servers, e.g. Wildfly, use the environment to pass location information to an ObjectFactory
71+
String connectionString = null;
72+
73+
if (environment.get(CONNECTION_STRING) instanceof String) {
74+
connectionString = (String) environment.get(CONNECTION_STRING);
75+
}
76+
77+
if (connectionString == null || connectionString.isEmpty()) {
78+
LOGGER.debug(format("No '%s' property in environment. Casting 'obj' to java.naming.Reference to look for a "
79+
+ "javax.naming.RefAddr with type equal to '%s'", CONNECTION_STRING, CONNECTION_STRING));
80+
81+
// Some app servers, e.g. Tomcat, pass obj as an instance of javax.naming.Reference and pass location information in a
82+
// javax.naming.RefAddr
83+
if (obj instanceof Reference) {
84+
Enumeration<RefAddr> props = ((Reference) obj).getAll();
85+
86+
while (props.hasMoreElements()) {
87+
RefAddr addr = props.nextElement();
88+
if (addr != null) {
89+
if (CONNECTION_STRING.equals(addr.getType())) {
90+
if (addr.getContent() instanceof String) {
91+
connectionString = (String) addr.getContent();
92+
break;
93+
}
94+
}
95+
}
96+
}
97+
}
98+
}
99+
100+
if (connectionString == null || connectionString.isEmpty()) {
101+
throw new MongoException(format("Could not locate '%s' in either environment or obj", CONNECTION_STRING));
102+
}
103+
104+
MongoClientURI uri = new MongoClientURI(connectionString);
105+
106+
return new MongoClient(uri);
107+
}
108+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
18+
/**
19+
* This package contains a JNDI ObjectFactory implementation.
20+
*
21+
* @since 3.4
22+
*/
23+
package com.mongodb.client.jndi;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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+
18+
package com.mongodb.client.jndi
19+
20+
import com.mongodb.FunctionalSpecification
21+
import com.mongodb.MongoClient
22+
import com.mongodb.MongoException
23+
24+
import javax.naming.Reference
25+
import javax.naming.StringRefAddr
26+
27+
import static com.mongodb.Fixture.mongoClientURIString
28+
29+
class MongoClientFactorySpecification extends FunctionalSpecification {
30+
def mongoClientFactory = new MongoClientFactory()
31+
32+
def 'should create MongoClient from environment'() {
33+
given:
34+
def environment = new Hashtable<String, String>()
35+
environment.put('connectionString', mongoClientURIString)
36+
37+
when:
38+
MongoClient client = mongoClientFactory.getObjectInstance(null, null, null, environment)
39+
40+
then:
41+
client != null
42+
43+
cleanup:
44+
client?.close()
45+
}
46+
47+
def 'should create MongoClient from obj that is of type Reference'() {
48+
given:
49+
def environment = new Hashtable<String, String>()
50+
def reference = new Reference(null, new StringRefAddr('connectionString', getMongoClientURIString()))
51+
52+
when:
53+
MongoClient client = mongoClientFactory.getObjectInstance(reference, null, null, environment)
54+
55+
then:
56+
client != null
57+
58+
cleanup:
59+
client?.close()
60+
}
61+
62+
def 'should throw if no connection string is provided'() {
63+
given:
64+
def environment = new Hashtable<String, String>()
65+
66+
when:
67+
mongoClientFactory.getObjectInstance(null, null, null, environment)
68+
69+
then:
70+
thrown(MongoException)
71+
}
72+
}
73+

mongo-java-driver/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ jar {
5252
'javax.crypto.*',
5353
'javax.crypto.spec.*',
5454
'javax.management.*',
55+
'javax.naming.spi.*',
5556
'javax.net.*',
5657
'javax.net.ssl.*',
5758
'javax.security.sasl.*',

0 commit comments

Comments
 (0)