1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
19 package org.apache.naming;
20
21 import java.util.HashMap;
22 import java.util.Hashtable;
23 import java.util.Enumeration;
24 import javax.naming.Context;
25 import javax.naming.Name;
26 import javax.naming.LinkRef;
27 import javax.naming.CompositeName;
28 import javax.naming.NameParser;
29 import javax.naming.Referenceable;
30 import javax.naming.Reference;
31 import javax.naming.NamingEnumeration;
32 import javax.naming.NamingException;
33 import javax.naming.NameAlreadyBoundException;
34 import javax.naming.NameNotFoundException;
35 import javax.naming.NotContextException;
36 import javax.naming.InitialContext;
37 import javax.naming.OperationNotSupportedException;
38 import javax.naming.spi.NamingManager;
39
40 /**
41 * Catalina JNDI Context implementation.
42 *
43 * @author Remy Maucherat
44 * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
45 */
46 public class NamingContext implements Context {
47
48
49 // -------------------------------------------------------------- Constants
50
51
52 /**
53 * Name parser for this context.
54 */
55 protected static final NameParser nameParser = new NameParserImpl();
56
57
58 private static org.apache.juli.logging.Log log =
59 org.apache.juli.logging.LogFactory.getLog(NamingContext.class);
60
61
62 // ----------------------------------------------------------- Constructors
63
64
65 /**
66 * Builds a naming context using the given environment.
67 */
68 public NamingContext(Hashtable env, String name)
69 throws NamingException {
70 this.bindings = new HashMap();
71 this.env = new Hashtable();
72 // FIXME ? Could be put in the environment ?
73 this.name = name;
74 // Populating the environment hashtable
75 if (env != null ) {
76 Enumeration envEntries = env.keys();
77 while (envEntries.hasMoreElements()) {
78 String entryName = (String) envEntries.nextElement();
79 addToEnvironment(entryName, env.get(entryName));
80 }
81 }
82 }
83
84
85 /**
86 * Builds a naming context using the given environment.
87 */
88 public NamingContext(Hashtable env, String name, HashMap bindings)
89 throws NamingException {
90 this(env, name);
91 this.bindings = bindings;
92 }
93
94
95 // ----------------------------------------------------- Instance Variables
96
97
98 /**
99 * Environment.
100 */
101 protected Hashtable env;
102
103
104 /**
105 * The string manager for this package.
106 */
107 protected StringManager sm = StringManager.getManager(Constants.Package);
108
109
110 /**
111 * Bindings in this Context.
112 */
113 protected HashMap bindings;
114
115
116 /**
117 * Name of the associated Catalina Context.
118 */
119 protected String name;
120
121
122 // --------------------------------------------------------- Public Methods
123
124
125 // -------------------------------------------------------- Context Methods
126
127
128 /**
129 * Retrieves the named object. If name is empty, returns a new instance
130 * of this context (which represents the same naming context as this
131 * context, but its environment may be modified independently and it may
132 * be accessed concurrently).
133 *
134 * @param name the name of the object to look up
135 * @return the object bound to name
136 * @exception NamingException if a naming exception is encountered
137 */
138 public Object lookup(Name name)
139 throws NamingException {
140 return lookup(name, true);
141 }
142
143
144 /**
145 * Retrieves the named object.
146 *
147 * @param name the name of the object to look up
148 * @return the object bound to name
149 * @exception NamingException if a naming exception is encountered
150 */
151 public Object lookup(String name)
152 throws NamingException {
153 return lookup(new CompositeName(name), true);
154 }
155
156
157 /**
158 * Binds a name to an object. All intermediate contexts and the target
159 * context (that named by all but terminal atomic component of the name)
160 * must already exist.
161 *
162 * @param name the name to bind; may not be empty
163 * @param obj the object to bind; possibly null
164 * @exception NameAlreadyBoundException if name is already bound
165 * @exception InvalidAttributesException if object did not supply all
166 * mandatory attributes
167 * @exception NamingException if a naming exception is encountered
168 */
169 public void bind(Name name, Object obj)
170 throws NamingException {
171 bind(name, obj, false);
172 }
173
174
175 /**
176 * Binds a name to an object.
177 *
178 * @param name the name to bind; may not be empty
179 * @param obj the object to bind; possibly null
180 * @exception NameAlreadyBoundException if name is already bound
181 * @exception InvalidAttributesException if object did not supply all
182 * mandatory attributes
183 * @exception NamingException if a naming exception is encountered
184 */
185 public void bind(String name, Object obj)
186 throws NamingException {
187 bind(new CompositeName(name), obj);
188 }
189
190
191 /**
192 * Binds a name to an object, overwriting any existing binding. All
193 * intermediate contexts and the target context (that named by all but
194 * terminal atomic component of the name) must already exist.
195 * <p>
196 * If the object is a DirContext, any existing attributes associated with
197 * the name are replaced with those of the object. Otherwise, any
198 * existing attributes associated with the name remain unchanged.
199 *
200 * @param name the name to bind; may not be empty
201 * @param obj the object to bind; possibly null
202 * @exception InvalidAttributesException if object did not supply all
203 * mandatory attributes
204 * @exception NamingException if a naming exception is encountered
205 */
206 public void rebind(Name name, Object obj)
207 throws NamingException {
208 bind(name, obj, true);
209 }
210
211
212 /**
213 * Binds a name to an object, overwriting any existing binding.
214 *
215 * @param name the name to bind; may not be empty
216 * @param obj the object to bind; possibly null
217 * @exception InvalidAttributesException if object did not supply all
218 * mandatory attributes
219 * @exception NamingException if a naming exception is encountered
220 */
221 public void rebind(String name, Object obj)
222 throws NamingException {
223 rebind(new CompositeName(name), obj);
224 }
225
226
227 /**
228 * Unbinds the named object. Removes the terminal atomic name in name
229 * from the target context--that named by all but the terminal atomic
230 * part of name.
231 * <p>
232 * This method is idempotent. It succeeds even if the terminal atomic
233 * name is not bound in the target context, but throws
234 * NameNotFoundException if any of the intermediate contexts do not exist.
235 *
236 * @param name the name to bind; may not be empty
237 * @exception NameNotFoundException if an intermediate context does not
238 * exist
239 * @exception NamingException if a naming exception is encountered
240 */
241 public void unbind(Name name)
242 throws NamingException {
243 checkWritable();
244
245 while ((!name.isEmpty()) && (name.get(0).length() == 0))
246 name = name.getSuffix(1);
247 if (name.isEmpty())
248 throw new NamingException
249 (sm.getString("namingContext.invalidName"));
250
251 NamingEntry entry = (NamingEntry) bindings.get(name.get(0));
252
253 if (entry == null) {
254 throw new NameNotFoundException
255 (sm.getString("namingContext.nameNotBound", name.get(0)));
256 }
257
258 if (name.size() > 1) {
259 if (entry.type == NamingEntry.CONTEXT) {
260 ((Context) entry.value).unbind(name.getSuffix(1));
261 } else {
262 throw new NamingException
263 (sm.getString("namingContext.contextExpected"));
264 }
265 } else {
266 bindings.remove(name.get(0));
267 }
268
269 }
270
271
272 /**
273 * Unbinds the named object.
274 *
275 * @param name the name to bind; may not be empty
276 * @exception NameNotFoundException if an intermediate context does not
277 * exist
278 * @exception NamingException if a naming exception is encountered
279 */
280 public void unbind(String name)
281 throws NamingException {
282 unbind(new CompositeName(name));
283 }
284
285
286 /**
287 * Binds a new name to the object bound to an old name, and unbinds the
288 * old name. Both names are relative to this context. Any attributes
289 * associated with the old name become associated with the new name.
290 * Intermediate contexts of the old name are not changed.
291 *
292 * @param oldName the name of the existing binding; may not be empty
293 * @param newName the name of the new binding; may not be empty
294 * @exception NameAlreadyBoundException if newName is already bound
295 * @exception NamingException if a naming exception is encountered
296 */
297 public void rename(Name oldName, Name newName)
298 throws NamingException {
299 Object value = lookup(oldName);
300 bind(newName, value);
301 unbind(oldName);
302 }
303
304
305 /**
306 * Binds a new name to the object bound to an old name, and unbinds the
307 * old name.
308 *
309 * @param oldName the name of the existing binding; may not be empty
310 * @param newName the name of the new binding; may not be empty
311 * @exception NameAlreadyBoundException if newName is already bound
312 * @exception NamingException if a naming exception is encountered
313 */
314 public void rename(String oldName, String newName)
315 throws NamingException {
316 rename(new CompositeName(oldName), new CompositeName(newName));
317 }
318
319
320 /**
321 * Enumerates the names bound in the named context, along with the class
322 * names of objects bound to them. The contents of any subcontexts are
323 * not included.
324 * <p>
325 * If a binding is added to or removed from this context, its effect on
326 * an enumeration previously returned is undefined.
327 *
328 * @param name the name of the context to list
329 * @return an enumeration of the names and class names of the bindings in
330 * this context. Each element of the enumeration is of type NameClassPair.
331 * @exception NamingException if a naming exception is encountered
332 */
333 public NamingEnumeration list(Name name)
334 throws NamingException {
335 // Removing empty parts
336 while ((!name.isEmpty()) && (name.get(0).length() == 0))
337 name = name.getSuffix(1);
338 if (name.isEmpty()) {
339 return new NamingContextEnumeration(bindings.values().iterator());
340 }
341
342 NamingEntry entry = (NamingEntry) bindings.get(name.get(0));
343
344 if (entry == null) {
345 throw new NameNotFoundException
346 (sm.getString("namingContext.nameNotBound", name.get(0)));
347 }
348
349 if (entry.type != NamingEntry.CONTEXT) {
350 throw new NamingException
351 (sm.getString("namingContext.contextExpected"));
352 }
353 return ((Context) entry.value).list(name.getSuffix(1));
354 }
355
356
357 /**
358 * Enumerates the names bound in the named context, along with the class
359 * names of objects bound to them.
360 *
361 * @param name the name of the context to list
362 * @return an enumeration of the names and class names of the bindings in
363 * this context. Each element of the enumeration is of type NameClassPair.
364 * @exception NamingException if a naming exception is encountered
365 */
366 public NamingEnumeration list(String name)
367 throws NamingException {
368 return list(new CompositeName(name));
369 }
370
371
372 /**
373 * Enumerates the names bound in the named context, along with the
374 * objects bound to them. The contents of any subcontexts are not
375 * included.
376 * <p>
377 * If a binding is added to or removed from this context, its effect on
378 * an enumeration previously returned is undefined.
379 *
380 * @param name the name of the context to list
381 * @return an enumeration of the bindings in this context.
382 * Each element of the enumeration is of type Binding.
383 * @exception NamingException if a naming exception is encountered
384 */
385 public NamingEnumeration listBindings(Name name)
386 throws NamingException {
387 // Removing empty parts
388 while ((!name.isEmpty()) && (name.get(0).length() == 0))
389 name = name.getSuffix(1);
390 if (name.isEmpty()) {
391 return new NamingContextBindingsEnumeration(bindings.values().iterator(), this);
392 }
393
394 NamingEntry entry = (NamingEntry) bindings.get(name.get(0));
395
396 if (entry == null) {
397 throw new NameNotFoundException
398 (sm.getString("namingContext.nameNotBound", name.get(0)));
399 }
400
401 if (entry.type != NamingEntry.CONTEXT) {
402 throw new NamingException
403 (sm.getString("namingContext.contextExpected"));
404 }
405 return ((Context) entry.value).listBindings(name.getSuffix(1));
406 }
407
408
409 /**
410 * Enumerates the names bound in the named context, along with the
411 * objects bound to them.
412 *
413 * @param name the name of the context to list
414 * @return an enumeration of the bindings in this context.
415 * Each element of the enumeration is of type Binding.
416 * @exception NamingException if a naming exception is encountered
417 */
418 public NamingEnumeration listBindings(String name)
419 throws NamingException {
420 return listBindings(new CompositeName(name));
421 }
422
423
424 /**
425 * Destroys the named context and removes it from the namespace. Any
426 * attributes associated with the name are also removed. Intermediate
427 * contexts are not destroyed.
428 * <p>
429 * This method is idempotent. It succeeds even if the terminal atomic
430 * name is not bound in the target context, but throws
431 * NameNotFoundException if any of the intermediate contexts do not exist.
432 *
433 * In a federated naming system, a context from one naming system may be
434 * bound to a name in another. One can subsequently look up and perform
435 * operations on the foreign context using a composite name. However, an
436 * attempt destroy the context using this composite name will fail with
437 * NotContextException, because the foreign context is not a "subcontext"
438 * of the context in which it is bound. Instead, use unbind() to remove
439 * the binding of the foreign context. Destroying the foreign context
440 * requires that the destroySubcontext() be performed on a context from
441 * the foreign context's "native" naming system.
442 *
443 * @param name the name of the context to be destroyed; may not be empty
444 * @exception NameNotFoundException if an intermediate context does not
445 * exist
446 * @exception NotContextException if the name is bound but does not name
447 * a context, or does not name a context of the appropriate type
448 */
449 public void destroySubcontext(Name name)
450 throws NamingException {
451
452 checkWritable();
453
454 while ((!name.isEmpty()) && (name.get(0).length() == 0))
455 name = name.getSuffix(1);
456 if (name.isEmpty())
457 throw new NamingException
458 (sm.getString("namingContext.invalidName"));
459
460 NamingEntry entry = (NamingEntry) bindings.get(name.get(0));
461
462 if (entry == null) {
463 throw new NameNotFoundException
464 (sm.getString("namingContext.nameNotBound", name.get(0)));
465 }
466
467 if (name.size() > 1) {
468 if (entry.type == NamingEntry.CONTEXT) {
469 ((Context) entry.value).unbind(name.getSuffix(1));
470 } else {
471 throw new NamingException
472 (sm.getString("namingContext.contextExpected"));
473 }
474 } else {
475 if (entry.type == NamingEntry.CONTEXT) {
476 ((Context) entry.value).close();
477 bindings.remove(name.get(0));
478 } else {
479 throw new NotContextException
480 (sm.getString("namingContext.contextExpected"));
481 }
482 }
483
484 }
485
486
487 /**
488 * Destroys the named context and removes it from the namespace.
489 *
490 * @param name the name of the context to be destroyed; may not be empty
491 * @exception NameNotFoundException if an intermediate context does not
492 * exist
493 * @exception NotContextException if the name is bound but does not name
494 * a context, or does not name a context of the appropriate type
495 */
496 public void destroySubcontext(String name)
497 throws NamingException {
498 destroySubcontext(new CompositeName(name));
499 }
500
501
502 /**
503 * Creates and binds a new context. Creates a new context with the given
504 * name and binds it in the target context (that named by all but
505 * terminal atomic component of the name). All intermediate contexts and
506 * the target context must already exist.
507 *
508 * @param name the name of the context to create; may not be empty
509 * @return the newly created context
510 * @exception NameAlreadyBoundException if name is already bound
511 * @exception InvalidAttributesException if creation of the subcontext
512 * requires specification of mandatory attributes
513 * @exception NamingException if a naming exception is encountered
514 */
515 public Context createSubcontext(Name name)
516 throws NamingException {
517 checkWritable();
518
519 Context newContext = new NamingContext(env, this.name);
520 bind(name, newContext);
521
522 return newContext;
523 }
524
525
526 /**
527 * Creates and binds a new context.
528 *
529 * @param name the name of the context to create; may not be empty
530 * @return the newly created context
531 * @exception NameAlreadyBoundException if name is already bound
532 * @exception InvalidAttributesException if creation of the subcontext
533 * requires specification of mandatory attributes
534 * @exception NamingException if a naming exception is encountered
535 */
536 public Context createSubcontext(String name)
537 throws NamingException {
538 return createSubcontext(new CompositeName(name));
539 }
540
541
542 /**
543 * Retrieves the named object, following links except for the terminal
544 * atomic component of the name. If the object bound to name is not a
545 * link, returns the object itself.
546 *
547 * @param name the name of the object to look up
548 * @return the object bound to name, not following the terminal link
549 * (if any).
550 * @exception NamingException if a naming exception is encountered
551 */
552 public Object lookupLink(Name name)
553 throws NamingException {
554 return lookup(name, false);
555 }
556
557
558 /**
559 * Retrieves the named object, following links except for the terminal
560 * atomic component of the name.
561 *
562 * @param name the name of the object to look up
563 * @return the object bound to name, not following the terminal link
564 * (if any).
565 * @exception NamingException if a naming exception is encountered
566 */
567 public Object lookupLink(String name)
568 throws NamingException {
569 return lookup(new CompositeName(name), false);
570 }
571
572
573 /**
574 * Retrieves the parser associated with the named context. In a
575 * federation of namespaces, different naming systems will parse names
576 * differently. This method allows an application to get a parser for
577 * parsing names into their atomic components using the naming convention
578 * of a particular naming system. Within any single naming system,
579 * NameParser objects returned by this method must be equal (using the
580 * equals() test).
581 *
582 * @param name the name of the context from which to get the parser
583 * @return a name parser that can parse compound names into their atomic
584 * components
585 * @exception NamingException if a naming exception is encountered
586 */
587 public NameParser getNameParser(Name name)
588 throws NamingException {
589
590 while ((!name.isEmpty()) && (name.get(0).length() == 0))
591 name = name.getSuffix(1);
592 if (name.isEmpty())
593 return nameParser;
594
595 if (name.size() > 1) {
596 Object obj = bindings.get(name.get(0));
597 if (obj instanceof Context) {
598 return ((Context) obj).getNameParser(name.getSuffix(1));
599 } else {
600 throw new NotContextException
601 (sm.getString("namingContext.contextExpected"));
602 }
603 }
604
605 return nameParser;
606
607 }
608
609
610 /**
611 * Retrieves the parser associated with the named context.
612 *
613 * @param name the name of the context from which to get the parser
614 * @return a name parser that can parse compound names into their atomic
615 * components
616 * @exception NamingException if a naming exception is encountered
617 */
618 public NameParser getNameParser(String name)
619 throws NamingException {
620 return getNameParser(new CompositeName(name));
621 }
622
623
624 /**
625 * Composes the name of this context with a name relative to this context.
626 * <p>
627 * Given a name (name) relative to this context, and the name (prefix)
628 * of this context relative to one of its ancestors, this method returns
629 * the composition of the two names using the syntax appropriate for the
630 * naming system(s) involved. That is, if name names an object relative
631 * to this context, the result is the name of the same object, but
632 * relative to the ancestor context. None of the names may be null.
633 *
634 * @param name a name relative to this context
635 * @param prefix the name of this context relative to one of its ancestors
636 * @return the composition of prefix and name
637 * @exception NamingException if a naming exception is encountered
638 */
639 public Name composeName(Name name, Name prefix)
640 throws NamingException {
641 prefix = (Name) prefix.clone();
642 return prefix.addAll(name);
643 }
644
645
646 /**
647 * Composes the name of this context with a name relative to this context.
648 *
649 * @param name a name relative to this context
650 * @param prefix the name of this context relative to one of its ancestors
651 * @return the composition of prefix and name
652 * @exception NamingException if a naming exception is encountered
653 */
654 public String composeName(String name, String prefix)
655 throws NamingException {
656 return prefix + "/" + name;
657 }
658
659
660 /**
661 * Adds a new environment property to the environment of this context. If
662 * the property already exists, its value is overwritten.
663 *
664 * @param propName the name of the environment property to add; may not
665 * be null
666 * @param propVal the value of the property to add; may not be null
667 * @exception NamingException if a naming exception is encountered
668 */
669 public Object addToEnvironment(String propName, Object propVal)
670 throws NamingException {
671 return env.put(propName, propVal);
672 }
673
674
675 /**
676 * Removes an environment property from the environment of this context.
677 *
678 * @param propName the name of the environment property to remove;
679 * may not be null
680 * @exception NamingException if a naming exception is encountered
681 */
682 public Object removeFromEnvironment(String propName)
683 throws NamingException {
684 return env.remove(propName);
685 }
686
687
688 /**
689 * Retrieves the environment in effect for this context. See class
690 * description for more details on environment properties.
691 * The caller should not make any changes to the object returned: their
692 * effect on the context is undefined. The environment of this context
693 * may be changed using addToEnvironment() and removeFromEnvironment().
694 *
695 * @return the environment of this context; never null
696 * @exception NamingException if a naming exception is encountered
697 */
698 public Hashtable getEnvironment()
699 throws NamingException {
700 return env;
701 }
702
703
704 /**
705 * Closes this context. This method releases this context's resources
706 * immediately, instead of waiting for them to be released automatically
707 * by the garbage collector.
708 * This method is idempotent: invoking it on a context that has already
709 * been closed has no effect. Invoking any other method on a closed
710 * context is not allowed, and results in undefined behaviour.
711 *
712 * @exception NamingException if a naming exception is encountered
713 */
714 public void close()
715 throws NamingException {
716 env.clear();
717 }
718
719
720 /**
721 * Retrieves the full name of this context within its own namespace.
722 * <p>
723 * Many naming services have a notion of a "full name" for objects in
724 * their respective namespaces. For example, an LDAP entry has a
725 * distinguished name, and a DNS record has a fully qualified name. This
726 * method allows the client application to retrieve this name. The string
727 * returned by this method is not a JNDI composite name and should not be
728 * passed directly to context methods. In naming systems for which the
729 * notion of full name does not make sense,
730 * OperationNotSupportedException is thrown.
731 *
732 * @return this context's name in its own namespace; never null
733 * @exception OperationNotSupportedException if the naming system does
734 * not have the notion of a full name
735 * @exception NamingException if a naming exception is encountered
736 */
737 public String getNameInNamespace()
738 throws NamingException {
739 throw new OperationNotSupportedException
740 (sm.getString("namingContext.noAbsoluteName"));
741 //FIXME ?
742 }
743
744
745 // ------------------------------------------------------ Protected Methods
746
747
748 /**
749 * Retrieves the named object.
750 *
751 * @param name the name of the object to look up
752 * @param resolveLinks If true, the links will be resolved
753 * @return the object bound to name
754 * @exception NamingException if a naming exception is encountered
755 */
756 protected Object lookup(Name name, boolean resolveLinks)
757 throws NamingException {
758
759 // Removing empty parts
760 while ((!name.isEmpty()) && (name.get(0).length() == 0))
761 name = name.getSuffix(1);
762 if (name.isEmpty()) {
763 // If name is empty, a newly allocated naming context is returned
764 return new NamingContext(env, this.name, bindings);
765 }
766
767 NamingEntry entry = (NamingEntry) bindings.get(name.get(0));
768
769 if (entry == null) {
770 throw new NameNotFoundException
771 (sm.getString("namingContext.nameNotBound", name.get(0)));
772 }
773
774 if (name.size() > 1) {
775 // If the size of the name is greater that 1, then we go through a
776 // number of subcontexts.
777 if (entry.type != NamingEntry.CONTEXT) {
778 throw new NamingException
779 (sm.getString("namingContext.contextExpected"));
780 }
781 return ((Context) entry.value).lookup(name.getSuffix(1));
782 } else {
783 if ((resolveLinks) && (entry.type == NamingEntry.LINK_REF)) {
784 String link = ((LinkRef) entry.value).getLinkName();
785 if (link.startsWith(".")) {
786 // Link relative to this context
787 return lookup(link.substring(1));
788 } else {
789 return (new InitialContext(env)).lookup(link);
790 }
791 } else if (entry.type == NamingEntry.REFERENCE) {
792 try {
793 Object obj = NamingManager.getObjectInstance
794 (entry.value, name, this, env);
795 if (obj != null) {
796 entry.value = obj;
797 entry.type = NamingEntry.ENTRY;
798 }
799 return obj;
800 } catch (NamingException e) {
801 throw e;
802 } catch (Exception e) {
803 log.warn(sm.getString
804 ("namingContext.failResolvingReference"), e);
805 throw new NamingException(e.getMessage());
806 }
807 } else {
808 return entry.value;
809 }
810 }
811
812 }
813
814
815 /**
816 * Binds a name to an object. All intermediate contexts and the target
817 * context (that named by all but terminal atomic component of the name)
818 * must already exist.
819 *
820 * @param name the name to bind; may not be empty
821 * @param obj the object to bind; possibly null
822 * @param rebind if true, then perform a rebind (ie, overwrite)
823 * @exception NameAlreadyBoundException if name is already bound
824 * @exception InvalidAttributesException if object did not supply all
825 * mandatory attributes
826 * @exception NamingException if a naming exception is encountered
827 */
828 protected void bind(Name name, Object obj, boolean rebind)
829 throws NamingException {
830
831 checkWritable();
832
833 while ((!name.isEmpty()) && (name.get(0).length() == 0))
834 name = name.getSuffix(1);
835 if (name.isEmpty())
836 throw new NamingException
837 (sm.getString("namingContext.invalidName"));
838
839 NamingEntry entry = (NamingEntry) bindings.get(name.get(0));
840
841 if (name.size() > 1) {
842 if (entry == null) {
843 throw new NameNotFoundException
844 (sm.getString("namingContext.nameNotBound", name.get(0)));
845 }
846 if (entry.type == NamingEntry.CONTEXT) {
847 if (rebind) {
848 ((Context) entry.value).rebind(name.getSuffix(1), obj);
849 } else {
850 ((Context) entry.value).bind(name.getSuffix(1), obj);
851 }
852 } else {
853 throw new NamingException
854 (sm.getString("namingContext.contextExpected"));
855 }
856 } else {
857 if ((!rebind) && (entry != null)) {
858 throw new NameAlreadyBoundException
859 (sm.getString("namingContext.alreadyBound", name.get(0)));
860 } else {
861 // Getting the type of the object and wrapping it within a new
862 // NamingEntry
863 Object toBind =
864 NamingManager.getStateToBind(obj, name, this, env);
865 if (toBind instanceof Context) {
866 entry = new NamingEntry(name.get(0), toBind,
867 NamingEntry.CONTEXT);
868 } else if (toBind instanceof LinkRef) {
869 entry = new NamingEntry(name.get(0), toBind,
870 NamingEntry.LINK_REF);
871 } else if (toBind instanceof Reference) {
872 entry = new NamingEntry(name.get(0), toBind,
873 NamingEntry.REFERENCE);
874 } else if (toBind instanceof Referenceable) {
875 toBind = ((Referenceable) toBind).getReference();
876 entry = new NamingEntry(name.get(0), toBind,
877 NamingEntry.REFERENCE);
878 } else {
879 entry = new NamingEntry(name.get(0), toBind,
880 NamingEntry.ENTRY);
881 }
882 bindings.put(name.get(0), entry);
883 }
884 }
885
886 }
887
888
889 /**
890 * Returns true if writing is allowed on this context.
891 */
892 protected boolean isWritable() {
893 return ContextAccessController.isWritable(name);
894 }
895
896
897 /**
898 * Throws a naming exception is Context is not writable.
899 */
900 protected void checkWritable()
901 throws NamingException {
902 if (!isWritable())
903 throw new NamingException(sm.getString("namingContext.readOnly"));
904 }
905
906
907 }
908