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