Issue #3729 concurrent JNDI access

+ concurrent map for the NamingContext bindings
+ refactored duplicate code into common methods
+ simplified deepBindSupport

Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
Greg Wilkins 2019-06-04 19:32:53 +02:00
parent ac8303c45e
commit 7484651941
4 changed files with 381 additions and 1161 deletions

View File

@ -18,12 +18,10 @@
package org.eclipse.jetty.jndi;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Map;
import java.util.WeakHashMap;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NameParser;
@ -78,8 +76,6 @@ public class ContextFactory implements ObjectFactory
*/
private static final ThreadLocal<ClassLoader> __threadClassLoader = new ThreadLocal<ClassLoader>();
/**
* Find or create a context which pertains to a classloader.
* <p>

View File

@ -18,10 +18,8 @@
package org.eclipse.jetty.jndi;
import java.util.Hashtable;
import java.util.Properties;
import javax.naming.CompoundName;
import javax.naming.Context;
import javax.naming.Name;

View File

@ -22,11 +22,10 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.naming.Binding;
import javax.naming.CompoundName;
import javax.naming.Context;
@ -56,7 +55,7 @@ import org.eclipse.jetty.util.log.Logger;
* All Names are expected to be Compound, not Composite.
*/
@SuppressWarnings("unchecked")
public class NamingContext implements Context, Cloneable, Dumpable
public class NamingContext implements Context, Dumpable
{
private final static Logger __log=NamingUtil.__log;
private final static List<Binding> __empty = Collections.emptyList();
@ -64,9 +63,22 @@ public class NamingContext implements Context, Cloneable, Dumpable
public static final String LOCK_PROPERTY = "org.eclipse.jetty.jndi.lock";
public static final String UNLOCK_PROPERTY = "org.eclipse.jetty.jndi.unlock";
protected final Hashtable<String,Object> _env = new Hashtable<String,Object>();
private boolean _supportDeepBinding = false;
protected Map<String,Binding> _bindings = new HashMap<String,Binding>();
/*
* The env is stored as a Hashtable to be compatible with the API.
* There is no need for concurrent protection (see Concurrent Access section
* of the {@link Context} javadoc), so multiple threads acting on the same
* Context env need to self - mutually exclude.
*/
protected final Hashtable<String,Object> _env = new Hashtable<>();
/*
* This contexts bindings are stored as a ConcurrentHashMap.
* There is generally no need for concurrent protection (see Concurrent Access section
* of the {@link Context} javadoc), However, the NamingContext is used for root contexts and
* we do not mutually exclude when initializing, so instead we do make the bindings
* thread safe (unlike the env where we expect users to respect the Concurrent Access requirements).
*/
protected final ConcurrentMap<String,Binding> _bindings;
protected NamingContext _parent = null;
protected String _name = null;
@ -99,7 +111,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
/**
* Constructor
*
* @param env environment properties
* @param env environment properties which are copied into this Context's environment
* @param name relative name of this context
* @param parent immediate ancestor Context (can be null)
* @param parser NameParser for this Context
@ -108,53 +120,48 @@ public class NamingContext implements Context, Cloneable, Dumpable
String name,
NamingContext parent,
NameParser parser)
{
this(env, name, parent, parser, null);
}
private NamingContext(Hashtable<String,Object> env,
String name,
NamingContext parent,
NameParser parser,
ConcurrentMap<String, Binding> bindings)
{
if (env != null)
{
_env.putAll(env);
// look for deep binding support in _env
Object support = _env.get(DEEP_BINDING);
if (support == null)
_supportDeepBinding = false;
else
_supportDeepBinding = support != null?Boolean.parseBoolean(support.toString()):false;
}
else
{
// no env? likely this is a root context (java or local) that
// was created without an _env. Look for a system property.
String value = System.getProperty(DEEP_BINDING,"false");
_supportDeepBinding = Boolean.parseBoolean(value);
// put what we discovered into the _env for later sub-contexts
// to utilize.
_env.put(DEEP_BINDING,_supportDeepBinding);
}
_name = name;
_parent = parent;
_parser = parser;
_bindings = bindings==null ? new ConcurrentHashMap<>() : bindings;
if(__log.isDebugEnabled())
__log.debug("supportDeepBinding={}",_supportDeepBinding);
__log.debug("new {}", this);
}
/*------------------------------------------------*/
/**
* Clone this NamingContext
*
* @return copy of this NamingContext
* @exception CloneNotSupportedException if an error occurs
* @return A shallow copy of the Context with the same bindings, but a copy of the Env
*/
@Override
public Object clone ()
throws CloneNotSupportedException
public NamingContext shallowCopy()
{
NamingContext ctx = (NamingContext)super.clone();
ctx._env.putAll(_env);
ctx._bindings.putAll(_bindings);
return ctx;
return new NamingContext(_env, _name, _parent, _parser, _bindings);
}
public boolean isDeepBindingSupported()
{
// look for deep binding support in _env
Object support = _env.get(DEEP_BINDING);
if (support!=null)
return Boolean.parseBoolean(String.valueOf(support));
if (_parent!=null)
return _parent.isDeepBindingSupported();
// probably a root context
return Boolean.parseBoolean(System.getProperty(DEEP_BINDING,"false"));
}
/*------------------------------------------------*/
/**
* Getter for _name
@ -190,20 +197,54 @@ public class NamingContext implements Context, Cloneable, Dumpable
if(env == null)
return;
_env.putAll(env);
_supportDeepBinding = _env.containsKey(DEEP_BINDING);
}
public Map<String,Binding> getBindings ()
private Object dereference(Object ctx, String firstComponent) throws NamingException
{
return _bindings;
if (ctx instanceof Reference)
{
//deference the object
try
{
return NamingManager.getObjectInstance(ctx, _parser.parse(firstComponent), this, _env);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
return ctx;
}
public void setBindings(Map<String,Binding> bindings)
private Context getContext(Name cname) throws NamingException
{
_bindings = bindings;
String firstComponent = cname.get(0);
if (firstComponent.equals(""))
return this;
Binding binding = getBinding (firstComponent);
if (binding == null)
{
NameNotFoundException nnfe = new NameNotFoundException(firstComponent + " is not bound");
nnfe.setRemainingName(cname);
throw nnfe;
}
Object ctx = dereference(binding.getObject(), firstComponent);
if (!(ctx instanceof Context))
throw new NotContextException(firstComponent + " not a context in " + this.getNameInNamespace());
return (Context)ctx;
}
/*------------------------------------------------*/
/**
* Bind a name to an object
@ -244,7 +285,8 @@ public class NamingContext implements Context, Cloneable, Dumpable
}
else
{
if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
if(__log.isDebugEnabled())
__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
//walk down the subcontext hierarchy
//need to ignore trailing empty "" name components
@ -256,13 +298,13 @@ public class NamingContext implements Context, Cloneable, Dumpable
ctx = this;
else
{
Binding binding = getBinding (firstComponent);
if (binding == null) {
if (_supportDeepBinding)
if (binding == null)
{
if (isDeepBindingSupported())
{
Name subname = _parser.parse(firstComponent);
Context subctx = new NamingContext((Hashtable)_env.clone(),firstComponent,this,_parser);
Context subctx = new NamingContext(_env,firstComponent,this,_parser, null);
addBinding(subname,subctx);
binding = getBinding(subname);
}
@ -272,27 +314,8 @@ public class NamingContext implements Context, Cloneable, Dumpable
}
}
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
ctx = dereference(binding.getObject(),firstComponent);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (ctx instanceof Context)
{
@ -354,56 +377,13 @@ public class NamingContext implements Context, Cloneable, Dumpable
if (binding != null)
throw new NameAlreadyBoundException (cname.toString());
Context ctx = new NamingContext ((Hashtable)_env.clone(), cname.get(0), this, _parser);
Context ctx = new NamingContext (_env, cname.get(0), this, _parser);
addBinding (cname, ctx);
return ctx;
}
//If the name has multiple subcontexts, walk the hierarchy by
//fetching the first one. All intermediate subcontexts in the
//name must already exist.
String firstComponent = cname.get(0);
Object ctx = null;
if (firstComponent.equals(""))
ctx = this;
else
{
Binding binding = getBinding (firstComponent);
if (binding == null)
throw new NameNotFoundException (firstComponent + " is not bound");
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
if(__log.isDebugEnabled())__log.debug("Object bound at "+firstComponent +" is a Reference");
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
return getContext(cname).createSubcontext (cname.getSuffix(1));
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (ctx instanceof Context)
{
return ((Context)ctx).createSubcontext (cname.getSuffix(1));
}
else
throw new NotContextException (firstComponent +" is not a Context");
}
/*------------------------------------------------*/
/**
@ -420,8 +400,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
return createSubcontext(_parser.parse(name));
}
/*------------------------------------------------*/
/**
*
@ -436,8 +414,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
removeBinding(_parser.parse(name));
}
/*------------------------------------------------*/
/**
*
@ -468,14 +444,10 @@ public class NamingContext implements Context, Cloneable, Dumpable
if ((cname == null) || (cname.size() == 0))
{
__log.debug("Null or empty name, returning copy of this context");
NamingContext ctx = new NamingContext (_env, _name, _parent, _parser);
ctx._bindings=_bindings;
return ctx;
__log.debug("Null or empty name, returning shallowCopy of this context");
return shallowCopy();
}
if (cname.size() == 1)
{
Binding binding = getBinding (cname);
@ -486,7 +458,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
throw nnfe;
}
Object o = binding.getObject();
//handle links by looking up the link
@ -505,7 +476,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
}
else if (o instanceof Reference)
{
//deference the object
// TODO use deference ??
try
{
return NamingManager.getObjectInstance(o, cname, this, _env);
@ -524,54 +495,9 @@ public class NamingContext implements Context, Cloneable, Dumpable
return o;
}
//it is a multipart name, recurse to the first subcontext
String firstComponent = cname.get(0);
Object ctx = null;
if (firstComponent.equals(""))
ctx = this;
else
{
Binding binding = getBinding (firstComponent);
if (binding == null)
{
NameNotFoundException nnfe = new NameNotFoundException();
nnfe.setRemainingName(cname);
throw nnfe;
return getContext(cname).lookup (cname.getSuffix(1));
}
//as we have bound a reference to an object factory
//for the component specific contexts
//at "comp" we need to resolve the reference
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (!(ctx instanceof Context))
throw new NotContextException();
return ((Context)ctx).lookup (cname.getSuffix(1));
}
/*------------------------------------------------*/
/**
* Lookup binding of an object by name
@ -587,8 +513,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
return lookup (_parser.parse(name));
}
/*------------------------------------------------*/
/**
* Lookup link bound to name
@ -603,12 +527,11 @@ public class NamingContext implements Context, Cloneable, Dumpable
{
Name cname = toCanonicalName(name);
if (cname == null)
if (cname == null || name.isEmpty())
{
NamingContext ctx = new NamingContext (_env, _name, _parent, _parser);
ctx._bindings=_bindings;
return ctx;
return shallowCopy();
}
if (cname.size() == 0)
throw new NamingException ("Name is empty");
@ -618,74 +541,11 @@ public class NamingContext implements Context, Cloneable, Dumpable
if (binding == null)
throw new NameNotFoundException();
Object o = binding.getObject();
//handle links by looking up the link
if (o instanceof Reference)
{
//deference the object
try
{
return NamingManager.getObjectInstance(o, cname.getPrefix(1), this, _env);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
else
{
//object is either a LinkRef which we don't dereference
//or a plain object in which case spec says we return it
return o;
}
return dereference(binding.getObject(), cname.getPrefix(1).toString());
}
//it is a multipart name, recurse to the first subcontext
String firstComponent = cname.get(0);
Object ctx = null;
if (firstComponent.equals(""))
ctx = this;
else
{
Binding binding = getBinding (firstComponent);
if (binding == null)
throw new NameNotFoundException ();
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
return getContext(cname).lookup (cname.getSuffix(1));
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (!(ctx instanceof Context))
throw new NotContextException();
return ((Context)ctx).lookup (cname.getSuffix(1));
}
/*------------------------------------------------*/
/**
@ -702,7 +562,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
return lookupLink (_parser.parse(name));
}
/*------------------------------------------------*/
/**
* List all names bound at Context named by Name
@ -718,61 +577,19 @@ public class NamingContext implements Context, Cloneable, Dumpable
if(__log.isDebugEnabled())__log.debug("list() on Context="+getName()+" for name="+name);
Name cname = toCanonicalName(name);
if (cname == null)
{
return new NameEnumeration(__empty.iterator());
}
if (cname.size() == 0)
{
return new NameEnumeration (_bindings.values().iterator());
}
//multipart name
String firstComponent = cname.get(0);
Object ctx = null;
if (firstComponent.equals(""))
ctx = this;
else
{
Binding binding = getBinding (firstComponent);
if (binding == null)
throw new NameNotFoundException ();
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
if(__log.isDebugEnabled())__log.debug("Dereferencing Reference for "+name.get(0));
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
return getContext(cname).list (cname.getSuffix(1));
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (!(ctx instanceof Context))
throw new NotContextException();
return ((Context)ctx).list (cname.getSuffix(1));
}
/*------------------------------------------------*/
/**
@ -789,8 +606,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
return list(_parser.parse(name));
}
/*------------------------------------------------*/
/**
* List all Bindings present at Context named by Name
@ -815,48 +630,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
return new BindingEnumeration (_bindings.values().iterator());
}
//multipart name
String firstComponent = cname.get(0);
Object ctx = null;
//if a name has a leading "/" it is parsed as "" so ignore it by staying
//at this level in the tree
if (firstComponent.equals(""))
ctx = this;
else
{
//it is a non-empty name component
Binding binding = getBinding (firstComponent);
if (binding == null)
throw new NameNotFoundException ();
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (!(ctx instanceof Context))
throw new NotContextException();
return ((Context)ctx).listBindings (cname.getSuffix(1));
return getContext(cname).listBindings (cname.getSuffix(1));
}
@ -917,49 +691,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
}
else
{
//walk down the subcontext hierarchy
if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
String firstComponent = cname.get(0);
Object ctx = null;
if (firstComponent.equals(""))
ctx = this;
else
{
Binding binding = getBinding (name.get(0));
if (binding == null)
throw new NameNotFoundException (name.get(0)+ " is not bound");
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (ctx instanceof Context)
{
((Context)ctx).rebind (cname.getSuffix(1), obj);
}
else
throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
getContext(cname).rebind (cname.getSuffix(1), obj);
}
}
@ -1020,7 +752,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
if (cname.size() == 0)
throw new NamingException ("Name is empty");
//if no subcontexts, just unbind it
if (cname.size() == 1)
{
@ -1028,48 +759,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
}
else
{
//walk down the subcontext hierarchy
if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
String firstComponent = cname.get(0);
Object ctx = null;
if (firstComponent.equals(""))
ctx = this;
else
{
Binding binding = getBinding (name.get(0));
if (binding == null)
throw new NameNotFoundException (name.get(0)+ " is not bound");
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (ctx instanceof Context)
{
((Context)ctx).unbind (cname.getSuffix(1));
}
else
throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
getContext(cname).unbind (cname.getSuffix(1));
}
}
@ -1277,7 +967,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
@Override
public Hashtable getEnvironment ()
{
return (Hashtable)_env.clone();
return _env;
}
/*------------------------------------------------*/
@ -1307,8 +997,10 @@ public class NamingContext implements Context, Cloneable, Dumpable
if (binding!=null)
{
if (_bindings.containsKey(key)) {
if(_supportDeepBinding) {
if (_bindings.putIfAbsent(key, binding)!=null)
{
if(isDeepBindingSupported())
{
// quietly return (no exception)
// this is jndi spec breaking, but is added to support broken
// jndi users like openejb.
@ -1316,7 +1008,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
}
throw new NameAlreadyBoundException(name.toString());
}
_bindings.put(key,binding);
}
}
@ -1329,10 +1020,9 @@ public class NamingContext implements Context, Cloneable, Dumpable
*/
public Binding getBinding (Name name)
{
return (Binding) _bindings.get(name.toString());
return _bindings.get(name.toString());
}
/*------------------------------------------------*/
/**
* Get a name to object binding from this Context
@ -1342,7 +1032,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
*/
public Binding getBinding (String name)
{
return (Binding) _bindings.get(name);
return _bindings.get(name);
}
/*------------------------------------------------*/
@ -1406,49 +1096,14 @@ public class NamingContext implements Context, Cloneable, Dumpable
@Override
public String dump()
{
StringBuilder buf = new StringBuilder();
try
{
dump(buf,"");
return Dumpable.dump(this);
}
catch(Exception e)
{
__log.warn(e);
}
return buf.toString();
}
/* ------------------------------------------------------------ */
@Override
public void dump(Appendable out,String indent) throws IOException
{
out.append(this.getClass().getSimpleName()).append("@").append(Long.toHexString(this.hashCode())).append("\n");
int size=_bindings.size();
int i=0;
for (Map.Entry<String,Binding> entry : ((Map<String,Binding>)_bindings).entrySet())
{
boolean last=++i==size;
out.append(indent).append(" +- ").append(entry.getKey()).append(": ");
Binding binding = entry.getValue();
Object value = binding.getObject();
if ("comp".equals(entry.getKey()) && value instanceof Reference && "org.eclipse.jetty.jndi.ContextFactory".equals(((Reference)value).getFactoryClassName()))
{
ContextFactory.dump(out,indent+(last?" ":" | "));
}
else if (value instanceof Dumpable)
{
((Dumpable)value).dump(out,indent+(last?" ":" | "));
}
else
{
out.append(value.getClass().getSimpleName()).append("=");
out.append(String.valueOf(value).replace('\n','|').replace('\r','|'));
out.append("\n");
}
}
Dumpable.dumpObjects(out,indent,this, _bindings);
}
private Collection<Listener> findListeners()

View File

@ -18,11 +18,8 @@
package org.eclipse.jetty.jndi.local;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;
import javax.naming.Binding;
import javax.naming.CompoundName;
import javax.naming.Context;
@ -40,8 +37,6 @@ import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.spi.NamingManager;
import org.eclipse.jetty.jndi.BindingEnumeration;
import org.eclipse.jetty.jndi.NameEnumeration;
import org.eclipse.jetty.jndi.NamingContext;
import org.eclipse.jetty.jndi.NamingUtil;
import org.eclipse.jetty.util.log.Logger;
@ -62,7 +57,6 @@ public class localContextRoot implements Context
protected final static NamingContext __root = new NamingRoot();
private final Hashtable<String,Object> _env;
static class NamingRoot extends NamingContext
{
public NamingRoot()
@ -71,8 +65,6 @@ public class localContextRoot implements Context
}
}
static class LocalNameParser implements NameParser
{
Properties syntax = new Properties();
@ -100,10 +92,6 @@ public class localContextRoot implements Context
*/
public static NamingContext getRoot()
{
return __root;
@ -122,7 +110,6 @@ public class localContextRoot implements Context
@Override
public void close() throws NamingException
{
}
/**
@ -136,7 +123,6 @@ public class localContextRoot implements Context
return "";
}
/**
*
*
@ -144,13 +130,9 @@ public class localContextRoot implements Context
*/
@Override
public void destroySubcontext(Name name) throws NamingException
{
synchronized (__root)
{
__root.destroySubcontext(getSuffix(name));
}
}
/**
*
@ -160,13 +142,8 @@ public class localContextRoot implements Context
@Override
public void destroySubcontext(String name) throws NamingException
{
synchronized (__root)
{
destroySubcontext(__root.getNameParser("").parse(getSuffix(name)));
}
}
/**
*
@ -179,7 +156,49 @@ public class localContextRoot implements Context
return _env;
}
private Object dereference(Object ctx, String firstComponent) throws NamingException
{
if (ctx instanceof Reference)
{
//deference the object
try
{
return NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn(e);
throw new NamingException (e.getMessage());
}
}
return ctx;
}
private Context getContext(Name cname) throws NamingException
{
String firstComponent = cname.get(0);
if (firstComponent.equals(""))
return this;
Binding binding = __root.getBinding (firstComponent);
if (binding == null)
{
NameNotFoundException nnfe = new NameNotFoundException(firstComponent + " is not bound");
nnfe.setRemainingName(cname);
throw nnfe;
}
Object ctx = dereference(binding.getObject(), firstComponent);
if (!(ctx instanceof Context))
throw new NotContextException(firstComponent + " not a context in " + this.getNameInNamespace());
return (Context)ctx;
}
/**
*
@ -188,15 +207,12 @@ public class localContextRoot implements Context
*/
@Override
public void unbind(Name name) throws NamingException
{
synchronized (__root)
{
//__root.unbind(getSuffix(name));
if (name.size() == 0)
return;
if (__root.isLocked())
throw new NamingException ("This context is immutable");
@ -208,7 +224,6 @@ public class localContextRoot implements Context
if (cname.size() == 0)
throw new NamingException ("Name is empty");
//if no subcontexts, just unbind it
if (cname.size() == 1)
{
@ -216,52 +231,7 @@ public class localContextRoot implements Context
}
else
{
//walk down the subcontext hierarchy
if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
String firstComponent = cname.get(0);
Object ctx = null;
if (firstComponent.equals(""))
ctx = this;
else
{
Binding binding = __root.getBinding (name.get(0));
if (binding == null)
throw new NameNotFoundException (name.get(0)+ " is not bound");
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (ctx instanceof Context)
{
((Context)ctx).unbind (cname.getSuffix(1));
}
else
throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
}
getContext(cname).unbind (cname.getSuffix(1));
}
}
@ -276,8 +246,6 @@ public class localContextRoot implements Context
unbind(__root.getNameParser("").parse(getSuffix(name)));
}
/**
*
*
@ -285,12 +253,9 @@ public class localContextRoot implements Context
*/
@Override
public Object lookupLink(String name) throws NamingException
{
synchronized (__root)
{
return lookupLink(__root.getNameParser("").parse(getSuffix(name)));
}
}
/**
*
@ -300,19 +265,12 @@ public class localContextRoot implements Context
@Override
public Object lookupLink(Name name) throws NamingException
{
synchronized (__root)
{
//return __root.lookupLink(getSuffix(name));
Name cname = __root.toCanonicalName(name);
if (cname == null)
if (cname == null || cname.isEmpty())
{
//If no name create copy of this context with same bindings, but with copy of the environment so it can be modified
NamingContext ctx = new NamingContext (_env, null, null, __root.getNameParser(""));
ctx.setBindings(__root.getBindings());
return ctx;
return __root.shallowCopy();
}
if (cname.size() == 0)
@ -352,49 +310,9 @@ public class localContextRoot implements Context
}
}
//it is a multipart name, recurse to the first subcontext
String firstComponent = cname.get(0);
Object ctx = null;
if (firstComponent.equals(""))
ctx = this;
else
{
Binding binding = __root.getBinding (firstComponent);
if (binding == null)
throw new NameNotFoundException ();
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
return getContext(cname).lookup (cname.getSuffix(1));
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (!(ctx instanceof Context))
throw new NotContextException();
return ((Context)ctx).lookup (cname.getSuffix(1));
}
}
/**
*
@ -407,7 +325,6 @@ public class localContextRoot implements Context
return _env.remove(propName);
}
/**
*
*
@ -416,23 +333,14 @@ public class localContextRoot implements Context
@Override
public Object lookup(Name name) throws NamingException
{
synchronized (__root)
{
//return __root.lookup(getSuffix(name));
if(__log.isDebugEnabled())__log.debug("Looking up name=\""+name+"\"");
Name cname = __root.toCanonicalName(name);
if ((cname == null) || (cname.size() == 0))
if ((cname == null) || cname.isEmpty())
{
__log.debug("Null or empty name, returning copy of this context");
NamingContext ctx = new NamingContext (_env, null, null, __root.getNameParser(""));
ctx.setBindings(__root.getBindings());
return ctx;
return __root.shallowCopy();
}
if (cname.size() == 1)
{
Binding binding = __root.getBinding (cname);
@ -443,7 +351,6 @@ public class localContextRoot implements Context
throw nnfe;
}
Object o = binding.getObject();
//handle links by looking up the link
@ -462,7 +369,7 @@ public class localContextRoot implements Context
}
else if (o instanceof Reference)
{
//deference the object
// TODO use deference
try
{
return NamingManager.getObjectInstance(o, cname, __root, _env);
@ -483,56 +390,9 @@ public class localContextRoot implements Context
return o;
}
//it is a multipart name, get the first subcontext
String firstComponent = cname.get(0);
Object ctx = null;
if (firstComponent.equals(""))
ctx = this;
else
{
Binding binding = __root.getBinding (firstComponent);
if (binding == null)
{
NameNotFoundException nnfe = new NameNotFoundException();
nnfe.setRemainingName(cname);
throw nnfe;
return getContext(cname).lookup(cname.getSuffix(1));
}
//as we have bound a reference to an object factory
//for the component specific contexts
//at "comp" we need to resolve the reference
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (!(ctx instanceof Context))
throw new NotContextException();
return ((Context)ctx).lookup (cname.getSuffix(1));
}
}
/**
*
*
@ -540,13 +400,9 @@ public class localContextRoot implements Context
*/
@Override
public Object lookup(String name) throws NamingException
{
synchronized (__root)
{
return lookup(__root.getNameParser("").parse(getSuffix(name)));
}
}
/**
*
@ -555,14 +411,9 @@ public class localContextRoot implements Context
*/
@Override
public void bind(String name, Object obj) throws NamingException
{
synchronized (__root)
{
bind(__root.getNameParser("").parse(getSuffix(name)), obj);
}
}
/**
*
@ -572,11 +423,6 @@ public class localContextRoot implements Context
@Override
public void bind(Name name, Object obj) throws NamingException
{
synchronized (__root)
{
// __root.bind(getSuffix(name), obj);
if (__root.isLocked())
throw new NamingException ("This context is immutable");
@ -588,7 +434,6 @@ public class localContextRoot implements Context
if (cname.size() == 0)
throw new NamingException ("Name is empty");
//if no subcontexts, just bind it
if (cname.size() == 1)
{
@ -605,52 +450,10 @@ public class localContextRoot implements Context
}
else
{
if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
if(__log.isDebugEnabled())
__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
//walk down the subcontext hierarchy
//need to ignore trailing empty "" name components
String firstComponent = cname.get(0);
Object ctx = null;
if (firstComponent.equals(""))
ctx = this;
else
{
Binding binding = __root.getBinding (firstComponent);
if (binding == null)
throw new NameNotFoundException (firstComponent+ " is not bound");
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (ctx instanceof Context)
{
((Context)ctx).bind (cname.getSuffix(1), obj);
}
else
throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
}
getContext(cname).bind (cname.getSuffix(1), obj);
}
}
@ -662,11 +465,6 @@ public class localContextRoot implements Context
@Override
public void rebind(Name name, Object obj) throws NamingException
{
synchronized (__root)
{
//__root.rebind(getSuffix(name), obj);
if (__root.isLocked())
throw new NamingException ("This context is immutable");
@ -678,7 +476,6 @@ public class localContextRoot implements Context
if (cname.size() == 0)
throw new NamingException ("Name is empty");
//if no subcontexts, just bind it
if (cname.size() == 1)
{
@ -695,49 +492,10 @@ public class localContextRoot implements Context
else
{
//walk down the subcontext hierarchy
if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
if(__log.isDebugEnabled())
__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
String firstComponent = cname.get(0);
Object ctx = null;
if (firstComponent.equals(""))
ctx = this;
else
{
Binding binding = __root.getBinding (name.get(0));
if (binding == null)
throw new NameNotFoundException (name.get(0)+ " is not bound");
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (ctx instanceof Context)
{
((Context)ctx).rebind (cname.getSuffix(1), obj);
}
else
throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
}
getContext(cname).rebind (cname.getSuffix(1), obj);
}
}
@ -748,12 +506,10 @@ public class localContextRoot implements Context
*/
@Override
public void rebind(String name, Object obj) throws NamingException
{
synchronized (__root)
{
rebind(__root.getNameParser("").parse(getSuffix(name)), obj);
}
}
/**
*
*
@ -761,12 +517,9 @@ public class localContextRoot implements Context
*/
@Override
public void rename(Name oldName, Name newName) throws NamingException
{
synchronized (__root)
{
throw new OperationNotSupportedException();
}
}
/**
*
@ -775,12 +528,9 @@ public class localContextRoot implements Context
*/
@Override
public void rename(String oldName, String newName) throws NamingException
{
synchronized (__root)
{
throw new OperationNotSupportedException();
}
}
/**
*
@ -789,8 +539,6 @@ public class localContextRoot implements Context
*/
@Override
public Context createSubcontext(String name) throws NamingException
{
synchronized (__root)
{
//if the subcontext comes directly off the root, use the env of the InitialContext
//as the root itself has no environment. Otherwise, it inherits the env of the parent
@ -802,7 +550,6 @@ public class localContextRoot implements Context
return createSubcontext(__root.getNameParser("").parse(name));
}
}
/**
*
@ -811,8 +558,6 @@ public class localContextRoot implements Context
*/
@Override
public Context createSubcontext(Name name) throws NamingException
{
synchronized (__root)
{
//if the subcontext comes directly off the root, use the env of the InitialContext
//as the root itself has no environment. Otherwise, it inherits the env of the parent
@ -822,9 +567,6 @@ public class localContextRoot implements Context
// ctx.setEnv(_env);
//return ctx;
if (__root.isLocked())
{
NamingException ne = new NamingException ("This context is immutable");
@ -847,57 +589,15 @@ public class localContextRoot implements Context
throw new NameAlreadyBoundException (cname.toString());
//make a new naming context with the root as the parent
Context ctx = new NamingContext ((Hashtable)_env.clone(), cname.get(0), __root, __root.getNameParser(""));
Context ctx = new NamingContext (_env, cname.get(0), __root, __root.getNameParser(""));
__root.addBinding (cname, ctx);
return ctx;
}
//If the name has multiple subcontexts,
return getContext(cname).createSubcontext(cname.getSuffix(1));
//If the name has multiple subcontexts, walk the hierarchy by
//fetching the first one. All intermediate subcontexts in the
//name must already exist.
String firstComponent = cname.get(0);
Object ctx = null;
if (firstComponent.equals(""))
ctx = this;
else
{
Binding binding = __root.getBinding (firstComponent);
if (binding == null)
throw new NameNotFoundException (firstComponent + " is not bound");
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
if(__log.isDebugEnabled())__log.debug("Object bound at "+firstComponent +" is a Reference");
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (ctx instanceof Context)
{
return ((Context)ctx).createSubcontext (cname.getSuffix(1));
}
else
throw new NotContextException (firstComponent +" is not a Context");
}
}
/**
*
@ -929,12 +629,8 @@ public class localContextRoot implements Context
@Override
public NamingEnumeration list(String name) throws NamingException
{
synchronized (__root)
{
return list(__root.getNameParser("").parse(getSuffix(name)));
return __root.list(name);
}
}
/**
*
@ -944,67 +640,7 @@ public class localContextRoot implements Context
@Override
public NamingEnumeration list(Name name) throws NamingException
{
synchronized (__root)
{
//return __root.list(getSuffix(name));
Name cname = __root.toCanonicalName(name);
if (cname == null)
{
List<Binding> empty = Collections.emptyList();
return new NameEnumeration(empty.iterator());
}
if (cname.size() == 0)
{
return new NameEnumeration (__root.getBindings().values().iterator());
}
//multipart name
String firstComponent = cname.get(0);
Object ctx = null;
if (firstComponent.equals(""))
ctx = this;
else
{
Binding binding = __root.getBinding (firstComponent);
if (binding == null)
throw new NameNotFoundException ();
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
if(__log.isDebugEnabled())__log.debug("Dereferencing Reference for "+name.get(0));
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (!(ctx instanceof Context))
throw new NotContextException();
return ((Context)ctx).list (cname.getSuffix(1));
}
return __root.list(name);
}
/**
@ -1015,70 +651,9 @@ public class localContextRoot implements Context
@Override
public NamingEnumeration listBindings(Name name) throws NamingException
{
synchronized (__root)
{
//return __root.listBindings(getSuffix(name));
Name cname = __root.toCanonicalName (name);
if (cname == null)
{
List<Binding> empty = Collections.emptyList();
return new BindingEnumeration(empty.iterator());
return __root.listBindings(name);
}
if (cname.size() == 0)
{
return new BindingEnumeration (__root.getBindings().values().iterator());
}
//multipart name
String firstComponent = cname.get(0);
Object ctx = null;
//if a name has a leading "/" it is parsed as "" so ignore it by staying
//at this level in the tree
if (firstComponent.equals(""))
ctx = this;
else
{
//it is a non-empty name component
Binding binding = __root.getBinding (firstComponent);
if (binding == null)
throw new NameNotFoundException ();
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
try
{
ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
}
catch (NamingException e)
{
throw e;
}
catch (Exception e)
{
__log.warn("",e);
throw new NamingException (e.getMessage());
}
}
}
if (!(ctx instanceof Context))
throw new NotContextException();
return ((Context)ctx).listBindings (cname.getSuffix(1));
}
}
/**
*
*
@ -1087,12 +662,8 @@ public class localContextRoot implements Context
@Override
public NamingEnumeration listBindings(String name) throws NamingException
{
synchronized (__root)
{
return listBindings(__root.getNameParser("").parse(getSuffix(name)));
return __root.listBindings(name);
}
}
/**
*