Skip to content

Commit

Permalink
JAVA-806: Add an implemenation of a JNDI ObjectFactory for MongoClien…
Browse files Browse the repository at this point in the history
…t instances

   Addresses JAVA-2309
  • Loading branch information
jyemin committed Sep 14, 2016
1 parent dc3329a commit dee6397
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 0 deletions.
3 changes: 3 additions & 0 deletions config/codenarc/codenarc.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
<rule-config name='NoDef'>
<property name='doNotApplyToFilesMatching' value='.*Specification.groovy'/>
</rule-config>
<rule-config name='HashtableIsObsolete'>
<property name='doNotApplyToFileNames' value='MongoClientFactorySpecification.groovy'/>
</rule-config>
</ruleset-ref>
<ruleset-ref path='rulesets/design.xml'>
<rule-config name='BuilderMethodWithSideEffects'>
Expand Down
108 changes: 108 additions & 0 deletions driver/src/main/com/mongodb/client/jndi/MongoClientFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright 2016 MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.mongodb.client.jndi;

import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.MongoException;
import com.mongodb.diagnostics.logging.Logger;
import com.mongodb.diagnostics.logging.Loggers;

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;
import java.util.Enumeration;
import java.util.Hashtable;

import static java.lang.String.format;

/**
* An ObjectFactory for MongoClient instances.
*
* @since 3.3
*/
public class MongoClientFactory implements ObjectFactory {

private static final Logger LOGGER = Loggers.getLogger("client.jndi");

private static final String CONNECTION_STRING = "connectionString";

/**
* This implementation will create instances of {@link MongoClient} based on a connection string conforming to the format specified in
* {@link MongoClientURI}.
* <p>The connection string is specified in one of two ways:</p>
* <ul>
* <li>As the {@code String} value of a property in the {@code environment} parameter with a key of {@code "connectionString"}</li>
* <li>As the {@code String} value of a {@link RefAddr} with type {@code "connectionString"} in an {@code obj} parameter
* of type {@link Reference}</li>
* </ul>
*
* Specification of the connection string in the {@code environment} parameter takes precedence over specification in the {@code obj}
* parameter. The {@code name} and {@code nameCtx} parameters are ignored.
*
* If a non-empty connection string is not specified in either of these two ways, a {@link MongoException} is thrown.
* @return an instance of {@link MongoClient} based on the specified connection string
* @throws MongoException
*
* Note: Not all options that can be specified via {@link com.mongodb.MongoClientOptions} can be specified via the connection string.
*/
@Override
public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx, final Hashtable<?, ?> environment)
throws Exception {

// Some app servers, e.g. Wildfly, use the environment to pass location information to an ObjectFactory
String connectionString = null;

if (environment.get(CONNECTION_STRING) instanceof String) {
connectionString = (String) environment.get(CONNECTION_STRING);
}

if (connectionString == null || connectionString.isEmpty()) {
LOGGER.debug(format("No '%s' property in environment. Casting 'obj' to java.naming.Reference to look for a "
+ "javax.naming.RefAddr with type equal to '%s'", CONNECTION_STRING, CONNECTION_STRING));

// Some app servers, e.g. Tomcat, pass obj as an instance of javax.naming.Reference and pass location information in a
// javax.naming.RefAddr
if (obj instanceof Reference) {
Enumeration<RefAddr> props = ((Reference) obj).getAll();

while (props.hasMoreElements()) {
RefAddr addr = props.nextElement();
if (addr != null) {
if (CONNECTION_STRING.equals(addr.getType())) {
if (addr.getContent() instanceof String) {
connectionString = (String) addr.getContent();
break;
}
}
}
}
}
}

if (connectionString == null || connectionString.isEmpty()) {
throw new MongoException(format("Could not locate '%s' in either environment or obj", CONNECTION_STRING));
}

MongoClientURI uri = new MongoClientURI(connectionString);

return new MongoClient(uri);
}
}
23 changes: 23 additions & 0 deletions driver/src/main/com/mongodb/client/jndi/package-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2016 MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

/**
* This package contains a JNDI ObjectFactory implementation.
*
* @since 3.4
*/
package com.mongodb.client.jndi;
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 2016 MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.mongodb.client.jndi

import com.mongodb.FunctionalSpecification
import com.mongodb.MongoClient
import com.mongodb.MongoException

import javax.naming.Reference
import javax.naming.StringRefAddr

import static com.mongodb.Fixture.mongoClientURIString

class MongoClientFactorySpecification extends FunctionalSpecification {
def mongoClientFactory = new MongoClientFactory()

def 'should create MongoClient from environment'() {
given:
def environment = new Hashtable<String, String>()
environment.put('connectionString', mongoClientURIString)

when:
MongoClient client = mongoClientFactory.getObjectInstance(null, null, null, environment)

then:
client != null

cleanup:
client?.close()
}

def 'should create MongoClient from obj that is of type Reference'() {
given:
def environment = new Hashtable<String, String>()
def reference = new Reference(null, new StringRefAddr('connectionString', getMongoClientURIString()))

when:
MongoClient client = mongoClientFactory.getObjectInstance(reference, null, null, environment)

then:
client != null

cleanup:
client?.close()
}

def 'should throw if no connection string is provided'() {
given:
def environment = new Hashtable<String, String>()

when:
mongoClientFactory.getObjectInstance(null, null, null, environment)

then:
thrown(MongoException)
}
}

1 change: 1 addition & 0 deletions mongo-java-driver/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ jar {
'javax.crypto.*',
'javax.crypto.spec.*',
'javax.management.*',
'javax.naming.spi.*',
'javax.net.*',
'javax.net.ssl.*',
'javax.security.sasl.*',
Expand Down

0 comments on commit dee6397

Please sign in to comment.