// ======================================================================== // Copyright (c) 2000-2009 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.local; import java.util.Collections; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Properties; 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.NameClassPair; 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.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; /** * * localContext * * Implementation of the delegate for InitialContext for the local namespace. * * * @version $Revision: 4780 $ $Date: 2009-03-17 16:36:08 +0100 (Tue, 17 Mar 2009) $ * */ public class localContextRoot implements Context { private final static Logger __log=NamingUtil.__log; protected final static NamingContext __root = new NamingRoot(); private final Hashtable<String,Object> _env; static class NamingRoot extends NamingContext { public NamingRoot() { super (null,null,null,new LocalNameParser()); } } static class LocalNameParser implements NameParser { Properties syntax = new Properties(); LocalNameParser() { syntax.put("jndi.syntax.direction", "left_to_right"); syntax.put("jndi.syntax.separator", "/"); syntax.put("jndi.syntax.ignorecase", "false"); } public Name parse(String name) throws NamingException { return new CompoundName(name, syntax); } } /* * Root has to use the localContextRoot's env for all operations. * So, if createSubcontext in the root, use the env of the localContextRoot. * If lookup binding in the root, use the env of the localContextRoot. * */ public static NamingContext getRoot() { return __root; } public localContextRoot(Hashtable env) { _env = new Hashtable(env); } /** * * * @see javax.naming.Context#close() */ public void close() throws NamingException { } /** * * * @see javax.naming.Context#getNameInNamespace() */ public String getNameInNamespace() throws NamingException { return ""; } /** * * * @see javax.naming.Context#destroySubcontext(javax.naming.Name) */ public void destroySubcontext(Name name) throws NamingException { synchronized (__root) { __root.destroySubcontext(getSuffix(name)); } } /** * * * @see javax.naming.Context#destroySubcontext(java.lang.String) */ public void destroySubcontext(String name) throws NamingException { synchronized (__root) { destroySubcontext(__root.getNameParser("").parse(getSuffix(name))); } } /** * * * @see javax.naming.Context#getEnvironment() */ public Hashtable getEnvironment() throws NamingException { return _env; } /** * * * @see javax.naming.Context#unbind(javax.naming.Name) */ 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"); Name cname = __root.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) { __root.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 = __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"); } } } /** * * * @see javax.naming.Context#unbind(java.lang.String) */ public void unbind(String name) throws NamingException { unbind(__root.getNameParser("").parse(getSuffix(name))); } /** * * * @see javax.naming.Context#lookupLink(java.lang.String) */ public Object lookupLink(String name) throws NamingException { synchronized (__root) { return lookupLink(__root.getNameParser("").parse(getSuffix(name))); } } /** * * * @see javax.naming.Context#lookupLink(javax.naming.Name) */ public Object lookupLink(Name name) throws NamingException { synchronized (__root) { //return __root.lookupLink(getSuffix(name)); Name cname = __root.toCanonicalName(name); if (cname == null) { //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; } if (cname.size() == 0) throw new NamingException ("Name is empty"); if (cname.size() == 1) { Binding binding = __root.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), __root, _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 = __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).lookup (cname.getSuffix(1)); } } /** * * * @see javax.naming.Context#removeFromEnvironment(java.lang.String) */ public Object removeFromEnvironment(String propName) throws NamingException { return _env.remove(propName); } /** * * * @see javax.naming.Context#lookup(javax.naming.Name) */ 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)) { __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; } if (cname.size() == 1) { Binding binding = __root.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 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, __root, _env); } catch (NamingException e) { throw e; } catch (final Exception e) { throw new NamingException (e.getMessage()) { { initCause(e);} }; } } else 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; } //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)); } } /** * * * @see javax.naming.Context#lookup(java.lang.String) */ public Object lookup(String name) throws NamingException { synchronized (__root) { return lookup(__root.getNameParser("").parse(getSuffix(name))); } } /** * * * @see javax.naming.Context#bind(java.lang.String, java.lang.Object) */ public void bind(String name, Object obj) throws NamingException { synchronized (__root) { bind(__root.getNameParser("").parse(getSuffix(name)), obj); } } /** * * * @see javax.naming.Context#bind(javax.naming.Name, java.lang.Object) */ 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"); Name cname = __root.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 __root.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 = __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"); } } } /** * * * @see javax.naming.Context#rebind(javax.naming.Name, java.lang.Object) */ 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"); Name cname = __root.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, __root, _env); if (objToBind instanceof Referenceable) { objToBind = ((Referenceable)objToBind).getReference(); } __root.removeBinding(cname); __root.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 = __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"); } } } /** * * * @see javax.naming.Context#rebind(java.lang.String, java.lang.Object) */ public void rebind(String name, Object obj) throws NamingException { synchronized (__root) { rebind(__root.getNameParser("").parse(getSuffix(name)), obj); } } /** * * * @see javax.naming.Context#rename(javax.naming.Name, javax.naming.Name) */ public void rename(Name oldName, Name newName) throws NamingException { synchronized (__root) { throw new OperationNotSupportedException(); } } /** * * * @see javax.naming.Context#rename(java.lang.String, java.lang.String) */ public void rename(String oldName, String newName) throws NamingException { synchronized (__root) { throw new OperationNotSupportedException(); } } /** * * * @see javax.naming.Context#createSubcontext(java.lang.String) */ 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 //Context further down the tree. //NamingContext ctx = (NamingContext)__root.createSubcontext(name); //if (ctx.getParent() == __root) // ctx.setEnv(_env); //return ctx; return createSubcontext(__root.getNameParser("").parse(name)); } } /** * * * @see javax.naming.Context#createSubcontext(javax.naming.Name) */ 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 //Context further down the tree. //NamingContext ctx = (NamingContext)__root.createSubcontext(getSuffix(name)); //if (ctx.getParent() == __root) // ctx.setEnv(_env); //return ctx; if (__root.isLocked()) { NamingException ne = new NamingException ("This context is immutable"); ne.setRemainingName(name); throw ne; } Name cname = __root.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 = __root.getBinding (cname); if (binding != null) 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("")); __root.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 = __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"); } } /** * * * @see javax.naming.Context#getNameParser(java.lang.String) */ public NameParser getNameParser(String name) throws NamingException { return __root.getNameParser(name); } /** * * * @see javax.naming.Context#getNameParser(javax.naming.Name) */ public NameParser getNameParser(Name name) throws NamingException { return __root.getNameParser(name); } /** * * * @see javax.naming.Context#list(java.lang.String) */ public NamingEnumeration list(String name) throws NamingException { synchronized (__root) { return list(__root.getNameParser("").parse(getSuffix(name))); } } /** * * * @see javax.naming.Context#list(javax.naming.Name) */ 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)); } } /** * * * @see javax.naming.Context#listBindings(javax.naming.Name) */ 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()); } 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)); } } /** * * * @see javax.naming.Context#listBindings(java.lang.String) */ public NamingEnumeration listBindings(String name) throws NamingException { synchronized (__root) { return listBindings(__root.getNameParser("").parse(getSuffix(name))); } } /** * * * @see javax.naming.Context#addToEnvironment(java.lang.String, * java.lang.Object) */ public Object addToEnvironment(String propName, Object propVal) throws NamingException { return _env.put(propName, propVal); } /** * * * @see javax.naming.Context#composeName(java.lang.String, java.lang.String) */ public String composeName(String name, String prefix) throws NamingException { return __root.composeName(name, prefix); } /** * * * @see javax.naming.Context#composeName(javax.naming.Name, * javax.naming.Name) */ public Name composeName(Name name, Name prefix) throws NamingException { return __root.composeName(name, prefix); } protected String getSuffix(String url) throws NamingException { return url; } protected Name getSuffix(Name name) throws NamingException { return name; } }