/*
* ModeShape (http://www.modeshape.org)
*
* 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 org.modeshape.common.naming;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.spi.InitialContextFactory;
import org.modeshape.common.SystemFailureException;
/**
* An {@link InitialContextFactory} that provides a singleton {@link Context JNDI naming context}. Because it is a singleton, it
* is useful in unit tests that {@link Context#lookup(String) looks up} objects where it can be used within service registration
* logic while also being easily accessible in the test case itself.
* <p>
* For example, the following code sample shows how this InitialContextFactory implementation can be specified via the standard "
* <code>{@link Context#INITIAL_CONTEXT_FACTORY java.naming.factory.initial}</code>" property:
*
* <pre>
* Hashtable<String, Object> jndiContext = new Hashtable<String, Object>();
* jndiContext.put("java.naming.factory.initial", "org.modeshape.common.naming.SingleonInitialContextFactory");
* jndiContext.put("java.naming.provider.url", "localhost");
* InitialContext initialContext = new InitialContext(jndiContext);
* </pre>
*
* while the following sample shows how the same {@link Context} instance will be subsequently returned from accessed within other
* code (e.g., a test case):
*
* <pre>
* Context context = SingletoneInitialContextFactory.create();
* </pre>
*
* </p>
*
* @author Luca Stancapiano
* @author Randall Hauch
*/
public class SingletonInitialContextFactory implements InitialContextFactory {
private static SingletonInitialContext SINGLETON;
public SingletonInitialContextFactory() {
}
@Override
public Context getInitialContext( Hashtable<?, ?> environment ) {
return getInstance(environment);
}
/**
* Return the {@link Context} singleton instance. If no such context has been configured, this method will configured the
* singletone using the supplied environment.
*
* @param environment the environment for the naming context; may be null or empty
* @return the singleton context; never null
* @see #getInitialContext(Hashtable)
* @see #getInstance(Hashtable)
*/
public static synchronized Context getInstance( Hashtable<?, ?> environment ) {
if (SINGLETON == null) SINGLETON = new SingletonInitialContext(environment);
return SINGLETON;
}
/**
* Return the previously-configured {@link Context} singleton instance. If no such context has been configured, this method
* throws a {@link SystemFailureException}.
*
* @return the singleton context; never null
* @throws SystemFailureException if the singleton context has not yet been configured.
* @see #getInitialContext(Hashtable)
* @see #getInstance(Hashtable)
*/
public static synchronized Context getInstance() {
if (SINGLETON == null) {
throw new SystemFailureException();
}
return SINGLETON;
}
/**
* Set the {@link Context#INITIAL_CONTEXT_FACTORY} system property to the name of this context's
* {@link SingletonInitialContextFactory factory class}.
*/
public static void initialize() {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
System.setProperty("java.naming.factory.initial", SingletonInitialContextFactory.class.getName());
return null;
}
});
}
/**
* Release any existing singleton {@link Context naming context}. Any subsequent calls to {@link #getInstance(Hashtable)} or
* {@link #getInitialContext(Hashtable)} will return a new singleton instance.
*/
public static synchronized void tearDown() {
SINGLETON = null;
}
}