/* * Copyright 2004 Original mockejb authors. * Copyright 2007 Nuxeo SAS. * * This file is derived from mockejb-0.6-beta2 * * 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.nuxeo.common.jndi; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.naming.spi.InitialContextFactory; import javax.naming.spi.InitialContextFactoryBuilder; import javax.naming.spi.NamingManager; /** * Creates {@link NamingContext }. In case a delegate * environment was provided, obtains delegate InitialContext. * Delegate context is used by NamingContext for unresolved lookups. * * @author Alexander Ananiev * @author Dimitar Gospodinov */ public class NamingContextFactory implements InitialContextFactory { private static final Map<String, Object> savedSystemProps = new HashMap<String, Object>(); private static Hashtable<?, ?> delegateEnv; private static Context delegateContext; private static Context rootContext; /** * Singleton for initial context. * Instantiates and returns root/initial <code>NamingContext</code> object that * will be used as starting point for all naming operations. * <code>NamingContext</code> is then used by <code>javax.naming.InitialContext</code> object. * It also creates the delegate context if the delegate environment is set. NamingContextFactory * caches the delegate context once it's created. * @see javax.naming.spi.InitialContextFactory#getInitialContext(java.util.Hashtable) * @return <code>NamingContext</code> object */ public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException { if (delegateContext == null && delegateEnv != null) { delegateContext = new InitialContext(delegateEnv); } if (rootContext == null) { rootContext = new NamingContext(delegateContext); } return rootContext; } /** * Sets the environment of the delegate JNDI context. Normally, * this is the environment of the application server. * At the very minimum, the environment includes PROVIDER_URL and INITIAL_CONTEXT_FACTORY. * <code>NamingContext</code> first tries to look up the object in its local tree. * If the object is not found, it will look in the delegate context. * * @param env JNDI properties of the delegate environment */ public static void setDelegateEnvironment(Hashtable<?, ?> env) { delegateEnv = env; } /** * Sets the delegate context. Normally, * this is the initial context of the application server. * * <code>NamingContext</code> first tries to look up the object in its local tree. * If the object is not found, it will look in the delegate context. * * Example: * <code> * NamingContextFactory.setDelegateContext(new InitialContext()); * </code> * @param ctx delegate context */ public static void setDelegateContext(Context ctx) { delegateContext = ctx; } /** * Sets the <code>NamingContextFactory</code> as the initial context factory. * This helper method sets the <code>Context.INITIAL_CONTEXT_FACTORY</code> * and <code>Context.URL_PKG_PREFIXES</code> system properties. The second one is needed to * be able to handle java:comp context correctly. * The method also saves the current values of these properties so they can be * restored later on using <code>revertSetAsInitial</code>. * This method is normally called from <code>setUp</code> * <p> * You can also set these properties directly: * <pre> * <code> * java.naming.factory.initial=org.nuxeo.common.jndi.NamingContextFactory * java.naming.factory.url.pkgs=org.nuxeo.common.jndi * </code> * </pre> * * @throws NamingException */ public static void setAsInitial() { // Preserve current set system props String key = Context.INITIAL_CONTEXT_FACTORY; savedSystemProps.put(key, System.getProperty(key)); key = Context.URL_PKG_PREFIXES; savedSystemProps.put(key, System.getProperty(key)); System.setProperty(Context.INITIAL_CONTEXT_FACTORY, NamingContextFactory.class.getName()); System.setProperty(Context.URL_PKG_PREFIXES, "org.nuxeo.common.jndi"); } /** * Same as {@link #setAsInitial()} but it use strong types (avoiding reflection) * to install the naming context factory. * <p> * This is preferable in frameworks that doesn't work well * with the current thread context class loader like OSGi. * @throws NamingException */ public static void install() throws NamingException { InitialContextFactoryBuilder b = new InitialContextFactoryBuilder() { @Override public InitialContextFactory createInitialContextFactory( Hashtable<?, ?> environment) throws NamingException { NamingContextFactory factory = new NamingContextFactory(); return factory; } }; NamingManager.setInitialContextFactoryBuilder(b); } /** * Restores the properties changed by <code>setAsInitial()</code>. * This method should be called in <code>tearDown()</code> to clean up * all changes to the environment in case if the test is running in the app * server. * <p> * This method also cleans the initial context. */ public static void revertSetAsInitial() { for (Map.Entry<String, Object> entry : savedSystemProps.entrySet()) { restoreSystemProperty(entry.getKey(), (String) entry.getValue()); } rootContext = null; } private static void restoreSystemProperty(String key, String value) { if (value != null) { System.setProperty(key, value); } else { System.getProperties().remove(key); } } }