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