View Javadoc

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