| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.jndi; |
| |
| |
| 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 javax.naming.Binding; |
| import javax.naming.CompoundName; |
| import javax.naming.Context; |
| import javax.naming.InitialContext; |
| import javax.naming.LinkRef; |
| import javax.naming.Name; |
| import javax.naming.NameAlreadyBoundException; |
| import javax.naming.NameNotFoundException; |
| import javax.naming.NameParser; |
| import javax.naming.NamingEnumeration; |
| import javax.naming.NamingException; |
| import javax.naming.NotContextException; |
| import javax.naming.OperationNotSupportedException; |
| import javax.naming.Reference; |
| import javax.naming.Referenceable; |
| import javax.naming.spi.NamingManager; |
| |
| import org.eclipse.jetty.util.component.Dumpable; |
| import org.eclipse.jetty.util.log.Logger; |
| |
| |
| /*------------------------------------------------*/ |
| /** NamingContext |
| * <p>Implementation of Context interface. |
| * |
| * <p><h4>Notes</h4> |
| * <p>All Names are expected to be Compound, not Composite. |
| */ |
| @SuppressWarnings("unchecked") |
| public class NamingContext implements Context, Cloneable, Dumpable |
| { |
| private final static Logger __log=NamingUtil.__log; |
| private final static List<Binding> __empty = Collections.emptyList(); |
| public static final String DEEP_BINDING = "org.eclipse.jetty.jndi.deepBinding"; |
| 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>(); |
| |
| protected NamingContext _parent = null; |
| protected String _name = null; |
| protected NameParser _parser = null; |
| private Collection<Listener> _listeners; |
| |
| /*------------------------------------------------*/ |
| /** |
| * Naming Context Listener. |
| */ |
| public interface Listener |
| { |
| /** |
| * Called by {@link NamingContext#addBinding(Name, Object)} when adding |
| * a binding. |
| * @param ctx The context to add to. |
| * @param binding The binding to add. |
| * @return The binding to bind, or null if the binding should be ignored. |
| */ |
| Binding bind(NamingContext ctx, Binding binding); |
| |
| /** |
| * @param ctx The context to unbind from |
| * @param binding The binding that was unbound. |
| */ |
| void unbind(NamingContext ctx, Binding binding); |
| } |
| |
| /*------------------------------------------------*/ |
| /** |
| * Constructor |
| * |
| * @param env environment properties |
| * @param name relative name of this context |
| * @param parent immediate ancestor Context (can be null) |
| * @param parser NameParser for this Context |
| */ |
| public NamingContext(Hashtable<String,Object> env, |
| String name, |
| NamingContext parent, |
| NameParser parser) |
| { |
| 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; |
| if(__log.isDebugEnabled()) |
| __log.debug("supportDeepBinding={}",_supportDeepBinding); |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Clone this NamingContext |
| * |
| * @return copy of this NamingContext |
| * @exception CloneNotSupportedException if an error occurs |
| */ |
| public Object clone () |
| throws CloneNotSupportedException |
| { |
| NamingContext ctx = (NamingContext)super.clone(); |
| ctx._env.putAll(_env); |
| ctx._bindings.putAll(_bindings); |
| return ctx; |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Getter for _name |
| * |
| * @return name of this Context (relative, not absolute) |
| */ |
| public String getName () |
| { |
| return _name; |
| } |
| |
| /*------------------------------------------------*/ |
| /** |
| * Getter for _parent |
| * |
| * @return parent Context |
| */ |
| public Context getParent() |
| { |
| return _parent; |
| } |
| |
| /*------------------------------------------------*/ |
| /** |
| * Setter for _parser |
| * |
| * |
| */ |
| public void setNameParser (NameParser parser) |
| { |
| _parser = parser; |
| } |
| |
| |
| public final void setEnv (Hashtable<String,Object> env) |
| { |
| _env.clear(); |
| if(env == null) |
| return; |
| _env.putAll(env); |
| _supportDeepBinding = _env.containsKey(DEEP_BINDING); |
| } |
| |
| |
| public Map<String,Binding> getBindings () |
| { |
| return _bindings; |
| } |
| |
| public void setBindings(Map<String,Binding> bindings) |
| { |
| _bindings = bindings; |
| } |
| |
| /*------------------------------------------------*/ |
| /** |
| * Bind a name to an object |
| * |
| * @param name Name of the object |
| * @param obj object to bind |
| * @exception NamingException if an error occurs |
| */ |
| public void bind(Name name, Object obj) |
| throws NamingException |
| { |
| if (isLocked()) |
| throw new NamingException ("This context is immutable"); |
| |
| Name cname = toCanonicalName(name); |
| |
| if (cname == null) |
| throw new NamingException ("Name is null"); |
| |
| if (cname.size() == 0) |
| throw new NamingException ("Name is empty"); |
| |
| |
| //if no subcontexts, just bind it |
| if (cname.size() == 1) |
| { |
| //get the object to be bound |
| Object objToBind = NamingManager.getStateToBind(obj, name,this, _env); |
| // Check for Referenceable |
| if (objToBind instanceof Referenceable) |
| { |
| objToBind = ((Referenceable)objToBind).getReference(); |
| } |
| |
| //anything else we should be able to bind directly |
| addBinding (cname, objToBind); |
| } |
| else |
| { |
| 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 = getBinding (firstComponent); |
| if (binding == null) { |
| if (_supportDeepBinding) |
| { |
| Name subname = _parser.parse(firstComponent); |
| Context subctx = new NamingContext((Hashtable)_env.clone(),firstComponent,this,_parser); |
| addBinding(subname,subctx); |
| binding = getBinding(subname); |
| } |
| else |
| { |
| 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"); |
| } |
| } |
| |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Bind a name (as a String) to an object |
| * |
| * @param name a <code>String</code> value |
| * @param obj an <code>Object</code> value |
| * @exception NamingException if an error occurs |
| */ |
| public void bind(String name, Object obj) |
| throws NamingException |
| { |
| bind (_parser.parse(name), obj); |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Create a context as a child of this one |
| * |
| * @param name a <code>Name</code> value |
| * @return a <code>Context</code> value |
| * @exception NamingException if an error occurs |
| */ |
| public Context createSubcontext (Name name) |
| throws NamingException |
| { |
| if (isLocked()) |
| { |
| NamingException ne = new NamingException ("This context is immutable"); |
| ne.setRemainingName(name); |
| throw ne; |
| } |
| |
| Name cname = toCanonicalName (name); |
| |
| if (cname == null) |
| throw new NamingException ("Name is null"); |
| if (cname.size() == 0) |
| throw new NamingException ("Name is empty"); |
| |
| if (cname.size() == 1) |
| { |
| //not permitted to bind if something already bound at that name |
| Binding binding = getBinding (cname); |
| if (binding != null) |
| throw new NameAlreadyBoundException (cname.toString()); |
| |
| Context ctx = new NamingContext ((Hashtable)_env.clone(), 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); |
| } |
| 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"); |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Create a Context as a child of this one |
| * |
| * @param name a <code>String</code> value |
| * @return a <code>Context</code> value |
| * @exception NamingException if an error occurs |
| */ |
| public Context createSubcontext (String name) |
| throws NamingException |
| { |
| return createSubcontext(_parser.parse(name)); |
| } |
| |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * |
| * |
| * @param name name of subcontext to remove |
| * @exception NamingException if an error occurs |
| */ |
| public void destroySubcontext (String name) |
| throws NamingException |
| { |
| removeBinding(_parser.parse(name)); |
| } |
| |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * |
| * |
| * @param name name of subcontext to remove |
| * @exception NamingException if an error occurs |
| */ |
| public void destroySubcontext (Name name) |
| throws NamingException |
| { |
| removeBinding(name); |
| } |
| |
| /*------------------------------------------------*/ |
| /** |
| * Lookup a binding by name |
| * |
| * @param name name of bound object |
| * @exception NamingException if an error occurs |
| */ |
| public Object lookup(Name name) |
| throws NamingException |
| { |
| if(__log.isDebugEnabled())__log.debug("Looking up name=\""+name+"\""); |
| Name cname = toCanonicalName(name); |
| |
| 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; |
| } |
| |
| |
| |
| if (cname.size() == 1) |
| { |
| Binding binding = getBinding (cname); |
| if (binding == null) |
| { |
| NameNotFoundException nnfe = new NameNotFoundException(); |
| nnfe.setRemainingName(cname); |
| throw nnfe; |
| } |
| |
| |
| Object o = binding.getObject(); |
| |
| //handle links by looking up the link |
| if (o instanceof LinkRef) |
| { |
| //if link name starts with ./ it is relative to current context |
| String linkName = ((LinkRef)o).getLinkName(); |
| if (linkName.startsWith("./")) |
| return this.lookup (linkName.substring(2)); |
| else |
| { |
| //link name is absolute |
| InitialContext ictx = new InitialContext(); |
| return ictx.lookup (linkName); |
| } |
| } |
| else if (o instanceof Reference) |
| { |
| //deference the object |
| try |
| { |
| return NamingManager.getObjectInstance(o, cname, this, _env); |
| } |
| catch (NamingException e) |
| { |
| throw e; |
| } |
| catch (Exception e) |
| { |
| __log.warn("",e); |
| throw new NamingException (e.getMessage()); |
| } |
| } |
| else |
| 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; |
| } |
| |
| //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 |
| * |
| * @param name name of bound object |
| * @return object bound to name |
| * @exception NamingException if an error occurs |
| */ |
| public Object lookup (String name) |
| throws NamingException |
| { |
| return lookup (_parser.parse(name)); |
| } |
| |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Lookup link bound to name |
| * |
| * @param name name of link binding |
| * @return LinkRef or plain object bound at name |
| * @exception NamingException if an error occurs |
| */ |
| public Object lookupLink (Name name) |
| throws NamingException |
| { |
| Name cname = toCanonicalName(name); |
| |
| if (cname == null) |
| { |
| NamingContext ctx = new NamingContext (_env, _name, _parent, _parser); |
| ctx._bindings=_bindings; |
| return ctx; |
| } |
| if (cname.size() == 0) |
| throw new NamingException ("Name is empty"); |
| |
| if (cname.size() == 1) |
| { |
| Binding binding = getBinding (cname); |
| 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; |
| } |
| } |
| |
| |
| //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); |
| } |
| 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 link bound to name |
| * |
| * @param name name of link binding |
| * @return LinkRef or plain object bound at name |
| * @exception NamingException if an error occurs |
| */ |
| public Object lookupLink (String name) |
| throws NamingException |
| { |
| return lookupLink (_parser.parse(name)); |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * List all names bound at Context named by Name |
| * |
| * @param name a <code>Name</code> value |
| * @return a <code>NamingEnumeration</code> value |
| * @exception NamingException if an error occurs |
| */ |
| public NamingEnumeration list(Name name) |
| throws NamingException |
| { |
| 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); |
| } |
| 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)); |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * List all names bound at Context named by Name |
| * |
| * @param name a <code>Name</code> value |
| * @return a <code>NamingEnumeration</code> value |
| * @exception NamingException if an error occurs |
| */ |
| public NamingEnumeration list(String name) |
| throws NamingException |
| { |
| return list(_parser.parse(name)); |
| } |
| |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * List all Bindings present at Context named by Name |
| * |
| * @param name a <code>Name</code> value |
| * @return a <code>NamingEnumeration</code> value |
| * @exception NamingException if an error occurs |
| */ |
| public NamingEnumeration listBindings(Name name) |
| throws NamingException |
| { |
| Name cname = toCanonicalName (name); |
| |
| if (cname == null) |
| { |
| return new BindingEnumeration(__empty.iterator()); |
| } |
| |
| if (cname.size() == 0) |
| { |
| 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)); |
| } |
| |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * List all Bindings at Name |
| * |
| * @param name a <code>String</code> value |
| * @return a <code>NamingEnumeration</code> value |
| * @exception NamingException if an error occurs |
| */ |
| public NamingEnumeration listBindings(String name) |
| throws NamingException |
| { |
| return listBindings (_parser.parse(name)); |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Overwrite or create a binding |
| * |
| * @param name a <code>Name</code> value |
| * @param obj an <code>Object</code> value |
| * @exception NamingException if an error occurs |
| */ |
| public void rebind(Name name, |
| Object obj) |
| throws NamingException |
| { |
| if (isLocked()) |
| throw new NamingException ("This context is immutable"); |
| |
| Name cname = toCanonicalName(name); |
| |
| if (cname == null) |
| throw new NamingException ("Name is null"); |
| |
| if (cname.size() == 0) |
| throw new NamingException ("Name is empty"); |
| |
| |
| //if no subcontexts, just bind it |
| if (cname.size() == 1) |
| { |
| //check if it is a Referenceable |
| Object objToBind = NamingManager.getStateToBind(obj, name, this, _env); |
| |
| if (objToBind instanceof Referenceable) |
| { |
| objToBind = ((Referenceable)objToBind).getReference(); |
| } |
| removeBinding(cname); |
| addBinding (cname, objToBind); |
| } |
| 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"); |
| } |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Overwrite or create a binding from Name to Object |
| * |
| * @param name a <code>String</code> value |
| * @param obj an <code>Object</code> value |
| * @exception NamingException if an error occurs |
| */ |
| public void rebind (String name, |
| Object obj) |
| throws NamingException |
| { |
| rebind (_parser.parse(name), obj); |
| } |
| |
| /*------------------------------------------------*/ |
| /** |
| * Not supported. |
| * |
| * @param name a <code>String</code> value |
| * @exception NamingException if an error occurs |
| */ |
| public void unbind (String name) |
| throws NamingException |
| { |
| unbind(_parser.parse(name)); |
| } |
| |
| /*------------------------------------------------*/ |
| /** |
| * Not supported. |
| * |
| * @param name a <code>String</code> value |
| * @exception NamingException if an error occurs |
| */ |
| public void unbind (Name name) |
| throws NamingException |
| { |
| if (name.size() == 0) |
| return; |
| |
| |
| if (isLocked()) |
| throw new NamingException ("This context is immutable"); |
| |
| Name cname = toCanonicalName(name); |
| |
| if (cname == null) |
| throw new NamingException ("Name is null"); |
| |
| if (cname.size() == 0) |
| throw new NamingException ("Name is empty"); |
| |
| |
| //if no subcontexts, just unbind it |
| if (cname.size() == 1) |
| { |
| removeBinding (cname); |
| } |
| 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"); |
| } |
| } |
| |
| /*------------------------------------------------*/ |
| /** |
| * Not supported |
| * |
| * @param oldName a <code>Name</code> value |
| * @param newName a <code>Name</code> value |
| * @exception NamingException if an error occurs |
| */ |
| public void rename(Name oldName, |
| Name newName) |
| throws NamingException |
| { |
| throw new OperationNotSupportedException(); |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Not supported |
| * |
| * @param oldName a <code>Name</code> value |
| * @param newName a <code>Name</code> value |
| * @exception NamingException if an error occurs |
| */ public void rename(String oldName, |
| String newName) |
| throws NamingException |
| { |
| throw new OperationNotSupportedException(); |
| } |
| |
| |
| |
| /*------------------------------------------------*/ |
| /** Join two names together. These are treated as |
| * CompoundNames. |
| * |
| * @param name a <code>Name</code> value |
| * @param prefix a <code>Name</code> value |
| * @return a <code>Name</code> value |
| * @exception NamingException if an error occurs |
| */ |
| public Name composeName(Name name, |
| Name prefix) |
| throws NamingException |
| { |
| if (name == null) |
| throw new NamingException ("Name cannot be null"); |
| if (prefix == null) |
| throw new NamingException ("Prefix cannot be null"); |
| |
| Name compoundName = (CompoundName)prefix.clone(); |
| compoundName.addAll (name); |
| return compoundName; |
| } |
| |
| |
| |
| /*------------------------------------------------*/ |
| /** Join two names together. These are treated as |
| * CompoundNames. |
| * |
| * @param name a <code>Name</code> value |
| * @param prefix a <code>Name</code> value |
| * @return a <code>Name</code> value |
| * @exception NamingException if an error occurs |
| */ |
| public String composeName (String name, |
| String prefix) |
| throws NamingException |
| { |
| if (name == null) |
| throw new NamingException ("Name cannot be null"); |
| if (prefix == null) |
| throw new NamingException ("Prefix cannot be null"); |
| |
| Name compoundName = _parser.parse(prefix); |
| compoundName.add (name); |
| return compoundName.toString(); |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Do nothing |
| * |
| * @exception NamingException if an error occurs |
| */ |
| public void close () |
| throws NamingException |
| { |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Return a NameParser for this Context. |
| * |
| * @param name a <code>Name</code> value |
| * @return a <code>NameParser</code> value |
| */ |
| public NameParser getNameParser (Name name) |
| { |
| return _parser; |
| } |
| |
| /*------------------------------------------------*/ |
| /** |
| * Return a NameParser for this Context. |
| * |
| * @param name a <code>Name</code> value |
| * @return a <code>NameParser</code> value |
| */ |
| public NameParser getNameParser (String name) |
| { |
| return _parser; |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Get the full name of this Context node |
| * by visiting it's ancestors back to root. |
| * |
| * NOTE: if this Context has a URL namespace then |
| * the URL prefix will be missing |
| * |
| * @return the full name of this Context |
| * @exception NamingException if an error occurs |
| */ |
| public String getNameInNamespace () |
| throws NamingException |
| { |
| Name name = _parser.parse(""); |
| |
| NamingContext c = this; |
| while (c != null) |
| { |
| String str = c.getName(); |
| if (str != null) |
| name.add(0, str); |
| c = (NamingContext)c.getParent(); |
| } |
| return name.toString(); |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Add an environment setting to this Context |
| * |
| * @param propName name of the property to add |
| * @param propVal value of the property to add |
| * @return propVal or previous value of the property |
| * @exception NamingException if an error occurs |
| */ |
| public Object addToEnvironment(String propName, |
| Object propVal) |
| throws NamingException |
| { |
| if (isLocked() && !(propName.equals(UNLOCK_PROPERTY))) |
| throw new NamingException ("This context is immutable"); |
| |
| return _env.put (propName, propVal); |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Remove a property from this Context's environment. |
| * |
| * @param propName name of property to remove |
| * @return value of property or null if it didn't exist |
| * @exception NamingException if an error occurs |
| */ |
| public Object removeFromEnvironment(String propName) |
| throws NamingException |
| { |
| if (isLocked()) |
| throw new NamingException ("This context is immutable"); |
| |
| return _env.remove (propName); |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Get the environment of this Context. |
| * |
| * @return a copy of the environment of this Context. |
| */ |
| public Hashtable getEnvironment () |
| { |
| return (Hashtable)_env.clone(); |
| } |
| |
| /*------------------------------------------------*/ |
| /** |
| * Add a name to object binding to this Context. |
| * |
| * @param name a <code>Name</code> value |
| * @param obj an <code>Object</code> value |
| */ |
| public void addBinding (Name name, Object obj) throws NameAlreadyBoundException |
| { |
| String key = name.toString(); |
| Binding binding=new Binding (key, obj); |
| |
| Collection<Listener> list = findListeners(); |
| |
| for (Listener listener : list) |
| { |
| binding=listener.bind(this,binding); |
| if (binding==null) |
| break; |
| } |
| |
| if(__log.isDebugEnabled()) |
| __log.debug("Adding binding with key="+key+" obj="+obj+" for context="+_name+" as "+binding); |
| |
| if (binding!=null) |
| { |
| if (_bindings.containsKey(key)) { |
| if(_supportDeepBinding) { |
| // quietly return (no exception) |
| // this is jndi spec breaking, but is added to support broken |
| // jndi users like openejb. |
| return; |
| } |
| throw new NameAlreadyBoundException(name.toString()); |
| } |
| _bindings.put(key,binding); |
| } |
| } |
| |
| /*------------------------------------------------*/ |
| /** |
| * Get a name to object binding from this Context |
| * |
| * @param name a <code>Name</code> value |
| * @return a <code>Binding</code> value |
| */ |
| public Binding getBinding (Name name) |
| { |
| return (Binding) _bindings.get(name.toString()); |
| } |
| |
| |
| /*------------------------------------------------*/ |
| /** |
| * Get a name to object binding from this Context |
| * |
| * @param name as a String |
| * @return null or the Binding |
| */ |
| public Binding getBinding (String name) |
| { |
| return (Binding) _bindings.get(name); |
| } |
| |
| /*------------------------------------------------*/ |
| public void removeBinding (Name name) |
| { |
| String key = name.toString(); |
| if (__log.isDebugEnabled()) |
| __log.debug("Removing binding with key="+key); |
| Binding binding = _bindings.remove(key); |
| if (binding!=null) |
| { |
| Collection<Listener> list = findListeners(); |
| for (Listener listener : list) |
| listener.unbind(this,binding); |
| } |
| } |
| |
| /*------------------------------------------------*/ |
| /** |
| * Remove leading or trailing empty components from |
| * name. Eg "/comp/env/" -> "comp/env" |
| * |
| * @param name the name to normalize |
| * @return normalized name |
| */ |
| public Name toCanonicalName (Name name) |
| { |
| Name canonicalName = name; |
| |
| if (name != null) |
| { |
| if (canonicalName.size() > 1) |
| { |
| if (canonicalName.get(0).equals("")) |
| canonicalName = canonicalName.getSuffix(1); |
| |
| if (canonicalName.get(canonicalName.size()-1).equals("")) |
| canonicalName = canonicalName.getPrefix(canonicalName.size()-1); |
| } |
| } |
| |
| return canonicalName; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public boolean isLocked() |
| { |
| if ((_env.get(LOCK_PROPERTY) == null) && (_env.get(UNLOCK_PROPERTY) == null)) |
| return false; |
| |
| Object lockKey = _env.get(LOCK_PROPERTY); |
| Object unlockKey = _env.get(UNLOCK_PROPERTY); |
| |
| if ((lockKey != null) && (unlockKey != null) && (lockKey.equals(unlockKey))) |
| return false; |
| return true; |
| } |
| |
| |
| /* ------------------------------------------------------------ */ |
| public String dump() |
| { |
| StringBuilder buf = new StringBuilder(); |
| try |
| { |
| dump(buf,""); |
| } |
| catch(Exception e) |
| { |
| __log.warn(e); |
| } |
| return buf.toString(); |
| } |
| |
| |
| /* ------------------------------------------------------------ */ |
| 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"); |
| } |
| } |
| } |
| |
| private Collection<Listener> findListeners() |
| { |
| Collection<Listener> list = new ArrayList<Listener>(); |
| NamingContext ctx=this; |
| while (ctx!=null) |
| { |
| if (ctx._listeners!=null) |
| list.addAll(ctx._listeners); |
| ctx=(NamingContext)ctx.getParent(); |
| } |
| return list; |
| } |
| |
| public void addListener(Listener listener) |
| { |
| if (_listeners==null) |
| _listeners=new ArrayList<Listener>(); |
| _listeners.add(listener); |
| } |
| |
| public boolean removeListener(Listener listener) |
| { |
| return _listeners.remove(listener); |
| } |
| |
| @Override |
| public String toString() |
| { |
| StringBuilder buf = new StringBuilder(); |
| buf.append(this.getClass().getName()).append('@').append(Integer.toHexString(this.hashCode())); |
| buf.append("[name=").append(this._name); |
| buf.append(",parent="); |
| if (this._parent != null) |
| { |
| buf.append(this._parent.getClass().getName()).append('@').append(Integer.toHexString(this._parent.hashCode())); |
| } |
| buf.append(",bindings"); |
| if (this._bindings == null) |
| { |
| buf.append("=<null>"); |
| } |
| else |
| { |
| buf.append(".size=").append(this._bindings.size()); |
| } |
| buf.append(']'); |
| return buf.toString(); |
| } |
| } |