Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/media/naming/MemoryContext.java


1   /* 
2    * $COPYRIGHT$
3    * $Id: MemoryContext.java,v 1.2 2001/06/04 10:23:21 neuro Exp $
4    *
5    * Date        Author            Changes 
6    * May 20 2001 Remus Pereni      Created
7    */
8   
9   package org.media.naming;
10  
11  import java.io.PrintWriter;
12  import java.util.Hashtable;
13  import java.util.Enumeration;
14  import javax.naming.Context;
15  import javax.naming.Reference;
16  import javax.naming.Referenceable;
17  import javax.naming.LinkRef;
18  import javax.naming.CompositeName;
19  import javax.naming.InitialContext;
20  import javax.naming.NamingEnumeration;
21  import javax.naming.NameParser;
22  import javax.naming.Name;
23  import javax.naming.NamingException;
24  import javax.naming.NotContextException;
25  import javax.naming.NameNotFoundException;
26  import javax.naming.OperationNotSupportedException;
27  import javax.naming.InvalidNameException;
28  import javax.naming.NameAlreadyBoundException;
29  import javax.naming.ContextNotEmptyException;
30  import javax.naming.spi.NamingManager;
31  
32  
33  /**
34   * An in-memory JNDI service provider. Binds objects into a namespace
35   * held entirely in memory, supporting serializable, remoteable and
36   * local objects. The in-memory service provider is particularly useful
37   * for holding resource factories (the JNDI ENC) and exposing run-time
38   * services and configuration objects.
39   * <p>
40   * An instance of {@link MemoryContext} constructed with no environment
41   * attribute will use it's namespace and serve as the root of that namespace.
42   * Such a namespace is no accessible except through the creating context,
43   * and is garbage collected when all such contexts are no longer
44   * referenced. If necessary the root context can be duplicated using
45   * <tt>lookup( "" )</tt>.
46   * <p>
47   * If the environment attribute {@link javax.naming.Context#PROVIDER_URL} is set,
48   * the context will reference a node in a namespace shared by all such
49   * contexts. That tree is statically held in memory for the life time
50   * of the virtual machine.
51   *
52   * <p>
53   * This class was inspired by the tyrex.naming package from the 
54   * <a href="http://tyrex.exolab.org">Tyrex</a> project.
55   * All credits for the good stuff should go to Assaf Arkin and
56   * the <a href="http://www.exolab.org">Exolab</a> group, 
57   * all the bad stuff blame it on 
58   * <a href="mailto:remus@nolimits.ro">me</a> :).
59   * </p>
60   *
61   * @author <a href="remus@nolimits.ro">Remus Pereni</a>
62   * @version $Revision: 1.2 $ $Date: 2001/06/04 10:23:21 $
63   * @see MemoryContextFactory
64   */
65  public class MemoryContext
66      implements Context
67  {
68  
69  
70      /**
71       * Environment attribute to set a context read-only. The value
72       * must be a string equal to <tt>true</tt>. Once the context has
73       * been set read-only, it cannot be reset to read-write.
74       */
75      public static final String ReadOnly = "readOnly";
76  
77  
78      /**
79       * The default name separator for this context is '/'.
80       */
81      public static final String  NameSeparator = "/";
82      
83  
84      /**
85       * The default name parser for this context.
86       */    
87      public static final NameParser DefaultNameParser =
88          new NameParser() {
89              
90              public Name parse( String name )
91                  throws NamingException
92              {
93                  // We only deal with the standard composite names.
94                  return new CompositeName( name );
95              }
96              
97          };
98      
99      
100     /**
101      * Holds the bindings associated with this context. Multiple
102      * contexts may share the same binding. The binding is selected
103      * based on the {@link javax.naming.Context#PROVIDER_URL} attribute. The
104      * context's name in the name space is know to the bindings.
105      */
106     private final MemoryBinding  _bindings;
107 
108 
109     /**
110      * The environment attributes used to construct this context.
111      * Will be passed on to all contexts constructed by this context.
112      */
113     private final Hashtable     _env = new Hashtable();
114 
115 
116     /**
117      * True if this context has been set read-only. Once it has
118      * been set read-only, it cannot revert to writable and all
119      * contexts returns by this context are read-only.
120      */
121     private boolean             _readOnly;
122 
123 
124     /**
125      * Construct a new context with the specified environment
126      * attributes. The environment property {@link javax.naming.Context#PROVIDER_URL}
127      * names the underlying bindings. If the property is absent, the
128      * returned context has it's own binding space which is not shared
129      * with other contexts created in this manner.
130      *
131      * @param env The environment attributes
132      * @throws NotContextException The attribute {@link
133      *   javax.naming.Context#PROVIDER_URL} does not specify a context
134      * @throws InvalidNameException The attribute {@link
135      *   javax.naming.Context#PROVIDER_URL} is an invalid name
136      */
137     public MemoryContext( Hashtable env )
138         throws NamingException
139     {
140         Enumeration enum;
141         String      name;
142         Object      value;
143 
144         // Use addToEnvironment to duplicate the environment variables.
145         // This takes care of setting certain flags appropriately.
146         if ( env != null ) {
147            value = env.get( PROVIDER_URL );
148            if ( value != null ) {
149                name = value.toString();
150                if ( name.length() > 0 )
151                    _bindings = MemoryContextFactory.getBindings( name );
152                else
153                    _bindings = new MemoryBinding();
154            } else
155                _bindings = new MemoryBinding();
156            enum = env.keys();
157            while ( enum.hasMoreElements() ) {
158                name = (String) enum.nextElement();
159                 value = env.get( name );
160                 if ( name.equals( ReadOnly ) )
161                     _readOnly = value.toString().equalsIgnoreCase( "true" );
162                 _env.put( name, value );
163            }
164         } else
165             _bindings = new MemoryBinding();
166     }
167 
168 
169     /**
170      * Construct a new context with the specified bindings and
171      * environment attributes.
172      */
173     MemoryContext( MemoryBinding bindings, Hashtable env )
174     {
175         Enumeration enum;
176         String      name;
177         Object      value;
178 
179         _bindings = bindings;
180 
181         // Use addToEnvironment to duplicate the environment variables.
182         // This takes care of setting certain flags appropriately.
183         if ( env != null ) {
184             enum = env.keys();
185             while ( enum.hasMoreElements() ) {
186                 name = (String) enum.nextElement();
187                 value = env.get( name );
188                 if ( name.equals( ReadOnly ) )
189                     _readOnly = value.toString().equalsIgnoreCase( "true" );
190                 _env.put( name, value );
191             }
192         }
193     }
194 
195 
196     //--------//
197     // Lookup //
198     //--------//
199 
200 
201     public Object lookup( String name )
202         throws NamingException
203     {
204         Object object;
205         String link;
206 
207         // This is a simple case optimization of the composite name lookup.
208         // It only applies if we're looking for a simple name that is
209         // directly reachable in this context, otherwise, we default to the
210         // composite name lookup.
211         object = _bindings.get( name );
212         if ( object != null ) {
213             if ( object instanceof LinkRef ) {
214                 // Found a link reference that we must follow. If the link
215                 // starts with a '.' we use it's name to do a look underneath
216                 // this context. Otherwise, we continue looking from some
217                 // initial context.
218                 link = ( (LinkRef) object ).getLinkName();
219                 if ( link.startsWith( "." ) )
220                     return lookup( link.substring( 1 ) );
221                 else
222                     return NamingManager.getInitialContext( _env ).lookup( link );
223             } else if ( object instanceof MemoryBinding ) {
224                 // If we found a subcontext, we must return a new context
225                 // to represent it and keep the environment set for this
226                 // context (e.g. read-only).
227                 return new MemoryContext( (MemoryBinding) object, _env );
228             } else if ( object instanceof Reference ) {
229                 // Reconstruct a reference.
230                 try {
231                     return NamingManager.getObjectInstance( object, new CompositeName( name ), this, _env );
232                 } catch ( Exception except ) {
233                     throw new NamingException( except.toString() );
234                 }
235             } else {
236                 // Simplest case, just return the bound object.
237                 return object;
238             }
239         } else
240             return internalLookup( new CompositeName( name ), true );
241     }
242 
243 
244     public Object lookup( Name name )
245         throws NamingException
246     {
247         return internalLookup( name, true );
248     }
249 
250 
251     public Object lookupLink( String name )
252         throws NamingException
253     {
254         return internalLookup( new CompositeName( name ), false );
255     }
256 
257 
258     public Object lookupLink( Name name )
259         throws NamingException
260     {
261         return internalLookup( name, false );
262     }
263 
264 
265     private Object internalLookup( Name name, boolean resolveLinkRef )
266         throws NamingException
267     {
268         String        simple;
269         Object        object;
270         MemoryBinding bindings;
271         String        link;
272         
273         // Start this this context's direct binding. As we iterate through
274         // composite names and links, we will change bindings all the time.
275         bindings = _bindings;
276         
277         // This loop is executed for as long as name has more the on part.
278         // At each iteration, the first part of the name is used to lookup
279         // a subcontext and the second part passes on to the iteration.
280         // If a link is found, the link's name is used in the next iteration
281         // step.
282         while ( true ) {
283             
284             // If the first part of the name contains empty parts, we discard
285             // them and keep on looking in this context. If the name is empty,
286             // we create a new context similar to this one.
287             while ( ! name.isEmpty() && name.get( 0 ).length() == 0 )
288                 name = name.getSuffix( 1 );
289             if ( name.isEmpty() )
290                 return new MemoryContext( bindings, _env );
291             
292             // Simple is the first part of the name for a composite name,
293             // for looking up the subcontext, or the last part of the
294             // name for looking up the binding.
295             simple = name.get( 0 );
296             
297             if ( name.size() > 1 ) {
298                 // Composite name, keep looking in subcontext until we
299                 // find the binding.
300                 object = bindings.get( simple );
301                 if ( object instanceof Context ) {
302                     // Found an external context, keep looking in that context.
303                     return ( (Context) object ).lookup( name.getSuffix( 1 ) );
304                 } else if ( object instanceof MemoryBinding ) {
305                     // Found another binding level, keep looking in that one.
306                     bindings = (MemoryBinding) object;
307                 } else {
308                     // Could not find another level for this name part,
309                     // must report that name part is not a subcontext.
310                     throw new NotContextException( simple + " is not a subcontext" );
311                 }
312                 name = name.getSuffix( 1 );
313             } else {
314                 // At this point name.size() == 1 and simple == name.get( 0 ).
315                 object = bindings.get( simple );
316                 if ( object == null )
317                     throw new NameNotFoundException( simple + " not found" );
318                 else if ( object instanceof LinkRef && resolveLinkRef ) {
319                     // Found a link reference that we must follow. If the link
320                     // starts with a '.' we use it's name to do a look underneath
321                     // this context. Otherwise, we continue looking from some
322                     // initial context.
323                     link = ( (LinkRef) object ).getLinkName();
324                     if ( link.startsWith( "." ) ) {
325                         name = new CompositeName( link.substring( 1 ) );
326                         continue; // Reiterate
327                     } else
328                         return NamingManager.getInitialContext( _env ).lookup( link );
329                 } else if ( object instanceof MemoryBinding ) {
330                     // If we found a subcontext, we must return a new context
331                     // to represent it and keep the environment set for this
332                     // context (e.g. read-only).
333                     return new MemoryContext( (MemoryBinding) object, _env );
334               } else if ( object instanceof Reference ) {
335                   // Reconstruct a reference
336                   try {
337                       return NamingManager.getObjectInstance( object, name,
338                                                               new MemoryContext( bindings, _env ), _env );
339                   } catch ( Exception except ) {
340                       throw new NamingException( except.getMessage() );
341                   }
342               } else {
343                   // Simplest case, just return the bound object.
344                   return object;
345               }
346             }
347         }
348     }
349 
350 
351     //---------//
352     // Binding //
353     //---------//
354 
355 
356     public void bind( String name, Object value )
357         throws NamingException
358     {
359         bind( new CompositeName( name ), value );
360     }
361 
362 
363     public void bind( Name name, Object value )
364         throws NamingException
365     {
366         String        simple;
367         MemoryBinding bindings;
368         Object        object;
369         
370         if ( _readOnly )
371             throw new OperationNotSupportedException( "Context is read-only" );
372         
373         if ( value instanceof MemoryContext )
374             value = ( (MemoryContext) value )._bindings;
375 
376         // If the first part of the name contains empty parts, we discard
377         // them and keep on looking in this context.
378         while ( ! name.isEmpty() && name.get( 0 ).length() == 0 )
379             name = name.getSuffix( 1 );
380         if ( name.isEmpty() )
381             throw new InvalidNameException( "Cannot bind empty name" );
382 
383         // Simple is the first part of the name for a composite name,
384         // for looking up the subcontext, or the last part of the
385         // name for looking up the binding.
386         simple = name.get( 0 );
387         bindings = _bindings;
388 
389         while ( name.size() > 1 ) {
390             // Composite name, keep looking in subcontext until we
391             // find the binding.
392             object = bindings.get( simple );
393             if ( object instanceof Context ) {
394                 // Found an external context, keep looking in that context.
395                 ( (Context) object ).bind( name.getSuffix( 1 ), value );
396                 return;
397             } else if ( object instanceof MemoryBinding ) {
398                 // Found another binding level, keep looking in that one.
399                 bindings = (MemoryBinding) object;
400             } else {
401                 // Could not find another level for this name part,
402                 // must report that name part is not a subcontext.
403                 throw new NotContextException( simple + " is not a subcontext" );
404             }
405             name = name.getSuffix( 1 );
406             simple = name.get( 0 );
407         }
408         
409         synchronized ( bindings ) {
410             // At this point name.size() == 1 and simple == name.get( 0 ).
411             if ( bindings.get( simple ) != null )
412                 throw new NameAlreadyBoundException( simple + " already bound, use rebind instead" );
413             if ( value instanceof Referenceable )
414               value = ( (Referenceable) value ).getReference();
415             bindings.put( simple, value );
416         }
417     }
418 
419 
420     public void rebind( String name, Object value )
421         throws NamingException
422     {
423         rebind( new CompositeName( name ), value );
424     }
425 
426 
427     public void rebind( Name name, Object value )
428         throws NamingException
429     {
430         String        simple;
431         MemoryBinding bindings;
432         Object        object;
433         
434         if ( _readOnly )
435             throw new OperationNotSupportedException( "Context is read-only" );
436         
437         if ( value instanceof MemoryContext )
438             value = ( (MemoryContext) value )._bindings;
439         
440         // If the first part of the name contains empty parts, we discard
441         // them and keep on looking in this context.
442         while ( ! name.isEmpty() && name.get( 0 ).length() == 0 )
443             name = name.getSuffix( 1 );
444         if ( name.isEmpty() )
445             throw new InvalidNameException( "Cannot rebind empty name" );
446         
447         // Simple is the first part of the name for a composite name,
448         // for looking up the subcontext, or the last part of the
449         // name for looking up the binding.
450         simple = name.get( 0 );
451         bindings = _bindings;
452         
453         while ( name.size() > 1 ) {
454             // Composite name, keep looking in subcontext until we
455             // find the binding.
456             object = bindings.get( simple );
457             if ( object instanceof Context ) {
458                 // Found an external context, keep looking in that context.
459                 ( (Context) object ).rebind( name.getSuffix( 1 ), value );
460                 return;
461             } else if ( object instanceof MemoryBinding ) {
462                 // Found another binding level, keep looking in that one.
463                 bindings = (MemoryBinding) object;
464             } else {
465                 // Could not find another level for this name part,
466                 // must report that name part is not a subcontext.
467                 throw new NotContextException( simple + " is not a subcontext" );
468             }
469             name = name.getSuffix( 1 );
470             simple = name.get( 0 );
471         }
472         
473         synchronized ( bindings ) {
474             // If the name is direct, we perform the rebinding in
475             // this context. This method is indempotent;
476             if ( value instanceof Referenceable )
477                 value = ( (Referenceable) value ).getReference();
478             bindings.put( simple, value );
479         }
480     }
481 
482 
483     public void unbind( String name )
484         throws NamingException
485     {
486         unbind( new CompositeName( name ) );
487     }
488 
489 
490     public void unbind( Name name )
491         throws NamingException
492     {
493         Object        object;
494         String        simple;
495         MemoryBinding bindings;
496         
497         if ( _readOnly )
498             throw new OperationNotSupportedException( "Context is read-only" );
499         
500         // If the first part of the name contains empty parts, we discard
501         // them and keep on looking in this context.
502         while ( ! name.isEmpty() && name.get( 0 ).length() == 0 )
503             name = name.getSuffix( 1 );
504         if ( name.isEmpty() )
505             throw new InvalidNameException( "Cannot unbind empty name" );
506         
507         // Simple is the first part of the name for a composite name,
508         // for looking up the subcontext, or the last part of the
509         // name for looking up the binding.
510         simple = name.get( 0 );
511         bindings = _bindings;
512         
513         while ( name.size() > 1 ) {
514             // Composite name, keep looking in subcontext until we
515             // find the binding.
516             object = bindings.get( simple );
517             if ( object instanceof Context ) {
518                 // Found an external context, keep looking in that context.
519                 ( (Context) object ).unbind( name.getSuffix( 1 ) );
520                 return;
521             } else if ( object instanceof MemoryBinding ) {
522                 // Found another binding level, keep looking in that one.
523                 bindings = (MemoryBinding) object;
524             } else {
525                 // Could not find another level for this name part,
526                 // must report that name part is not a subcontext.
527                 throw new NotContextException( simple + " is not a subcontext" );
528             }
529             name = name.getSuffix( 1 );
530             simple = name.get( 0 );
531         }
532         
533         synchronized ( bindings ) {
534             // If the name is direct, we perform the unbinding in
535             // this context. This method is indempotent;
536             bindings.remove( simple );
537         }
538     }
539     
540 
541     public void rename( String oldName, String newName )
542         throws NamingException
543     {
544         rename( new CompositeName( oldName ), new CompositeName( newName ) );
545     }
546 
547 
548     public void rename( Name oldName, Name newName )
549         throws NamingException
550     {
551         String        simple;
552         MemoryBinding bindings;
553         Object        object;
554         
555         if ( _readOnly )
556             throw new OperationNotSupportedException( "Context is read-only" );
557         
558         // If the first part of the name contains empty parts, we discard
559         // them and keep on looking in this context.
560         while ( ! oldName.isEmpty() && oldName.get( 0 ).length() == 0 )
561             oldName = oldName.getSuffix( 1 );
562         while ( ! newName.isEmpty() && newName.get( 0 ).length() == 0 )
563             newName = newName.getSuffix( 1 );
564         if ( oldName.isEmpty() || newName.isEmpty() )
565             throw new InvalidNameException( "Cannot rename empty name" );
566 
567         // Simple is the first part of the name for a composite name,
568         // for looking up the subcontext, or the last part of the
569         // name for looking up the binding.
570         simple = newName.get( 0 );
571         bindings = _bindings;
572 
573         while ( newName.size() > 1 ) {
574             // Composite name, keep looking in subcontext until we
575             // find the binding.
576             object = bindings.get( simple );
577             if ( object instanceof Context ) {
578                 // Found an external context, keep looking in that context.
579                 ( (Context) object ).rename( newName.getSuffix( 1 ), oldName );
580                 return;
581             } else if ( object instanceof MemoryBinding ) {
582                 // Found another binding level, keep looking in that one.
583                 bindings = (MemoryBinding) object;
584             } else {
585                 // Could not find another level for this name part,
586                 // must report that name part is not a subcontext.
587                 throw new NotContextException( simple + " is not a subcontext" );
588             }
589             newName = newName.getSuffix( 1 );
590             simple = newName.get( 0 );
591         }
592         
593         // At this point newName.size() == 1, simple == newName.get( 0 )
594         // and the old name should be bound directly to bindings.
595         synchronized ( bindings ) {
596             if ( bindings.get( simple ) != null )
597                 throw new NameAlreadyBoundException( simple + " already bound, use rebind to override" );
598             if ( oldName.size() == 1 ) {
599                 object = bindings.remove( oldName.get( 0 ) );
600                 if ( object == null )
601                     throw new NameNotFoundException( oldName.get( 0 ) + " not found" );
602             } else {
603                 object = lookup( oldName );
604                 unbind( oldName );
605             }
606             bindings.put( simple, object );
607         }
608     }
609 
610 
611     //---------//
612     // Binding //
613     //---------//
614 
615 
616     public NamingEnumeration list( String name )
617         throws NamingException
618     {
619         if ( name.length() == 0 )
620             return _bindings.enumerate( this, true );
621         else
622             return list( new CompositeName( name ) );
623     }
624 
625 
626     public NamingEnumeration list( Name name )
627         throws NamingException
628     {
629         Object        object;
630         String        simple;
631         MemoryBinding bindings;
632         
633         // If the first part of the name contains empty parts, we discard
634         // them and keep on looking in this context.
635         while ( ! name.isEmpty() && name.get( 0 ).length() == 0 )
636             name = name.getSuffix( 1 );
637         if ( name.isEmpty() )
638             return _bindings.enumerate( this, true );
639 
640         // Simple is the first part of the name for a composite name,
641         // for looking up the subcontext, or the last part of the
642         // name for looking up the binding.
643         simple = name.get( 0 );
644         bindings = _bindings;
645 
646         while ( name.size() > 1 ) {
647             // Composite name, keep looking in subcontext until we
648             // find the binding.
649             object = bindings.get( simple );
650             if ( object instanceof Context ) {
651                 // Found an external context, keep looking in that context.
652                 return ( (Context) object ).list( name.getSuffix( 1 ) );
653             } else if ( object instanceof MemoryBinding ) {
654                 // Found another binding level, keep looking in that one.
655                 bindings = (MemoryBinding) object;
656             } else {
657                 // Could not find another level for this name part,
658                 // must report that name part is not a subcontext.
659                 throw new NotContextException( simple + " is not a subcontext" );
660             }
661             name = name.getSuffix( 1 );
662             simple = name.get( 0 );
663         }
664         
665         // The end of the name is either '.' in which case list the
666         // last bindings reached so far, or a name part in which case
667         // lookup that binding and list it.
668         if ( simple.length() == 0 )
669             return bindings.enumerate( this, true );
670         object = bindings.get( simple );
671         if ( object instanceof Context )
672             return ( (Context) object ).list( "" );
673         else if ( object instanceof MemoryBinding )
674             return ( (MemoryBinding) object ).enumerate( this, true );
675         else
676             throw new NotContextException( simple + " is not a subcontext" );
677     }
678 
679     
680     public NamingEnumeration listBindings( String name )
681         throws NamingException
682     {
683         if ( name.length() == 0 )
684             return _bindings.enumerate( this, false );
685         else
686             return listBindings( new CompositeName( name ) );
687     }
688 
689 
690     public NamingEnumeration listBindings( Name name )
691         throws NamingException
692     {
693         Object        object;
694         String        simple;
695         MemoryBinding bindings;
696         
697         // If the first part of the name contains empty parts, we discard
698         // them and keep on looking in this context.
699         while ( ! name.isEmpty() && name.get( 0 ).length() == 0 )
700             name = name.getSuffix( 1 );
701         if ( name.isEmpty() )
702             return _bindings.enumerate( this, false );
703         
704         // Simple is the first part of the name for a composite name,
705         // for looking up the subcontext, or the last part of the
706         // name for looking up the binding.
707         simple = name.get( 0 );
708         bindings = _bindings;
709         
710         while ( name.size() > 1 ) {
711             // Composite name, keep looking in subcontext until we
712             // find the binding.
713             object = bindings.get( simple );
714             if ( object instanceof Context ) {
715                 // Found an external context, keep looking in that context.
716                 return ( (Context) object ).listBindings( name.getSuffix( 1 ) );
717             } else if ( object instanceof MemoryBinding ) {
718                 // Found another binding level, keep looking in that one.
719                 bindings = (MemoryBinding) object;
720             } else {
721                 // Could not find another level for this name part,
722                 // must report that name part is not a subcontext.
723                 throw new NotContextException( simple + " is not a subcontext" );
724             }
725             name = name.getSuffix( 1 );
726             simple = name.get( 0 );
727         }
728         
729         // The end of the name is either '.' in which case list the
730         // last bindings reached so far, or a name part in which case
731         // lookup that binding and list it.
732         if ( simple.length() == 0 )
733             return bindings.enumerate( this, false );
734         object = bindings.get( simple );
735         if ( object instanceof Context )
736             return ( (Context) object ).listBindings( "" );
737         else if ( object instanceof MemoryBinding )
738             return ( (MemoryBinding) object ).enumerate( this, false );
739         else
740             throw new NotContextException( simple + " is not a subcontext" );
741     }
742     
743 
744     //-------------//
745     // Subcontexts //
746     //-------------//
747 
748 
749     public Context createSubcontext( String name )
750         throws NamingException
751     {
752         return createSubcontext( new CompositeName( name ) );
753     }
754 
755 
756     public Context createSubcontext( Name name )
757         throws NamingException
758     {
759         Object        object;
760         String        simple;
761         MemoryBinding bindings;
762         MemoryBinding newBindings;
763         
764         if ( _readOnly )
765             throw new OperationNotSupportedException( "Context is read-only" );
766         
767         // If the first part of the name contains empty parts, we discard
768         // them and keep on looking in this context.
769         while ( ! name.isEmpty() && name.get( 0 ).length() == 0 )
770             name = name.getSuffix( 1 );
771         if ( name.isEmpty() )
772             throw new InvalidNameException( "Subcontext name is empty" );
773         
774         // Simple is the first part of the name for a composite name,
775         // for looking up the subcontext, or the last part of the
776         // name for looking up the binding.
777         simple = name.get( 0 );
778         bindings = _bindings;
779         
780         while ( name.size() > 1 ) {
781             // Composite name, keep looking in subcontext until we
782             // find the binding.
783             object = bindings.get( simple );
784             if ( object instanceof Context ) {
785                 // Found an external context, keep looking in that context.
786                 return ( (Context) object ).createSubcontext( name.getSuffix( 1 ) );
787             } else if ( object instanceof MemoryBinding ) {
788                 // Found another binding level, keep looking in that one.
789                 bindings = (MemoryBinding) object;
790             } else {
791                 // Could not find another level for this name part,
792                 // must report that name part is not a subcontext.
793                 throw new NotContextException( simple + " is not a subcontext" );
794             }
795             name = name.getSuffix( 1 );
796             simple = name.get( 0 );
797         }
798 
799         synchronized ( bindings ) {
800             object = bindings.get( simple );
801             // If subcontext already found, return a new context for
802             // that subcontext.
803             if ( object != null ) {
804                 if ( object instanceof Context )
805                     return (Context) ( (Context) object ).lookup( "" );
806                 else if ( object instanceof MemoryBinding )
807                     return new MemoryContext( (MemoryBinding) object, _env );
808                 else
809                     throw new NameAlreadyBoundException( simple + " already bound" );
810             }
811             // Create a new binding for the subcontex and return a
812             // new context.
813             newBindings = new MemoryBinding();
814             bindings.put( simple, newBindings );
815             return new MemoryContext( newBindings, _env );
816         }
817     }
818 
819     
820     public void destroySubcontext( String name )
821         throws NamingException
822     {
823         destroySubcontext( new CompositeName( name ) );
824     }
825 
826 
827     public void destroySubcontext( Name name )
828         throws NamingException
829     {
830         Object        object;
831         String        simple;
832         MemoryBinding bindings;
833 
834         if ( _readOnly )
835             throw new OperationNotSupportedException( "Context is read-only" );
836 
837         // If the first part of the name contains empty parts, we discard
838         // them and keep on looking in this context.
839         while ( ! name.isEmpty() && name.get( 0 ).length() == 0 )
840             name = name.getSuffix( 1 );
841         if ( name.isEmpty() )
842             throw new InvalidNameException( "Subcontext name is empty" );
843 
844         // Simple is the first part of the name for a composite name,
845         // for looking up the subcontext, or the last part of the
846         // name for looking up the binding.
847         simple = name.get( 0 );
848         bindings = _bindings;
849 
850         while ( name.size() > 1 ) {
851             // Composite name, keep looking in subcontext until we
852             // find the binding.
853             object = bindings.get( simple );
854             if ( object instanceof Context ) {
855                 // Found an external context, keep looking in that context.
856                 ( (Context) object ).destroySubcontext( name.getSuffix( 1 ) );
857                 return;
858             } else if ( object instanceof MemoryBinding ) {
859                 // Found another binding level, keep looking in that one.
860                 bindings = (MemoryBinding) object;
861             } else {
862                 // Could not find another level for this name part,
863                 // must report that name part is not a subcontext.
864                 throw new NotContextException( simple + " is not a subcontext" );
865             }
866             name = name.getSuffix( 1 );
867             simple = name.get( 0 );
868         }
869         
870         synchronized ( bindings ) {
871             object = bindings.get( simple );
872             if ( object == null )
873                 return;
874             if ( object instanceof MemoryBinding ) {
875                 if ( ! ( (MemoryBinding) object ).isEmpty() )
876                     throw new ContextNotEmptyException( simple + " is not empty, cannot destroy" );
877                 ( (MemoryBinding) object ).destroy();
878                 bindings.remove( simple );
879             } else if ( object instanceof Context ) {
880                 ( (Context) object ).close();
881                 bindings.remove( simple );
882             } else
883                 throw new NotContextException( simple + " is not a subcontext" );
884         }
885     }
886 
887 
888     //--------------------//
889     // Naming composition //
890     //--------------------//
891 
892 
893     public NameParser getNameParser( String name )
894         throws NamingException
895     {
896         if ( name.length() == 0 )
897             return DefaultNameParser;
898         return getNameParser( new CompositeName( name ) );
899     }
900 
901 
902     public NameParser getNameParser( Name name )
903         throws NamingException
904     {
905         String        simple;
906         MemoryBinding bindings;
907         Object        object;
908 
909         // If the first part of the name contains empty parts, we discard
910         // them and keep on looking in this context.
911         while ( ! name.isEmpty() && name.get( 0 ).length() == 0 )
912             name = name.getSuffix( 1 );
913         if ( name.isEmpty() )
914             return DefaultNameParser;
915         
916         // Simple is the first part of the name for a composite name,
917         // for looking up the subcontext, or the last part of the
918         // name for looking up the binding.
919         simple = name.get( 0 );
920         bindings = _bindings;
921         
922         while ( name.size() > 1 ) {
923             // Composite name, keep looking in subcontext until we
924             // find the binding.
925             object = bindings.get( simple );
926             if ( object instanceof Context ) {
927                 // Found an external context, keep looking in that context.
928                 return ( (Context) object ).getNameParser( name.getSuffix( 1 ) );
929             } else if ( object instanceof MemoryBinding ) {
930                 // Found another binding level, keep looking in that one.
931                 bindings = (MemoryBinding) object;
932             } else {
933                 // Could not find another level for this name part,
934                 // must report that name part is not a subcontext.
935                 throw new NotContextException( simple + " is not a subcontext" );
936             }
937             name = name.getSuffix( 1 );
938             simple = name.get( 0 );
939         }
940         
941         return DefaultNameParser;
942     }
943 
944 
945     public Name composeName( Name name, Name prefix )
946         throws NamingException
947     {
948         prefix = (Name) prefix.clone();
949         return prefix.addAll( name );
950     }
951 
952 
953     public String composeName( String name, String prefix )
954     {
955         return prefix + NameSeparator + name;
956     }
957 
958 
959     public String getNameInNamespace()
960         throws NamingException
961     {
962         return _bindings.getName();
963     }
964     
965 
966     //-------------//
967     // Environment //
968     //-------------//
969 
970 
971     public Object addToEnvironment( String name, Object value )
972         throws NamingException
973     {
974         boolean readOnly;
975 
976         if ( name.equals( ReadOnly ) ) {
977             readOnly = value.toString().equalsIgnoreCase( "true" );
978             if ( _readOnly && ! readOnly )
979                 throw new OperationNotSupportedException( "Context is read-only" );
980             _readOnly = readOnly;
981         }
982         return _env.put( name, value );
983     }
984 
985     public Hashtable getEnvironment()
986     {
987         return _env;
988     }
989 
990 
991     public Object removeFromEnvironment( String name )
992     {
993         return _env.remove( name );
994     }
995 
996 
997     public void close()
998     {
999         _env.clear();
1000    }
1001
1002
1003    public String toString()
1004    {
1005        if ( _readOnly )
1006            return _bindings.getName() + " (read-only)";
1007        else
1008            return _bindings.getName();
1009    }
1010
1011
1012    /**
1013     * Returns the bindings represented by this context.
1014     * Used when assigning a memory context into the ENC.
1015     */
1016    public MemoryBinding getBindings()
1017    {
1018        return _bindings;
1019    }
1020
1021
1022    void debug( PrintWriter writer )
1023    {
1024        _bindings.debug( writer );
1025    }
1026
1027
1028}
1029
1030
1031