/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.naming;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
/**
* Handles the associations :
* <ul>
* <li>Object with a NamingContext</li>
* <li>Calling thread with a NamingContext</li>
* <li>Calling thread with object bound to the same naming context</li>
* <li>Thread context class loader with a NamingContext</li>
* <li>Thread context class loader with object bound to the same
* NamingContext</li>
* </ul>
* The objects are typically Catalina Server or Context objects.
*
* @author Remy Maucherat
*/
public class ContextBindings {
// -------------------------------------------------------------- Variables
/**
* Bindings object - naming context. Keyed by object.
*/
private static final Hashtable<Object,Context> objectBindings = new Hashtable<>();
/**
* Bindings thread - naming context. Keyed by thread.
*/
private static final Hashtable<Thread,Context> threadBindings = new Hashtable<>();
/**
* Bindings thread - object. Keyed by thread.
*/
private static final Hashtable<Thread,Object> threadObjectBindings = new Hashtable<>();
/**
* Bindings class loader - naming context. Keyed by class loader.
*/
private static final Hashtable<ClassLoader,Context> clBindings = new Hashtable<>();
/**
* Bindings class loader - object. Keyed by class loader.
*/
private static final Hashtable<ClassLoader,Object> clObjectBindings = new Hashtable<>();
/**
* The string manager for this package.
*/
protected static final StringManager sm = StringManager.getManager(ContextBindings.class);
// --------------------------------------------------------- Public Methods
/**
* Binds an object and a naming context.
*
* @param obj Object to bind with naming context
* @param context Associated naming context instance
*/
public static void bindContext(Object obj, Context context) {
bindContext(obj, context, null);
}
/**
* Binds an object and a naming context.
*
* @param obj Object to bind with naming context
* @param context Associated naming context instance
* @param token Security token
*/
public static void bindContext(Object obj, Context context, Object token) {
if (ContextAccessController.checkSecurityToken(obj, token)) {
objectBindings.put(obj, context);
}
}
/**
* Unbinds an object and a naming context.
*
* @param obj Object to unbind
* @param token Security token
*/
public static void unbindContext(Object obj, Object token) {
if (ContextAccessController.checkSecurityToken(obj, token)) {
objectBindings.remove(obj);
}
}
/**
* Retrieve a naming context.
*
* @param obj Object bound to the required naming context
*/
static Context getContext(Object obj) {
return objectBindings.get(obj);
}
/**
* Binds a naming context to a thread.
*
* @param obj Object bound to the required naming context
* @param token Security token
*
* @throws NamingException If no naming context is bound to the provided
* object
*/
public static void bindThread(Object obj, Object token) throws NamingException {
if (ContextAccessController.checkSecurityToken(obj, token)) {
Context context = objectBindings.get(obj);
if (context == null) {
throw new NamingException(
sm.getString("contextBindings.unknownContext", obj));
}
threadBindings.put(Thread.currentThread(), context);
threadObjectBindings.put(Thread.currentThread(), obj);
}
}
/**
* Unbinds a thread and a naming context.
*
* @param obj Object bound to the required naming context
* @param token Security token
*/
public static void unbindThread(Object obj, Object token) {
if (ContextAccessController.checkSecurityToken(obj, token)) {
threadBindings.remove(Thread.currentThread());
threadObjectBindings.remove(Thread.currentThread());
}
}
/**
* Retrieves the naming context bound to the current thread.
*
* @return The naming context bound to the current thread.
*
* @throws NamingException If no naming context is bound to the current
* thread
*/
public static Context getThread() throws NamingException {
Context context = threadBindings.get(Thread.currentThread());
if (context == null) {
throw new NamingException
(sm.getString("contextBindings.noContextBoundToThread"));
}
return context;
}
/**
* Retrieves the name of the object bound to the naming context that is also
* bound to the current thread.
*/
static String getThreadName() throws NamingException {
Object obj = threadObjectBindings.get(Thread.currentThread());
if (obj == null) {
throw new NamingException
(sm.getString("contextBindings.noContextBoundToThread"));
}
return obj.toString();
}
/**
* Tests if current thread is bound to a naming context.
*
* @return <code>true</code> if the current thread is bound to a naming
* context, otherwise <code>false</code>
*/
public static boolean isThreadBound() {
return threadBindings.containsKey(Thread.currentThread());
}
/**
* Binds a naming context to a class loader.
*
* @param obj Object bound to the required naming context
* @param token Security token
* @param classLoader The class loader to bind to the naming context
*
* @throws NamingException If no naming context is bound to the provided
* object
*/
public static void bindClassLoader(Object obj, Object token,
ClassLoader classLoader) throws NamingException {
if (ContextAccessController.checkSecurityToken(obj, token)) {
Context context = objectBindings.get(obj);
if (context == null) {
throw new NamingException
(sm.getString("contextBindings.unknownContext", obj));
}
clBindings.put(classLoader, context);
clObjectBindings.put(classLoader, obj);
}
}
/**
* Unbinds a naming context and a class loader.
*
* @param obj Object bound to the required naming context
* @param token Security token
* @param classLoader The class loader bound to the naming context
*/
public static void unbindClassLoader(Object obj, Object token,
ClassLoader classLoader) {
if (ContextAccessController.checkSecurityToken(obj, token)) {
Object o = clObjectBindings.get(classLoader);
if (o == null || !o.equals(obj)) {
return;
}
clBindings.remove(classLoader);
clObjectBindings.remove(classLoader);
}
}
/**
* Retrieves the naming context bound to a class loader.
*
* @return the naming context bound to current class loader or one of its
* parents
*
* @throws NamingException If no naming context was bound
*/
public static Context getClassLoader() throws NamingException {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Context context = null;
do {
context = clBindings.get(cl);
if (context != null) {
return context;
}
} while ((cl = cl.getParent()) != null);
throw new NamingException(sm.getString("contextBindings.noContextBoundToCL"));
}
/**
* Retrieves the name of the object bound to the naming context that is also
* bound to the thread context class loader.
*/
static String getClassLoaderName() throws NamingException {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Object obj = null;
do {
obj = clObjectBindings.get(cl);
if (obj != null) {
return obj.toString();
}
} while ((cl = cl.getParent()) != null);
throw new NamingException (sm.getString("contextBindings.noContextBoundToCL"));
}
/**
* Tests if the thread context class loader is bound to a context.
*
* @return <code>true</code> if the thread context class loader or one of
* its parents is bound to a naming context, otherwise
* <code>false</code>
*/
public static boolean isClassLoaderBound() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
do {
if (clBindings.containsKey(cl)) {
return true;
}
} while ((cl = cl.getParent()) != null);
return false;
}
}