View Javadoc

    1   // ========================================================================
    2   // $Id: NamingContext.java 887 2006-09-05 13:46:42Z janb $
    3   // Copyright 1999-2006 Mort Bay Consulting Pty. Ltd.
    4   // ------------------------------------------------------------------------
    5   // Licensed under the Apache License, Version 2.0 (the "License");
    6   // you may not use this file except in compliance with the License.
    7   // You may obtain a copy of the License at
    8   // http://www.apache.org/licenses/LICENSE-2.0
    9   // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  // ========================================================================
    15
    16  package org.mortbay.naming;
    17
    18
    19  import java.util.Enumeration;
    20  import java.util.Hashtable;
    21  import java.util.NoSuchElementException;
    22
    23  import javax.naming.Binding;
    24  import javax.naming.CompoundName;
    25  import javax.naming.Context;
    26  import javax.naming.InitialContext;
    27  import javax.naming.LinkRef;
    28  import javax.naming.Name;
    29  import javax.naming.NameAlreadyBoundException;
    30  import javax.naming.NameClassPair;
    31  import javax.naming.NameNotFoundException;
    32  import javax.naming.NameParser;
    33  import javax.naming.NamingEnumeration;
    34  import javax.naming.NamingException;
    35  import javax.naming.NotContextException;
    36  import javax.naming.OperationNotSupportedException;
    37  import javax.naming.Reference;
    38  import javax.naming.Referenceable;
    39  import javax.naming.spi.NamingManager;
    40
    41  import org.mortbay.log.Log;
    42
    43
    44  /*------------------------------------------------*/
    45  /** NamingContext
    46   * <p>Implementation of Context interface.
    47   *
    48   * <p><h4>Notes</h4>
    49   * <p>All Names are expected to be Compound, not Composite.
    50   *
    51   * <p><h4>Usage</h4>
    52   * <pre>
    53   */
    54  /*
    55  * </pre>
    56  *
    57  * @see
    58  *
    59  * @author <a href="mailto:janb@mortbay.com">Jan Bartel</a>
    60  * @version 1.0
    61  */
    62  public class NamingContext implements Context, Cloneable
    63  {
    64
    65      public static final String LOCK_PROPERTY = "org.mortbay.jndi.lock";
    66      public static final String UNLOCK_PROPERTY = "org.mortbay.jndi.unlock";
    67
    68      public static final Enumeration EMPTY_ENUM = new Enumeration ()
    69          {
    70              public boolean hasMoreElements()
    71              {
    72                  return false;
    73              }
    74
    75              public Object nextElement ()
    76              {
    77                  throw new NoSuchElementException();
    78              }
    79          };
    80
    81
    82      protected Context _parent = null;
    83      protected String _name = null;
    84      protected Hashtable _env = null;
    85      protected Hashtable _bindings = new Hashtable();
    86      protected NameParser _parser = null;
    87
    88
    89
    90      /*------------------------------------------------*/
    91      /** NameEnumeration
    92       * <p>Implementation of NamingEnumeration interface.
    93       *
    94       * <p><h4>Notes</h4>
    95       * <p>Used for returning results of Context.list();
    96       *
    97       * <p><h4>Usage</h4>
    98       * <pre>
    99       */
    100     /*
    101      * </pre>
    102      *
    103      * @see
    104      *
    105      */
    106     public class NameEnumeration implements NamingEnumeration
    107     {
    108         Enumeration _delegate;
    109
    110         public NameEnumeration (Enumeration e)
    111         {
    112             _delegate = e;
    113         }
    114
    115         public void close()
    116             throws NamingException
    117         {
    118         }
    119
    120         public boolean hasMore ()
    121             throws NamingException
    122         {
    123             return _delegate.hasMoreElements();
    124         }
    125
    126         public Object next()
    127             throws NamingException
    128         {
    129             Binding b = (Binding)_delegate.nextElement();
    130             return new NameClassPair (b.getName(), b.getClassName(), true);
    131         }
    132
    133         public boolean hasMoreElements()
    134         {
    135             return _delegate.hasMoreElements();
    136         }
    137
    138         public Object nextElement()
    139         {
    140             Binding b = (Binding)_delegate.nextElement();
    141             return new NameClassPair (b.getName(), b.getClassName(), true);
    142         }
    143     }
    144
    145
    146
    147
    148
    149
    150     /*------------------------------------------------*/
    151     /** BindingEnumeration
    152      * <p>Implementation of NamingEnumeration
    153      *
    154      * <p><h4>Notes</h4>
    155      * <p>Used to return results of Context.listBindings();
    156      *
    157      * <p><h4>Usage</h4>
    158      * <pre>
    159      */
    160     /*
    161      * </pre>
    162      *
    163      * @see
    164      *
    165      */
    166     public class BindingEnumeration implements NamingEnumeration
    167     {
    168         Enumeration _delegate;
    169
    170         public BindingEnumeration (Enumeration e)
    171         {
    172             _delegate = e;
    173         }
    174
    175         public void close()
    176             throws NamingException
    177         {
    178         }
    179
    180         public boolean hasMore ()
    181             throws NamingException
    182         {
    183             return _delegate.hasMoreElements();
    184         }
    185
    186         public Object next()
    187             throws NamingException
    188         {
    189             Binding b = (Binding)_delegate.nextElement();
    190             return new Binding (b.getName(), b.getClassName(), b.getObject(), true);
    191         }
    192
    193         public boolean hasMoreElements()
    194         {
    195             return _delegate.hasMoreElements();
    196         }
    197
    198         public Object nextElement()
    199         {
    200             Binding b = (Binding)_delegate.nextElement();
    201             return new Binding (b.getName(), b.getClassName(), b.getObject(),true);
    202         }
    203     }
    204
    205
    206
    207     /*------------------------------------------------*/
    208     /**
    209      * Constructor
    210      *
    211      * @param env environment properties
    212      * @param name relative name of this context
    213      * @param parent immediate ancestor Context (can be null)
    214      * @param parser NameParser for this Context
    215      */
    216     public NamingContext(Hashtable env,
    217                          String name,
    218                          Context parent,
    219                          NameParser parser)
    220     {
    221         if (env == null)
    222             _env = new Hashtable();
    223         else
    224             _env = new Hashtable(env);
    225         _name = name;
    226         _parent = parent;
    227         _parser = parser;
    228     }
    229
    230
    231
    232     /*------------------------------------------------*/
    233     /**
    234      * Creates a new <code>NamingContext</code> instance.
    235      *
    236      * @param env a <code>Hashtable</code> value
    237      */
    238     public NamingContext (Hashtable env)
    239     {
    240         if (env == null)
    241             _env = new Hashtable();
    242         else
    243             _env = new Hashtable(env);
    244     }
    245
    246
    247
    248
    249     /*------------------------------------------------*/
    250     /**
    251      * Constructor
    252      *
    253      */
    254     public NamingContext ()
    255     {
    256         _env = new Hashtable();
    257     }
    258
    259
    260     /*------------------------------------------------*/
    261     /**
    262      * Clone this NamingContext
    263      *
    264      * @return copy of this NamingContext
    265      * @exception CloneNotSupportedException if an error occurs
    266      */
    267     public Object clone ()
    268         throws CloneNotSupportedException
    269     {
    270         NamingContext ctx = (NamingContext)super.clone();
    271         ctx._env = (Hashtable)_env.clone();
    272         ctx._bindings = (Hashtable)_bindings.clone();
    273         return ctx;
    274     }
    275
    276
    277     /*------------------------------------------------*/
    278     /**
    279      * Getter for _name
    280      *
    281      * @return name of this Context (relative, not absolute)
    282      */
    283     public String getName ()
    284     {
    285         return _name;
    286     }
    287
    288     /*------------------------------------------------*/
    289     /**
    290      * Getter for _parent
    291      *
    292      * @return parent Context
    293      */
    294     public Context getParent()
    295     {
    296         return _parent;
    297     }
    298
    299     /*------------------------------------------------*/
    300     /**
    301      * Setter for _parser
    302      *
    303      *
    304      */
    305     public void setNameParser (NameParser parser)
    306     {
    307         _parser = parser;
    308     }
    309
    310
    311
    312     /*------------------------------------------------*/
    313     /**
    314      * Bind a name to an object
    315      *
    316      * @param name Name of the object
    317      * @param obj object to bind
    318      * @exception NamingException if an error occurs
    319      */
    320     public void bind(Name name, Object obj)
    321         throws NamingException
    322     {
    323         if (isLocked())
    324             throw new NamingException ("This context is immutable");
    325
    326         Name cname = toCanonicalName(name);
    327
    328         if (cname == null)
    329             throw new NamingException ("Name is null");
    330
    331         if (cname.size() == 0)
    332             throw new NamingException ("Name is empty");
    333
    334
    335         //if no subcontexts, just bind it
    336         if (cname.size() == 1)
    337         {
    338             //get the object to be bound
    339             Object objToBind = NamingManager.getStateToBind(obj, name,this, null);
    340             // Check for Referenceable
    341             if (objToBind instanceof Referenceable)
    342             {
    343                 objToBind = ((Referenceable)objToBind).getReference();
    344             }
    345             //anything else we should be able to bind directly
    346
    347             Binding binding = getBinding (cname);
    348             if (binding == null)
    349                 addBinding (cname, objToBind);
    350             else
    351                 throw new NameAlreadyBoundException (cname.toString());
    352         }
    353         else
    354         {
    355             if(Log.isDebugEnabled())Log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
    356
    357             //walk down the subcontext hierarchy
    358             //need to ignore trailing empty "" name components
    359
    360             String firstComponent = cname.get(0);
    361             Object ctx = null;
    362
    363             if (firstComponent.equals(""))
    364                 ctx = this;
    365             else
    366             {
    367
    368                 Binding  binding = getBinding (firstComponent);
    369                 if (binding == null)
    370                     throw new NameNotFoundException (firstComponent+ " is not bound");
    371
    372                 ctx = binding.getObject();
    373
    374
    375                 if (ctx instanceof Reference)
    376                 {
    377                     //deference the object
    378                     try
    379                     {
    380                         ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
    381                     }
    382                     catch (NamingException e)
    383                     {
    384                         throw e;
    385                     }
    386                     catch (Exception e)
    387                     {
    388                         Log.warn("",e);
    389                         throw new NamingException (e.getMessage());
    390                     }
    391                 }
    392             }
    393
    394
    395             if (ctx instanceof Context)
    396             {
    397                 ((Context)ctx).bind (cname.getSuffix(1), obj);
    398             }
    399             else
    400                 throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
    401         }
    402     }
    403
    404
    405
    406     /*------------------------------------------------*/
    407     /**
    408      * Bind a name (as a String) to an object
    409      *
    410      * @param name a <code>String</code> value
    411      * @param obj an <code>Object</code> value
    412      * @exception NamingException if an error occurs
    413      */
    414     public void bind(String name, Object obj)
    415         throws NamingException
    416     {
    417         bind (_parser.parse(name), obj);
    418     }
    419
    420
    421     /*------------------------------------------------*/
    422     /**
    423      * Create a context as a child of this one
    424      *
    425      * @param name a <code>Name</code> value
    426      * @return a <code>Context</code> value
    427      * @exception NamingException if an error occurs
    428      */
    429     public Context createSubcontext (Name name)
    430         throws NamingException
    431     {
    432         if (isLocked())
    433         {
    434             NamingException ne = new NamingException ("This context is immutable");
    435             ne.setRemainingName(name);
    436             throw ne;
    437         }
    438
    439
    440
    441         Name cname = toCanonicalName (name);
    442
    443         if (cname == null)
    444             throw new NamingException ("Name is null");
    445         if (cname.size() == 0)
    446             throw new NamingException ("Name is empty");
    447
    448         if (cname.size() == 1)
    449         {
    450             //not permitted to bind if something already bound at that name
    451             Binding binding = getBinding (cname);
    452             if (binding != null)
    453                 throw new NameAlreadyBoundException (cname.toString());
    454
    455             Context ctx = new NamingContext ((Hashtable)_env.clone(), cname.get(0), this, _parser);
    456             addBinding (cname, ctx);
    457             return ctx;
    458         }
    459
    460
    461         //If the name has multiple subcontexts, walk the hierarchy by
    462         //fetching the first one. All intermediate subcontexts in the
    463         //name must already exist.
    464         String firstComponent = cname.get(0);
    465         Object ctx = null;
    466
    467         if (firstComponent.equals(""))
    468             ctx = this;
    469         else
    470         {
    471             Binding binding = getBinding (firstComponent);
    472             if (binding == null)
    473                 throw new NameNotFoundException (firstComponent + " is not bound");
    474
    475             ctx = binding.getObject();
    476
    477             if (ctx instanceof Reference)
    478             {
    479                 //deference the object
    480                 if(Log.isDebugEnabled())Log.debug("Object bound at "+firstComponent +" is a Reference");
    481                 try
    482                 {
    483                     ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
    484                 }
    485                 catch (NamingException e)
    486                 {
    487                     throw e;
    488                 }
    489                 catch (Exception e)
    490                 {
    491                     Log.warn("",e);
    492                     throw new NamingException (e.getMessage());
    493                 }
    494             }
    495         }
    496
    497         if (ctx instanceof Context)
    498         {
    499             return ((Context)ctx).createSubcontext (cname.getSuffix(1));
    500         }
    501         else
    502             throw new NotContextException (firstComponent +" is not a Context");
    503     }
    504
    505
    506     /*------------------------------------------------*/
    507     /**
    508      * Create a Context as a child of this one
    509      *
    510      * @param name a <code>String</code> value
    511      * @return a <code>Context</code> value
    512      * @exception NamingException if an error occurs
    513      */
    514     public Context createSubcontext (String name)
    515         throws NamingException
    516     {
    517         return createSubcontext(_parser.parse(name));
    518     }
    519
    520
    521
    522     /*------------------------------------------------*/
    523     /**
    524      * Not supported
    525      *
    526      * @param name name of subcontext to remove
    527      * @exception NamingException if an error occurs
    528      */
    529     public void destroySubcontext (String name)
    530         throws NamingException
    531     {
    532         removeBinding(_parser.parse(name));
    533     }
    534
    535
    536
    537     /*------------------------------------------------*/
    538     /**
    539      * Not supported
    540      *
    541      * @param name name of subcontext to remove
    542      * @exception NamingException if an error occurs
    543      */
    544     public void destroySubcontext (Name name)
    545         throws NamingException
    546     {
    547          removeBinding(name);
    548     }
    549
    550     /*------------------------------------------------*/
    551     /**
    552      * Lookup a binding by name
    553      *
    554      * @param name name of bound object
    555      * @exception NamingException if an error occurs
    556      */
    557     public Object lookup(Name name)
    558         throws NamingException
    559     {
    560         if(Log.isDebugEnabled())Log.debug("Looking up name=\""+name+"\"");
    561         Name cname = toCanonicalName(name);
    562
    563         if ((cname == null) || (cname.size() == 0))
    564         {
    565             Log.debug("Null or empty name, returning copy of this context");
    566             NamingContext ctx = new NamingContext (_env, _name, _parent, _parser);
    567             ctx._bindings = _bindings;
    568             return ctx;
    569         }
    570
    571
    572
    573         if (cname.size() == 1)
    574         {
    575             Binding binding = getBinding (cname);
    576             if (binding == null)
    577             {
    578                 NameNotFoundException nnfe = new NameNotFoundException();
    579                 nnfe.setRemainingName(cname);
    580                 throw nnfe;
    581             }
    582
    583
    584             Object o = binding.getObject();
    585
    586             //handle links by looking up the link
    587             if (o instanceof LinkRef)
    588             {
    589                 //if link name starts with ./ it is relative to current context
    590                 String linkName = ((LinkRef)o).getLinkName();
    591                 if (linkName.startsWith("./"))
    592                     return this.lookup (linkName.substring(2));
    593                 else
    594                 {
    595                     //link name is absolute
    596                     InitialContext ictx = new InitialContext();
    597                     return ictx.lookup (linkName);
    598                 }
    599             }
    600             else if (o instanceof Reference)
    601             {
    602                 //deference the object
    603                 try
    604                 {
    605                     return NamingManager.getObjectInstance(o, cname, this, _env);
    606                 }
    607                 catch (NamingException e)
    608                 {
    609                     throw e;
    610                 }
    611                 catch (Exception e)
    612                 {
    613                     Log.warn("",e);
    614                     throw new NamingException (e.getMessage());
    615                 }
    616             }
    617             else
    618                 return o;
    619         }
    620
    621         //it is a multipart name, recurse to the first subcontext
    622
    623         String firstComponent = cname.get(0);
    624         Object ctx = null;
    625
    626         if (firstComponent.equals(""))
    627             ctx = this;
    628         else
    629         {
    630
    631             Binding binding = getBinding (firstComponent);
    632             if (binding == null)
    633             {
    634                 NameNotFoundException nnfe = new NameNotFoundException();
    635                 nnfe.setRemainingName(cname);
    636                 throw nnfe;
    637             }
    638
    639             //as we have bound a reference to an object factory
    640             //for the component specific contexts
    641             //at "comp" we need to resolve the reference
    642             ctx = binding.getObject();
    643
    644             if (ctx instanceof Reference)
    645             {
    646                 //deference the object
    647                 try
    648                 {
    649                     ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
    650                 }
    651                 catch (NamingException e)
    652                 {
    653                     throw e;
    654                 }
    655                 catch (Exception e)
    656                 {
    657                     Log.warn("",e);
    658                     throw new NamingException (e.getMessage());
    659                 }
    660             }
    661         }
    662         if (!(ctx instanceof Context))
    663             throw new NotContextException();
    664
    665         return ((Context)ctx).lookup (cname.getSuffix(1));
    666     }
    667
    668
    669     /*------------------------------------------------*/
    670     /**
    671      * Lookup binding of an object by name
    672      *
    673      * @param name name of bound object
    674      * @return object bound to name
    675      * @exception NamingException if an error occurs
    676      */
    677     public Object lookup (String name)
    678         throws NamingException
    679     {
    680         return lookup (_parser.parse(name));
    681     }
    682
    683
    684
    685     /*------------------------------------------------*/
    686     /**
    687      * Lookup link bound to name
    688      *
    689      * @param name name of link binding
    690      * @return LinkRef or plain object bound at name
    691      * @exception NamingException if an error occurs
    692      */
    693     public Object lookupLink (Name name)
    694         throws NamingException
    695     {
    696         Name cname = toCanonicalName(name);
    697
    698         if (cname == null)
    699         {
    700             NamingContext ctx = new NamingContext (_env, _name, _parent, _parser);
    701             ctx._bindings = _bindings;
    702             return ctx;
    703         }
    704         if (cname.size() == 0)
    705             throw new NamingException ("Name is empty");
    706
    707         if (cname.size() == 1)
    708         {
    709             Binding binding = getBinding (cname);
    710             if (binding == null)
    711                 throw new NameNotFoundException();
    712
    713             Object o = binding.getObject();
    714
    715             //handle links by looking up the link
    716             if (o instanceof Reference)
    717             {
    718                 //deference the object
    719                 try
    720                 {
    721                     return NamingManager.getObjectInstance(o, cname.getPrefix(1), this, _env);
    722                 }
    723                 catch (NamingException e)
    724                 {
    725                     throw e;
    726                 }
    727                 catch (Exception e)
    728                 {
    729                     Log.warn("",e);
    730                     throw new NamingException (e.getMessage());
    731                 }
    732             }
    733             else
    734             {
    735                 //object is either a LinkRef which we don't dereference
    736                 //or a plain object in which case spec says we return it
    737                 return o;
    738             }
    739         }
    740
    741
    742         //it is a multipart name, recurse to the first subcontext
    743         String firstComponent = cname.get(0);
    744         Object ctx = null;
    745
    746         if (firstComponent.equals(""))
    747             ctx = this;
    748         else
    749         {
    750             Binding binding = getBinding (firstComponent);
    751             if (binding == null)
    752                 throw new NameNotFoundException ();
    753
    754             ctx = binding.getObject();
    755
    756             if (ctx instanceof Reference)
    757             {
    758                 //deference the object
    759                 try
    760                 {
    761                     ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
    762                 }
    763                 catch (NamingException e)
    764                 {
    765                     throw e;
    766                 }
    767                 catch (Exception e)
    768                 {
    769                     Log.warn("",e);
    770                     throw new NamingException (e.getMessage());
    771                 }
    772             }
    773         }
    774
    775         if (!(ctx instanceof Context))
    776             throw new NotContextException();
    777
    778         return ((Context)ctx).lookup (cname.getSuffix(1));
    779     }
    780
    781
    782     /*------------------------------------------------*/
    783     /**
    784      * Lookup link bound to name
    785      *
    786      * @param name name of link binding
    787      * @return LinkRef or plain object bound at name
    788      * @exception NamingException if an error occurs
    789      */
    790     public Object lookupLink (String name)
    791         throws NamingException
    792     {
    793         return lookupLink (_parser.parse(name));
    794     }
    795
    796
    797     /*------------------------------------------------*/
    798     /**
    799      * List all names bound at Context named by Name
    800      *
    801      * @param name a <code>Name</code> value
    802      * @return a <code>NamingEnumeration</code> value
    803      * @exception NamingException if an error occurs
    804      */
    805     public NamingEnumeration list(Name name)
    806         throws NamingException
    807     {
    808         if(Log.isDebugEnabled())Log.debug("list() on Context="+getName()+" for name="+name);
    809         Name cname = toCanonicalName(name);
    810
    811
    812
    813         if (cname == null)
    814         {
    815             return new NameEnumeration(EMPTY_ENUM);
    816         }
    817
    818
    819         if (cname.size() == 0)
    820         {
    821            return new NameEnumeration (_bindings.elements());
    822         }
    823
    824
    825
    826         //multipart name
    827         String firstComponent = cname.get(0);
    828         Object ctx = null;
    829
    830         if (firstComponent.equals(""))
    831             ctx = this;
    832         else
    833         {
    834             Binding binding = getBinding (firstComponent);
    835             if (binding == null)
    836                 throw new NameNotFoundException ();
    837
    838             ctx = binding.getObject();
    839
    840             if (ctx instanceof Reference)
    841             {
    842                 //deference the object
    843                 if(Log.isDebugEnabled())Log.debug("Dereferencing Reference for "+name.get(0));
    844                 try
    845                 {
    846                     ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
    847                 }
    848                 catch (NamingException e)
    849                 {
    850                     throw e;
    851                 }
    852                 catch (Exception e)
    853                 {
    854                     Log.warn("",e);
    855                     throw new NamingException (e.getMessage());
    856                 }
    857             }
    858         }
    859
    860         if (!(ctx instanceof Context))
    861             throw new NotContextException();
    862
    863         return ((Context)ctx).list (cname.getSuffix(1));
    864     }
    865
    866
    867     /*------------------------------------------------*/
    868     /**
    869      * List all names bound at Context named by Name
    870      *
    871      * @param name a <code>Name</code> value
    872      * @return a <code>NamingEnumeration</code> value
    873      * @exception NamingException if an error occurs
    874      */
    875     public NamingEnumeration list(String name)
    876         throws NamingException
    877     {
    878         return list(_parser.parse(name));
    879     }
    880
    881
    882
    883     /*------------------------------------------------*/
    884     /**
    885      * List all Bindings present at Context named by Name
    886      *
    887      * @param name a <code>Name</code> value
    888      * @return a <code>NamingEnumeration</code> value
    889      * @exception NamingException if an error occurs
    890      */
    891     public NamingEnumeration listBindings(Name name)
    892         throws NamingException
    893     {
    894         Name cname = toCanonicalName (name);
    895
    896         if (cname == null)
    897         {
    898             return new BindingEnumeration(EMPTY_ENUM);
    899         }
    900
    901         if (cname.size() == 0)
    902         {
    903            return new BindingEnumeration (_bindings.elements());
    904         }
    905
    906
    907
    908         //multipart name
    909         String firstComponent = cname.get(0);
    910         Object ctx = null;
    911
    912         //if a name has a leading "/" it is parsed as "" so ignore it by staying
    913         //at this level in the tree
    914         if (firstComponent.equals(""))
    915             ctx = this;
    916         else
    917         {
    918             //it is a non-empty name component
    919             Binding binding = getBinding (firstComponent);
    920             if (binding == null)
    921                 throw new NameNotFoundException ();
    922
    923             ctx = binding.getObject();
    924
    925             if (ctx instanceof Reference)
    926             {
    927                 //deference the object
    928                 try
    929                 {
    930                     ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
    931                 }
    932                 catch (NamingException e)
    933                 {
    934                     throw e;
    935                 }
    936                 catch (Exception e)
    937                 {
    938                     Log.warn("",e);
    939                     throw new NamingException (e.getMessage());
    940                 }
    941             }
    942         }
    943
    944         if (!(ctx instanceof Context))
    945             throw new NotContextException();
    946
    947         return ((Context)ctx).listBindings (cname.getSuffix(1));
    948     }
    949
    950
    951
    952     /*------------------------------------------------*/
    953     /**
    954      * List all Bindings at Name
    955      *
    956      * @param name a <code>String</code> value
    957      * @return a <code>NamingEnumeration</code> value
    958      * @exception NamingException if an error occurs
    959      */
    960     public NamingEnumeration listBindings(String name)
    961         throws NamingException
    962     {
    963         return listBindings (_parser.parse(name));
    964     }
    965
    966
    967     /*------------------------------------------------*/
    968     /**
    969      * Overwrite or create a binding
    970      *
    971      * @param name a <code>Name</code> value
    972      * @param obj an <code>Object</code> value
    973      * @exception NamingException if an error occurs
    974      */
    975     public void rebind(Name name,
    976                        Object obj)
    977         throws NamingException
    978     {
    979         if (isLocked())
    980             throw new NamingException ("This context is immutable");
    981
    982         Name cname = toCanonicalName(name);
    983
    984         if (cname == null)
    985             throw new NamingException ("Name is null");
    986
    987         if (cname.size() == 0)
    988             throw new NamingException ("Name is empty");
    989
    990
    991         //if no subcontexts, just bind it
    992         if (cname.size() == 1)
    993         {
    994             //check if it is a Referenceable
    995             Object objToBind = NamingManager.getStateToBind(obj, name, this, null);
    996             if (objToBind instanceof Referenceable)
    997             {
    998                 objToBind = ((Referenceable)objToBind).getReference();
    999             }
    1000             addBinding (cname, objToBind);
    1001         }
    1002         else
    1003         {
    1004             //walk down the subcontext hierarchy
    1005             if(Log.isDebugEnabled())Log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
    1006
    1007             String firstComponent = cname.get(0);
    1008             Object ctx = null;
    1009
    1010
    1011             if (firstComponent.equals(""))
    1012                 ctx = this;
    1013             else
    1014             {
    1015                 Binding  binding = getBinding (name.get(0));
    1016                 if (binding == null)
    1017                     throw new NameNotFoundException (name.get(0)+ " is not bound");
    1018
    1019                 ctx = binding.getObject();
    1020
    1021
    1022                 if (ctx instanceof Reference)
    1023                 {
    1024                     //deference the object
    1025                     try
    1026                     {
    1027                         ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
    1028                     }
    1029                     catch (NamingException e)
    1030                     {
    1031                         throw e;
    1032                     }
    1033                     catch (Exception e)
    1034                     {
    1035                         Log.warn("",e);
    1036                         throw new NamingException (e.getMessage());
    1037                     }
    1038                 }
    1039             }
    1040
    1041             if (ctx instanceof Context)
    1042             {
    1043                 ((Context)ctx).rebind (cname.getSuffix(1), obj);
    1044             }
    1045             else
    1046                 throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
    1047         }
    1048     }
    1049
    1050
    1051     /*------------------------------------------------*/
    1052     /**
    1053      * Overwrite or create a binding from Name to Object
    1054      *
    1055      * @param name a <code>String</code> value
    1056      * @param obj an <code>Object</code> value
    1057      * @exception NamingException if an error occurs
    1058      */
    1059     public void rebind (String name,
    1060                         Object obj)
    1061         throws NamingException
    1062     {
    1063         rebind (_parser.parse(name), obj);
    1064     }
    1065
    1066     /*------------------------------------------------*/
    1067     /**
    1068      * Not supported.
    1069      *
    1070      * @param name a <code>String</code> value
    1071      * @exception NamingException if an error occurs
    1072      */
    1073     public void unbind (String name)
    1074         throws NamingException
    1075     {
    1076         unbind(_parser.parse(name));
    1077     }
    1078
    1079     /*------------------------------------------------*/
    1080     /**
    1081      * Not supported.
    1082      *
    1083      * @param name a <code>String</code> value
    1084      * @exception NamingException if an error occurs
    1085      */
    1086     public void unbind (Name name)
    1087         throws NamingException
    1088     {
    1089         if (name.size() == 0)
    1090             return;
    1091
    1092
    1093         if (isLocked())
    1094             throw new NamingException ("This context is immutable");
    1095
    1096         Name cname = toCanonicalName(name);
    1097
    1098         if (cname == null)
    1099             throw new NamingException ("Name is null");
    1100
    1101         if (cname.size() == 0)
    1102             throw new NamingException ("Name is empty");
    1103
    1104
    1105         //if no subcontexts, just unbind it
    1106         if (cname.size() == 1)
    1107         {
    1108             removeBinding (cname);
    1109         }
    1110         else
    1111         {
    1112             //walk down the subcontext hierarchy
    1113             if(Log.isDebugEnabled())Log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
    1114
    1115             String firstComponent = cname.get(0);
    1116             Object ctx = null;
    1117
    1118
    1119             if (firstComponent.equals(""))
    1120                 ctx = this;
    1121             else
    1122             {
    1123                 Binding  binding = getBinding (name.get(0));
    1124                 if (binding == null)
    1125                     throw new NameNotFoundException (name.get(0)+ " is not bound");
    1126
    1127                 ctx = binding.getObject();
    1128
    1129
    1130                 if (ctx instanceof Reference)
    1131                 {
    1132                     //deference the object
    1133                     try
    1134                     {
    1135                         ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
    1136                     }
    1137                     catch (NamingException e)
    1138                     {
    1139                         throw e;
    1140                     }
    1141                     catch (Exception e)
    1142                     {
    1143                         Log.warn("",e);
    1144                         throw new NamingException (e.getMessage());
    1145                     }
    1146                 }
    1147             }
    1148
    1149             if (ctx instanceof Context)
    1150             {
    1151                 ((Context)ctx).unbind (cname.getSuffix(1));
    1152             }
    1153             else
    1154                 throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
    1155         }
    1156
    1157     }
    1158
    1159     /*------------------------------------------------*/
    1160     /**
    1161      * Not supported
    1162      *
    1163      * @param oldName a <code>Name</code> value
    1164      * @param newName a <code>Name</code> value
    1165      * @exception NamingException if an error occurs
    1166      */
    1167     public void rename(Name oldName,
    1168                        Name newName)
    1169         throws NamingException
    1170     {
    1171         throw new OperationNotSupportedException();
    1172     }
    1173
    1174
    1175     /*------------------------------------------------*/
    1176     /**
    1177      * Not supported
    1178      *
    1179      * @param oldName a <code>Name</code> value
    1180      * @param newName a <code>Name</code> value
    1181      * @exception NamingException if an error occurs
    1182      */    public void rename(String oldName,
    1183                        String newName)
    1184         throws NamingException
    1185     {
    1186         throw new OperationNotSupportedException();
    1187     }
    1188
    1189
    1190
    1191     /*------------------------------------------------*/
    1192     /** Join two names together. These are treated as
    1193      * CompoundNames.
    1194      *
    1195      * @param name a <code>Name</code> value
    1196      * @param prefix a <code>Name</code> value
    1197      * @return a <code>Name</code> value
    1198      * @exception NamingException if an error occurs
    1199      */
    1200     public Name composeName(Name name,
    1201                             Name prefix)
    1202         throws NamingException
    1203     {
    1204         if (name == null)
    1205             throw new NamingException ("Name cannot be null");
    1206         if (prefix == null)
    1207             throw new NamingException ("Prefix cannot be null");
    1208
    1209         Name compoundName = (CompoundName)prefix.clone();
    1210         compoundName.addAll (name);
    1211         return compoundName;
    1212     }
    1213
    1214
    1215
    1216     /*------------------------------------------------*/
    1217     /** Join two names together. These are treated as
    1218      * CompoundNames.
    1219      *
    1220      * @param name a <code>Name</code> value
    1221      * @param prefix a <code>Name</code> value
    1222      * @return a <code>Name</code> value
    1223      * @exception NamingException if an error occurs
    1224      */
    1225     public String composeName (String name,
    1226                                String prefix)
    1227         throws NamingException
    1228     {
    1229         if (name == null)
    1230             throw new NamingException ("Name cannot be null");
    1231         if (prefix == null)
    1232             throw new NamingException ("Prefix cannot be null");
    1233
    1234         Name compoundName = _parser.parse(prefix);
    1235         compoundName.add (name);
    1236         return compoundName.toString();
    1237     }
    1238
    1239
    1240     /*------------------------------------------------*/
    1241     /**
    1242      * Do nothing
    1243      *
    1244      * @exception NamingException if an error occurs
    1245      */
    1246     public void close ()
    1247         throws NamingException
    1248     {
    1249
    1250
    1251     }
    1252
    1253
    1254     /*------------------------------------------------*/
    1255     /**
    1256      * Return a NameParser for this Context.
    1257      *
    1258      * @param name a <code>Name</code> value
    1259      * @return a <code>NameParser</code> value
    1260      */
    1261     public NameParser getNameParser (Name name)
    1262     {
    1263         return _parser;
    1264     }
    1265
    1266     /*------------------------------------------------*/
    1267     /**
    1268      * Return a NameParser for this Context.
    1269      *
    1270      * @param name a <code>Name</code> value
    1271      * @return a <code>NameParser</code> value
    1272      */
    1273     public NameParser getNameParser (String name)
    1274     {
    1275         return _parser;
    1276     }
    1277
    1278
    1279     /*------------------------------------------------*/
    1280     /**
    1281      * Get the full name of this Context node
    1282      * by visiting it's ancestors back to root.
    1283      *
    1284      * NOTE: if this Context has a URL namespace then
    1285      * the URL prefix will be missing
    1286      *
    1287      * @return the full name of this Context
    1288      * @exception NamingException if an error occurs
    1289      */
    1290     public String getNameInNamespace ()
    1291         throws NamingException
    1292     {
    1293         Name name = _parser.parse("");
    1294
    1295         NamingContext c = this;
    1296         while (c != null)
    1297         {
    1298             String str = c.getName();
    1299             if (str != null)
    1300                 name.add(0, str);
    1301             c = (NamingContext)c.getParent();
    1302         }
    1303         return name.toString();
    1304     }
    1305
    1306
    1307     /*------------------------------------------------*/
    1308     /**
    1309      * Add an environment setting to this Context
    1310      *
    1311      * @param propName name of the property to add
    1312      * @param propVal value of the property to add
    1313      * @return propVal or previous value of the property
    1314      * @exception NamingException if an error occurs
    1315      */
    1316     public Object addToEnvironment(String propName,
    1317                                    Object propVal)
    1318         throws NamingException
    1319     {
    1320         if (isLocked() && !(propName.equals(UNLOCK_PROPERTY)))
    1321             throw new NamingException ("This context is immutable");
    1322
    1323         return _env.put (propName, propVal);
    1324     }
    1325
    1326
    1327     /*------------------------------------------------*/
    1328     /**
    1329      * Remove a property from this Context's environment.
    1330      *
    1331      * @param propName name of property to remove
    1332      * @return value of property or null if it didn't exist
    1333      * @exception NamingException if an error occurs
    1334      */
    1335     public Object removeFromEnvironment(String propName)
    1336         throws NamingException
    1337     {
    1338         if (isLocked())
    1339             throw new NamingException ("This context is immutable");
    1340
    1341         return _env.remove (propName);
    1342     }
    1343
    1344
    1345     /*------------------------------------------------*/
    1346     /**
    1347      * Get the environment of this Context.
    1348      *
    1349      * @return a copy of the environment of this Context.
    1350      */
    1351     public Hashtable getEnvironment ()
    1352     {
    1353         return (Hashtable)_env.clone();
    1354     }
    1355
    1356
    1357     /*------------------------------------------------*/
    1358     /**
    1359      * Add a name to object binding to this Context.
    1360      *
    1361      * @param name a <code>Name</code> value
    1362      * @param obj an <code>Object</code> value
    1363      */
    1364     protected void addBinding (Name name, Object obj)
    1365     {
    1366         String key = name.toString();
    1367         if(Log.isDebugEnabled())Log.debug("Adding binding with key="+key+" obj="+obj+" for context="+_name);
    1368         _bindings.put (key, new Binding (key, obj));
    1369     }
    1370
    1371     /*------------------------------------------------*/
    1372     /**
    1373      * Get a name to object binding from this Context
    1374      *
    1375      * @param name a <code>Name</code> value
    1376      * @return a <code>Binding</code> value
    1377      */
    1378     protected Binding getBinding (Name name)
    1379     {
    1380         if(Log.isDebugEnabled())Log.debug("Looking up binding for "+name.toString()+" for context="+_name);
    1381         return (Binding) _bindings.get(name.toString());
    1382     }
    1383
    1384
    1385     /*------------------------------------------------*/
    1386     /**
    1387      * Get a name to object binding from this Context
    1388      *
    1389      * @param name as a String
    1390      * @return null or the Binding
    1391      */
    1392     protected Binding getBinding (String name)
    1393     {
    1394         if(Log.isDebugEnabled())Log.debug("Looking up binding for "+name+" for context="+_name);
    1395         return (Binding) _bindings.get(name);
    1396     }
    1397
    1398
    1399     protected void removeBinding (Name name)
    1400     {
    1401         String key = name.toString();
    1402         if (Log.isDebugEnabled()) Log.debug("Removing binding with key="+key);
    1403         _bindings.remove(key);
    1404     }
    1405
    1406     /*------------------------------------------------*/
    1407     /**
    1408      * Remove leading or trailing empty components from
    1409      * name. Eg "/comp/env/" -> "comp/env"
    1410      *
    1411      * @param name the name to normalize
    1412      * @return normalized name
    1413      */
    1414     public Name toCanonicalName (Name name)
    1415     {
    1416         Name canonicalName = name;
    1417
    1418         if (name != null)
    1419         {
    1420             if (canonicalName.size() > 1)
    1421             {
    1422                 if (canonicalName.get(0).equals(""))
    1423                     canonicalName = canonicalName.getSuffix(1);
    1424
    1425
    1426                 if (canonicalName.get(canonicalName.size()-1).equals(""))
    1427                     canonicalName = canonicalName.getPrefix(canonicalName.size()-1);
    1428
    1429             }
    1430         }
    1431
    1432         return canonicalName;
    1433     }
    1434
    1435     private boolean isLocked()
    1436     {
    1437        if ((_env.get(LOCK_PROPERTY) == null) && (_env.get(UNLOCK_PROPERTY) == null))
    1438            return false;
    1439
    1440        Object lockKey = _env.get(LOCK_PROPERTY);
    1441        Object unlockKey = _env.get(UNLOCK_PROPERTY);
    1442
    1443        if ((lockKey != null) && (unlockKey != null) && (lockKey.equals(unlockKey)))
    1444            return false;
    1445        return true;
    1446     }
    1447
    1448 }