Browse Source
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@474 50f2f4bb-b051-0410-bef5-90022cba6387pull/1/head
3 changed files with 661 additions and 0 deletions
@ -0,0 +1,82 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2008 the original author or authors. |
||||||
|
* |
||||||
|
* 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.springframework.mock.jndi; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
|
||||||
|
import javax.naming.NamingException; |
||||||
|
|
||||||
|
import org.springframework.core.CollectionFactory; |
||||||
|
import org.springframework.jndi.JndiTemplate; |
||||||
|
|
||||||
|
/** |
||||||
|
* Simple extension of the JndiTemplate class that always returns |
||||||
|
* a given object. Very useful for testing. Effectively a mock object. |
||||||
|
* |
||||||
|
* @author Rod Johnson |
||||||
|
* @author Juergen Hoeller |
||||||
|
*/ |
||||||
|
public class ExpectedLookupTemplate extends JndiTemplate { |
||||||
|
|
||||||
|
private final Map<String, Object> jndiObjects = new ConcurrentHashMap<String, Object>(); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Construct a new JndiTemplate that will always return given objects |
||||||
|
* for given names. To be populated through <code>addObject</code> calls. |
||||||
|
* @see #addObject(String, Object) |
||||||
|
*/ |
||||||
|
public ExpectedLookupTemplate() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Construct a new JndiTemplate that will always return the |
||||||
|
* given object, but honour only requests for the given name. |
||||||
|
* @param name the name the client is expected to look up |
||||||
|
* @param object the object that will be returned |
||||||
|
*/ |
||||||
|
public ExpectedLookupTemplate(String name, Object object) { |
||||||
|
addObject(name, object); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Add the given object to the list of JNDI objects that this |
||||||
|
* template will expose. |
||||||
|
* @param name the name the client is expected to look up |
||||||
|
* @param object the object that will be returned |
||||||
|
*/ |
||||||
|
public void addObject(String name, Object object) { |
||||||
|
this.jndiObjects.put(name, object); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* If the name is the expected name specified in the constructor, |
||||||
|
* return the object provided in the constructor. If the name is |
||||||
|
* unexpected, a respective NamingException gets thrown. |
||||||
|
*/ |
||||||
|
public Object lookup(String name) throws NamingException { |
||||||
|
Object object = this.jndiObjects.get(name); |
||||||
|
if (object == null) { |
||||||
|
throw new NamingException("Unexpected JNDI name '" + name + "': expecting " + this.jndiObjects.keySet()); |
||||||
|
} |
||||||
|
return object; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,345 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2008 the original author or authors. |
||||||
|
* |
||||||
|
* 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.springframework.mock.jndi; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Hashtable; |
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.Map; |
||||||
|
import javax.naming.Binding; |
||||||
|
import javax.naming.Context; |
||||||
|
import javax.naming.Name; |
||||||
|
import javax.naming.NameClassPair; |
||||||
|
import javax.naming.NameNotFoundException; |
||||||
|
import javax.naming.NameParser; |
||||||
|
import javax.naming.NamingEnumeration; |
||||||
|
import javax.naming.NamingException; |
||||||
|
import javax.naming.OperationNotSupportedException; |
||||||
|
|
||||||
|
import org.apache.commons.logging.Log; |
||||||
|
import org.apache.commons.logging.LogFactory; |
||||||
|
|
||||||
|
import org.springframework.util.StringUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* Simple implementation of a JNDI naming context. |
||||||
|
* Only supports binding plain Objects to String names. |
||||||
|
* Mainly for test environments, but also usable for standalone applications. |
||||||
|
* |
||||||
|
* <p>This class is not intended for direct usage by applications, although it |
||||||
|
* can be used for example to override JndiTemplate's <code>createInitialContext</code> |
||||||
|
* method in unit tests. Typically, SimpleNamingContextBuilder will be used to |
||||||
|
* set up a JVM-level JNDI environment. |
||||||
|
* |
||||||
|
* @author Rod Johnson |
||||||
|
* @author Juergen Hoeller |
||||||
|
* @see org.springframework.mock.jndi.SimpleNamingContextBuilder |
||||||
|
* @see org.springframework.jndi.JndiTemplate#createInitialContext |
||||||
|
*/ |
||||||
|
public class SimpleNamingContext implements Context { |
||||||
|
|
||||||
|
private final Log logger = LogFactory.getLog(getClass()); |
||||||
|
|
||||||
|
private final String root; |
||||||
|
|
||||||
|
private final Hashtable<String, Object> boundObjects; |
||||||
|
|
||||||
|
private final Hashtable<String, Object> environment = new Hashtable<String, Object>(); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new naming context. |
||||||
|
*/ |
||||||
|
public SimpleNamingContext() { |
||||||
|
this(""); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new naming context with the given naming root. |
||||||
|
*/ |
||||||
|
public SimpleNamingContext(String root) { |
||||||
|
this.root = root; |
||||||
|
this.boundObjects = new Hashtable<String, Object>(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new naming context with the given naming root, |
||||||
|
* the given name/object map, and the JNDI environment entries. |
||||||
|
*/ |
||||||
|
public SimpleNamingContext(String root, Hashtable<String, Object> boundObjects, Hashtable<String, Object> env) { |
||||||
|
this.root = root; |
||||||
|
this.boundObjects = boundObjects; |
||||||
|
if (env != null) { |
||||||
|
this.environment.putAll(env); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Actual implementations of Context methods follow
|
||||||
|
|
||||||
|
public NamingEnumeration<NameClassPair> list(String root) throws NamingException { |
||||||
|
if (logger.isDebugEnabled()) { |
||||||
|
logger.debug("Listing name/class pairs under [" + root + "]"); |
||||||
|
} |
||||||
|
return new NameClassPairEnumeration(this, root); |
||||||
|
} |
||||||
|
|
||||||
|
public NamingEnumeration<Binding> listBindings(String root) throws NamingException { |
||||||
|
if (logger.isDebugEnabled()) { |
||||||
|
logger.debug("Listing bindings under [" + root + "]"); |
||||||
|
} |
||||||
|
return new BindingEnumeration(this, root); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Look up the object with the given name. |
||||||
|
* <p>Note: Not intended for direct use by applications. |
||||||
|
* Will be used by any standard InitialContext JNDI lookups. |
||||||
|
* @throws javax.naming.NameNotFoundException if the object could not be found |
||||||
|
*/ |
||||||
|
public Object lookup(String lookupName) throws NameNotFoundException { |
||||||
|
String name = this.root + lookupName; |
||||||
|
if (logger.isDebugEnabled()) { |
||||||
|
logger.debug("Static JNDI lookup: [" + name + "]"); |
||||||
|
} |
||||||
|
if ("".equals(name)) { |
||||||
|
return new SimpleNamingContext(this.root, this.boundObjects, this.environment); |
||||||
|
} |
||||||
|
Object found = this.boundObjects.get(name); |
||||||
|
if (found == null) { |
||||||
|
if (!name.endsWith("/")) { |
||||||
|
name = name + "/"; |
||||||
|
} |
||||||
|
for (String boundName : this.boundObjects.keySet()) { |
||||||
|
if (boundName.startsWith(name)) { |
||||||
|
return new SimpleNamingContext(name, this.boundObjects, this.environment); |
||||||
|
} |
||||||
|
} |
||||||
|
throw new NameNotFoundException( |
||||||
|
"Name [" + this.root + lookupName + "] not bound; " + this.boundObjects.size() + " bindings: [" + |
||||||
|
StringUtils.collectionToDelimitedString(this.boundObjects.keySet(), ",") + "]"); |
||||||
|
} |
||||||
|
return found; |
||||||
|
} |
||||||
|
|
||||||
|
public Object lookupLink(String name) throws NameNotFoundException { |
||||||
|
return lookup(name); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Bind the given object to the given name. |
||||||
|
* Note: Not intended for direct use by applications |
||||||
|
* if setting up a JVM-level JNDI environment. |
||||||
|
* Use SimpleNamingContextBuilder to set up JNDI bindings then. |
||||||
|
* @see org.springframework.mock.jndi.SimpleNamingContextBuilder#bind |
||||||
|
*/ |
||||||
|
public void bind(String name, Object obj) { |
||||||
|
if (logger.isInfoEnabled()) { |
||||||
|
logger.info("Static JNDI binding: [" + this.root + name + "] = [" + obj + "]"); |
||||||
|
} |
||||||
|
this.boundObjects.put(this.root + name, obj); |
||||||
|
} |
||||||
|
|
||||||
|
public void unbind(String name) { |
||||||
|
if (logger.isInfoEnabled()) { |
||||||
|
logger.info("Static JNDI remove: [" + this.root + name + "]"); |
||||||
|
} |
||||||
|
this.boundObjects.remove(this.root + name); |
||||||
|
} |
||||||
|
|
||||||
|
public void rebind(String name, Object obj) { |
||||||
|
bind(name, obj); |
||||||
|
} |
||||||
|
|
||||||
|
public void rename(String oldName, String newName) throws NameNotFoundException { |
||||||
|
Object obj = lookup(oldName); |
||||||
|
unbind(oldName); |
||||||
|
bind(newName, obj); |
||||||
|
} |
||||||
|
|
||||||
|
public Context createSubcontext(String name) { |
||||||
|
String subcontextName = this.root + name; |
||||||
|
if (!subcontextName.endsWith("/")) { |
||||||
|
subcontextName += "/"; |
||||||
|
} |
||||||
|
Context subcontext = new SimpleNamingContext(subcontextName, this.boundObjects, this.environment); |
||||||
|
bind(name, subcontext); |
||||||
|
return subcontext; |
||||||
|
} |
||||||
|
|
||||||
|
public void destroySubcontext(String name) { |
||||||
|
unbind(name); |
||||||
|
} |
||||||
|
|
||||||
|
public String composeName(String name, String prefix) { |
||||||
|
return prefix + name; |
||||||
|
} |
||||||
|
|
||||||
|
public Hashtable<String, Object> getEnvironment() { |
||||||
|
return this.environment; |
||||||
|
} |
||||||
|
|
||||||
|
public Object addToEnvironment(String propName, Object propVal) { |
||||||
|
return this.environment.put(propName, propVal); |
||||||
|
} |
||||||
|
|
||||||
|
public Object removeFromEnvironment(String propName) { |
||||||
|
return this.environment.remove(propName); |
||||||
|
} |
||||||
|
|
||||||
|
public void close() { |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Unsupported methods follow: no support for javax.naming.Name
|
||||||
|
|
||||||
|
public NamingEnumeration<NameClassPair> list(Name name) throws NamingException { |
||||||
|
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); |
||||||
|
} |
||||||
|
|
||||||
|
public NamingEnumeration<Binding> listBindings(Name name) throws NamingException { |
||||||
|
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); |
||||||
|
} |
||||||
|
|
||||||
|
public Object lookup(Name name) throws NamingException { |
||||||
|
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); |
||||||
|
} |
||||||
|
|
||||||
|
public Object lookupLink(Name name) throws NamingException { |
||||||
|
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); |
||||||
|
} |
||||||
|
|
||||||
|
public void bind(Name name, Object obj) throws NamingException { |
||||||
|
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); |
||||||
|
} |
||||||
|
|
||||||
|
public void unbind(Name name) throws NamingException { |
||||||
|
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); |
||||||
|
} |
||||||
|
|
||||||
|
public void rebind(Name name, Object obj) throws NamingException { |
||||||
|
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); |
||||||
|
} |
||||||
|
|
||||||
|
public void rename(Name oldName, Name newName) throws NamingException { |
||||||
|
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); |
||||||
|
} |
||||||
|
|
||||||
|
public Context createSubcontext(Name name) throws NamingException { |
||||||
|
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); |
||||||
|
} |
||||||
|
|
||||||
|
public void destroySubcontext(Name name) throws NamingException { |
||||||
|
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); |
||||||
|
} |
||||||
|
|
||||||
|
public String getNameInNamespace() throws NamingException { |
||||||
|
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); |
||||||
|
} |
||||||
|
|
||||||
|
public NameParser getNameParser(Name name) throws NamingException { |
||||||
|
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); |
||||||
|
} |
||||||
|
|
||||||
|
public NameParser getNameParser(String name) throws NamingException { |
||||||
|
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); |
||||||
|
} |
||||||
|
|
||||||
|
public Name composeName(Name name, Name prefix) throws NamingException { |
||||||
|
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private static abstract class AbstractNamingEnumeration<T> implements NamingEnumeration<T> { |
||||||
|
|
||||||
|
private Iterator<T> iterator; |
||||||
|
|
||||||
|
private AbstractNamingEnumeration(SimpleNamingContext context, String proot) throws NamingException { |
||||||
|
if (!"".equals(proot) && !proot.endsWith("/")) { |
||||||
|
proot = proot + "/"; |
||||||
|
} |
||||||
|
String root = context.root + proot; |
||||||
|
Map<String, T> contents = new HashMap<String, T>(); |
||||||
|
for (String boundName : context.boundObjects.keySet()) { |
||||||
|
if (boundName.startsWith(root)) { |
||||||
|
int startIndex = root.length(); |
||||||
|
int endIndex = boundName.indexOf('/', startIndex); |
||||||
|
String strippedName = |
||||||
|
(endIndex != -1 ? boundName.substring(startIndex, endIndex) : boundName.substring(startIndex)); |
||||||
|
if (!contents.containsKey(strippedName)) { |
||||||
|
try { |
||||||
|
contents.put(strippedName, createObject(strippedName, context.lookup(proot + strippedName))); |
||||||
|
} |
||||||
|
catch (NameNotFoundException ex) { |
||||||
|
// cannot happen
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (contents.size() == 0) { |
||||||
|
throw new NamingException("Invalid root: [" + context.root + proot + "]"); |
||||||
|
} |
||||||
|
this.iterator = contents.values().iterator(); |
||||||
|
} |
||||||
|
|
||||||
|
protected abstract T createObject(String strippedName, Object obj); |
||||||
|
|
||||||
|
public boolean hasMore() { |
||||||
|
return this.iterator.hasNext(); |
||||||
|
} |
||||||
|
|
||||||
|
public T next() { |
||||||
|
return this.iterator.next(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean hasMoreElements() { |
||||||
|
return this.iterator.hasNext(); |
||||||
|
} |
||||||
|
|
||||||
|
public T nextElement() { |
||||||
|
return this.iterator.next(); |
||||||
|
} |
||||||
|
|
||||||
|
public void close() { |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private static class NameClassPairEnumeration extends AbstractNamingEnumeration<NameClassPair> { |
||||||
|
|
||||||
|
private NameClassPairEnumeration(SimpleNamingContext context, String root) throws NamingException { |
||||||
|
super(context, root); |
||||||
|
} |
||||||
|
|
||||||
|
protected NameClassPair createObject(String strippedName, Object obj) { |
||||||
|
return new NameClassPair(strippedName, obj.getClass().getName()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private static class BindingEnumeration extends AbstractNamingEnumeration<Binding> { |
||||||
|
|
||||||
|
private BindingEnumeration(SimpleNamingContext context, String root) throws NamingException { |
||||||
|
super(context, root); |
||||||
|
} |
||||||
|
|
||||||
|
protected Binding createObject(String strippedName, Object obj) { |
||||||
|
return new Binding(strippedName, obj); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,234 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2008 the original author or authors. |
||||||
|
* |
||||||
|
* 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.springframework.mock.jndi; |
||||||
|
|
||||||
|
import java.util.Hashtable; |
||||||
|
|
||||||
|
import javax.naming.Context; |
||||||
|
import javax.naming.NamingException; |
||||||
|
import javax.naming.spi.InitialContextFactory; |
||||||
|
import javax.naming.spi.InitialContextFactoryBuilder; |
||||||
|
import javax.naming.spi.NamingManager; |
||||||
|
|
||||||
|
import org.apache.commons.logging.Log; |
||||||
|
import org.apache.commons.logging.LogFactory; |
||||||
|
|
||||||
|
import org.springframework.util.ClassUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* Simple implementation of a JNDI naming context builder. |
||||||
|
* |
||||||
|
* <p>Mainly targeted at test environments, where each test case can |
||||||
|
* configure JNDI appropriately, so that <code>new InitialContext()</code> |
||||||
|
* will expose the required objects. Also usable for standalone applications, |
||||||
|
* e.g. for binding a JDBC DataSource to a well-known JNDI location, to be |
||||||
|
* able to use traditional J2EE data access code outside of a J2EE container. |
||||||
|
* |
||||||
|
* <p>There are various choices for DataSource implementations: |
||||||
|
* <ul> |
||||||
|
* <li>SingleConnectionDataSource (using the same Connection for all getConnection calls); |
||||||
|
* <li>DriverManagerDataSource (creating a new Connection on each getConnection call); |
||||||
|
* <li>Apache's Jakarta Commons DBCP offers BasicDataSource (a real pool). |
||||||
|
* </ul> |
||||||
|
* |
||||||
|
* <p>Typical usage in bootstrap code: |
||||||
|
* |
||||||
|
* <pre class="code"> |
||||||
|
* SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); |
||||||
|
* DataSource ds = new DriverManagerDataSource(...); |
||||||
|
* builder.bind("java:comp/env/jdbc/myds", ds); |
||||||
|
* builder.activate();</pre> |
||||||
|
* |
||||||
|
* Note that it's impossible to activate multiple builders within the same JVM, |
||||||
|
* due to JNDI restrictions. Thus to configure a fresh builder repeatedly, use |
||||||
|
* the following code to get a reference to either an already activated builder |
||||||
|
* or a newly activated one: |
||||||
|
* |
||||||
|
* <pre class="code"> |
||||||
|
* SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder(); |
||||||
|
* DataSource ds = new DriverManagerDataSource(...); |
||||||
|
* builder.bind("java:comp/env/jdbc/myds", ds);</pre> |
||||||
|
* |
||||||
|
* Note that you <i>should not</i> call <code>activate()</code> on a builder from |
||||||
|
* this factory method, as there will already be an activated one in any case. |
||||||
|
* |
||||||
|
* <p>An instance of this class is only necessary at setup time. |
||||||
|
* An application does not need to keep a reference to it after activation. |
||||||
|
* |
||||||
|
* @author Juergen Hoeller |
||||||
|
* @author Rod Johnson |
||||||
|
* @see #emptyActivatedContextBuilder() |
||||||
|
* @see #bind(String, Object) |
||||||
|
* @see #activate() |
||||||
|
* @see org.springframework.mock.jndi.SimpleNamingContext |
||||||
|
* @see org.springframework.jdbc.datasource.SingleConnectionDataSource |
||||||
|
* @see org.springframework.jdbc.datasource.DriverManagerDataSource |
||||||
|
* @see org.apache.commons.dbcp.BasicDataSource |
||||||
|
*/ |
||||||
|
public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder { |
||||||
|
|
||||||
|
/** An instance of this class bound to JNDI */ |
||||||
|
private static volatile SimpleNamingContextBuilder activated; |
||||||
|
|
||||||
|
private static boolean initialized = false; |
||||||
|
|
||||||
|
private static final Object initializationLock = new Object(); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if a SimpleNamingContextBuilder is active. |
||||||
|
* @return the current SimpleNamingContextBuilder instance, |
||||||
|
* or <code>null</code> if none |
||||||
|
*/ |
||||||
|
public static SimpleNamingContextBuilder getCurrentContextBuilder() { |
||||||
|
return activated; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* If no SimpleNamingContextBuilder is already configuring JNDI, |
||||||
|
* create and activate one. Otherwise take the existing activate |
||||||
|
* SimpleNamingContextBuilder, clear it and return it. |
||||||
|
* <p>This is mainly intended for test suites that want to |
||||||
|
* reinitialize JNDI bindings from scratch repeatedly. |
||||||
|
* @return an empty SimpleNamingContextBuilder that can be used |
||||||
|
* to control JNDI bindings |
||||||
|
*/ |
||||||
|
public static SimpleNamingContextBuilder emptyActivatedContextBuilder() throws NamingException { |
||||||
|
if (activated != null) { |
||||||
|
// Clear already activated context builder.
|
||||||
|
activated.clear(); |
||||||
|
} |
||||||
|
else { |
||||||
|
// Create and activate new context builder.
|
||||||
|
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); |
||||||
|
// The activate() call will cause an assigment to the activated variable.
|
||||||
|
builder.activate(); |
||||||
|
} |
||||||
|
return activated; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private final Log logger = LogFactory.getLog(getClass()); |
||||||
|
|
||||||
|
private final Hashtable boundObjects = new Hashtable(); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Register the context builder by registering it with the JNDI NamingManager. |
||||||
|
* Note that once this has been done, <code>new InitialContext()</code> will always |
||||||
|
* return a context from this factory. Use the <code>emptyActivatedContextBuilder()</code> |
||||||
|
* static method to get an empty context (for example, in test methods). |
||||||
|
* @throws IllegalStateException if there's already a naming context builder |
||||||
|
* registered with the JNDI NamingManager |
||||||
|
*/ |
||||||
|
public void activate() throws IllegalStateException, NamingException { |
||||||
|
logger.info("Activating simple JNDI environment"); |
||||||
|
synchronized (initializationLock) { |
||||||
|
if (!initialized) { |
||||||
|
if (NamingManager.hasInitialContextFactoryBuilder()) { |
||||||
|
throw new IllegalStateException( |
||||||
|
"Cannot activate SimpleNamingContextBuilder: there is already a JNDI provider registered. " + |
||||||
|
"Note that JNDI is a JVM-wide service, shared at the JVM system class loader level, " + |
||||||
|
"with no reset option. As a consequence, a JNDI provider must only be registered once per JVM."); |
||||||
|
} |
||||||
|
NamingManager.setInitialContextFactoryBuilder(this); |
||||||
|
initialized = true; |
||||||
|
} |
||||||
|
} |
||||||
|
activated = this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Temporarily deactivate this context builder. It will remain registered with |
||||||
|
* the JNDI NamingManager but will delegate to the standard JNDI InitialContextFactory |
||||||
|
* (if configured) instead of exposing its own bound objects. |
||||||
|
* <p>Call <code>activate()</code> again in order to expose this contexz builder's own |
||||||
|
* bound objects again. Such activate/deactivate sequences can be applied any number |
||||||
|
* of times (e.g. within a larger integration test suite running in the same VM). |
||||||
|
* @see #activate() |
||||||
|
*/ |
||||||
|
public void deactivate() { |
||||||
|
logger.info("Deactivating simple JNDI environment"); |
||||||
|
activated = null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Clear all bindings in this context builder, while keeping it active. |
||||||
|
*/ |
||||||
|
public void clear() { |
||||||
|
this.boundObjects.clear(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Bind the given object under the given name, for all naming contexts |
||||||
|
* that this context builder will generate. |
||||||
|
* @param name the JNDI name of the object (e.g. "java:comp/env/jdbc/myds") |
||||||
|
* @param obj the object to bind (e.g. a DataSource implementation) |
||||||
|
*/ |
||||||
|
public void bind(String name, Object obj) { |
||||||
|
if (logger.isInfoEnabled()) { |
||||||
|
logger.info("Static JNDI binding: [" + name + "] = [" + obj + "]"); |
||||||
|
} |
||||||
|
this.boundObjects.put(name, obj); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Simple InitialContextFactoryBuilder implementation, |
||||||
|
* creating a new SimpleNamingContext instance. |
||||||
|
* @see SimpleNamingContext |
||||||
|
*/ |
||||||
|
public InitialContextFactory createInitialContextFactory(Hashtable environment) { |
||||||
|
if (activated == null && environment != null) { |
||||||
|
Object icf = environment.get(Context.INITIAL_CONTEXT_FACTORY); |
||||||
|
if (icf != null) { |
||||||
|
Class icfClass = null; |
||||||
|
if (icf instanceof Class) { |
||||||
|
icfClass = (Class) icf; |
||||||
|
} |
||||||
|
else if (icf instanceof String) { |
||||||
|
icfClass = ClassUtils.resolveClassName((String) icf, getClass().getClassLoader()); |
||||||
|
} |
||||||
|
else { |
||||||
|
throw new IllegalArgumentException("Invalid value type for environment key [" + |
||||||
|
Context.INITIAL_CONTEXT_FACTORY + "]: " + icf.getClass().getName()); |
||||||
|
} |
||||||
|
if (!InitialContextFactory.class.isAssignableFrom(icfClass)) { |
||||||
|
throw new IllegalArgumentException( |
||||||
|
"Specified class does not implement [" + InitialContextFactory.class.getName() + "]: " + icf); |
||||||
|
} |
||||||
|
try { |
||||||
|
return (InitialContextFactory) icfClass.newInstance(); |
||||||
|
} |
||||||
|
catch (Throwable ex) { |
||||||
|
IllegalStateException ise = |
||||||
|
new IllegalStateException("Cannot instantiate specified InitialContextFactory: " + icf); |
||||||
|
ise.initCause(ex); |
||||||
|
throw ise; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Default case...
|
||||||
|
return new InitialContextFactory() { |
||||||
|
public Context getInitialContext(Hashtable environment) { |
||||||
|
return new SimpleNamingContext("", boundObjects, environment); |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue