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