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.Hashtable;
021: import javax.naming.Context;
022: import javax.naming.Name;
023: import javax.naming.NameParser;
024: import javax.naming.NamingEnumeration;
025: import javax.naming.NamingException;
026:
027: /**
028: * Catalina JNDI Context implementation.
029: *
030: * @author Remy Maucherat
031: * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
032: */
033:
034: public class SelectorContext implements Context {
035:
036: // -------------------------------------------------------------- Constants
037:
038: /**
039: * Namespace URL.
040: */
041: public static final String prefix = "java:";
042:
043: /**
044: * Namespace URL length.
045: */
046: public static final int prefixLength = prefix.length();
047:
048: /**
049: * Initial context prefix.
050: */
051: public static final String IC_PREFIX = "IC_";
052:
053: // ----------------------------------------------------------- Constructors
054:
055: /**
056: * Builds a Catalina selector context using the given environment.
057: */
058: public SelectorContext(Hashtable env) {
059: this .env = env;
060: }
061:
062: /**
063: * Builds a Catalina selector context using the given environment.
064: */
065: public SelectorContext(Hashtable env, boolean initialContext) {
066: this (env);
067: this .initialContext = initialContext;
068: }
069:
070: // ----------------------------------------------------- Instance Variables
071:
072: /**
073: * Environment.
074: */
075: protected Hashtable env;
076:
077: /**
078: * The string manager for this package.
079: */
080: protected StringManager sm = StringManager
081: .getManager(Constants.Package);
082:
083: /**
084: * Request for an initial context.
085: */
086: protected boolean initialContext = false;
087:
088: // --------------------------------------------------------- Public Methods
089:
090: // -------------------------------------------------------- Context Methods
091:
092: /**
093: * Retrieves the named object. If name is empty, returns a new instance
094: * of this context (which represents the same naming context as this
095: * context, but its environment may be modified independently and it may
096: * be accessed concurrently).
097: *
098: * @param name the name of the object to look up
099: * @return the object bound to name
100: * @exception NamingException if a naming exception is encountered
101: */
102: public Object lookup(Name name) throws NamingException {
103: // Strip the URL header
104: // Find the appropriate NamingContext according to the current bindings
105: // Execute the lookup on that context
106: return getBoundContext().lookup(parseName(name));
107: }
108:
109: /**
110: * Retrieves the named object.
111: *
112: * @param name the name of the object to look up
113: * @return the object bound to name
114: * @exception NamingException if a naming exception is encountered
115: */
116: public Object lookup(String name) throws NamingException {
117: // Strip the URL header
118: // Find the appropriate NamingContext according to the current bindings
119: // Execute the lookup on that context
120: return getBoundContext().lookup(parseName(name));
121: }
122:
123: /**
124: * Binds a name to an object. All intermediate contexts and the target
125: * context (that named by all but terminal atomic component of the name)
126: * must already exist.
127: *
128: * @param name the name to bind; may not be empty
129: * @param obj the object to bind; possibly null
130: * @exception NameAlreadyBoundException if name is already bound
131: * @exception InvalidAttributesException if object did not supply all
132: * mandatory attributes
133: * @exception NamingException if a naming exception is encountered
134: */
135: public void bind(Name name, Object obj) throws NamingException {
136: getBoundContext().bind(parseName(name), obj);
137: }
138:
139: /**
140: * Binds a name to an object.
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(String name, Object obj) throws NamingException {
150: getBoundContext().bind(parseName(name), obj);
151: }
152:
153: /**
154: * Binds a name to an object, overwriting any existing binding. All
155: * intermediate contexts and the target context (that named by all but
156: * terminal atomic component of the name) must already exist.
157: * <p>
158: * If the object is a DirContext, any existing attributes associated with
159: * the name are replaced with those of the object. Otherwise, any
160: * existing attributes associated with the name remain unchanged.
161: *
162: * @param name the name to bind; may not be empty
163: * @param obj the object to bind; possibly null
164: * @exception InvalidAttributesException if object did not supply all
165: * mandatory attributes
166: * @exception NamingException if a naming exception is encountered
167: */
168: public void rebind(Name name, Object obj) throws NamingException {
169: getBoundContext().rebind(parseName(name), obj);
170: }
171:
172: /**
173: * Binds a name to an object, overwriting any existing binding.
174: *
175: * @param name the name to bind; may not be empty
176: * @param obj the object to bind; possibly null
177: * @exception InvalidAttributesException if object did not supply all
178: * mandatory attributes
179: * @exception NamingException if a naming exception is encountered
180: */
181: public void rebind(String name, Object obj) throws NamingException {
182: getBoundContext().rebind(parseName(name), obj);
183: }
184:
185: /**
186: * Unbinds the named object. Removes the terminal atomic name in name
187: * from the target context--that named by all but the terminal atomic
188: * part of name.
189: * <p>
190: * This method is idempotent. It succeeds even if the terminal atomic
191: * name is not bound in the target context, but throws
192: * NameNotFoundException if any of the intermediate contexts do not exist.
193: *
194: * @param name the name to bind; may not be empty
195: * @exception NameNotFoundException if an intermediate context does not
196: * exist
197: * @exception NamingException if a naming exception is encountered
198: */
199: public void unbind(Name name) throws NamingException {
200: getBoundContext().unbind(parseName(name));
201: }
202:
203: /**
204: * Unbinds the named object.
205: *
206: * @param name the name to bind; may not be empty
207: * @exception NameNotFoundException if an intermediate context does not
208: * exist
209: * @exception NamingException if a naming exception is encountered
210: */
211: public void unbind(String name) throws NamingException {
212: getBoundContext().unbind(parseName(name));
213: }
214:
215: /**
216: * Binds a new name to the object bound to an old name, and unbinds the
217: * old name. Both names are relative to this context. Any attributes
218: * associated with the old name become associated with the new name.
219: * Intermediate contexts of the old name are not changed.
220: *
221: * @param oldName the name of the existing binding; may not be empty
222: * @param newName the name of the new binding; may not be empty
223: * @exception NameAlreadyBoundException if newName is already bound
224: * @exception NamingException if a naming exception is encountered
225: */
226: public void rename(Name oldName, Name newName)
227: throws NamingException {
228: getBoundContext()
229: .rename(parseName(oldName), parseName(newName));
230: }
231:
232: /**
233: * Binds a new name to the object bound to an old name, and unbinds the
234: * old name.
235: *
236: * @param oldName the name of the existing binding; may not be empty
237: * @param newName the name of the new binding; may not be empty
238: * @exception NameAlreadyBoundException if newName is already bound
239: * @exception NamingException if a naming exception is encountered
240: */
241: public void rename(String oldName, String newName)
242: throws NamingException {
243: getBoundContext()
244: .rename(parseName(oldName), parseName(newName));
245: }
246:
247: /**
248: * Enumerates the names bound in the named context, along with the class
249: * names of objects bound to them. The contents of any subcontexts are
250: * not included.
251: * <p>
252: * If a binding is added to or removed from this context, its effect on
253: * an enumeration previously returned is undefined.
254: *
255: * @param name the name of the context to list
256: * @return an enumeration of the names and class names of the bindings in
257: * this context. Each element of the enumeration is of type NameClassPair.
258: * @exception NamingException if a naming exception is encountered
259: */
260: public NamingEnumeration list(Name name) throws NamingException {
261: return getBoundContext().list(parseName(name));
262: }
263:
264: /**
265: * Enumerates the names bound in the named context, along with the class
266: * names of objects bound to them.
267: *
268: * @param name the name of the context to list
269: * @return an enumeration of the names and class names of the bindings in
270: * this context. Each element of the enumeration is of type NameClassPair.
271: * @exception NamingException if a naming exception is encountered
272: */
273: public NamingEnumeration list(String name) throws NamingException {
274: return getBoundContext().list(parseName(name));
275: }
276:
277: /**
278: * Enumerates the names bound in the named context, along with the
279: * objects bound to them. The contents of any subcontexts are not
280: * included.
281: * <p>
282: * If a binding is added to or removed from this context, its effect on
283: * an enumeration previously returned is undefined.
284: *
285: * @param name the name of the context to list
286: * @return an enumeration of the bindings in this context.
287: * Each element of the enumeration is of type Binding.
288: * @exception NamingException if a naming exception is encountered
289: */
290: public NamingEnumeration listBindings(Name name)
291: throws NamingException {
292: return getBoundContext().listBindings(parseName(name));
293: }
294:
295: /**
296: * Enumerates the names bound in the named context, along with the
297: * objects bound to them.
298: *
299: * @param name the name of the context to list
300: * @return an enumeration of the bindings in this context.
301: * Each element of the enumeration is of type Binding.
302: * @exception NamingException if a naming exception is encountered
303: */
304: public NamingEnumeration listBindings(String name)
305: throws NamingException {
306: return getBoundContext().listBindings(parseName(name));
307: }
308:
309: /**
310: * Destroys the named context and removes it from the namespace. Any
311: * attributes associated with the name are also removed. Intermediate
312: * contexts are not destroyed.
313: * <p>
314: * This method is idempotent. It succeeds even if the terminal atomic
315: * name is not bound in the target context, but throws
316: * NameNotFoundException if any of the intermediate contexts do not exist.
317: *
318: * In a federated naming system, a context from one naming system may be
319: * bound to a name in another. One can subsequently look up and perform
320: * operations on the foreign context using a composite name. However, an
321: * attempt destroy the context using this composite name will fail with
322: * NotContextException, because the foreign context is not a "subcontext"
323: * of the context in which it is bound. Instead, use unbind() to remove
324: * the binding of the foreign context. Destroying the foreign context
325: * requires that the destroySubcontext() be performed on a context from
326: * the foreign context's "native" naming system.
327: *
328: * @param name the name of the context to be destroyed; may not be empty
329: * @exception NameNotFoundException if an intermediate context does not
330: * exist
331: * @exception NotContextException if the name is bound but does not name
332: * a context, or does not name a context of the appropriate type
333: */
334: public void destroySubcontext(Name name) throws NamingException {
335: getBoundContext().destroySubcontext(parseName(name));
336: }
337:
338: /**
339: * Destroys the named context and removes it from the namespace.
340: *
341: * @param name the name of the context to be destroyed; may not be empty
342: * @exception NameNotFoundException if an intermediate context does not
343: * exist
344: * @exception NotContextException if the name is bound but does not name
345: * a context, or does not name a context of the appropriate type
346: */
347: public void destroySubcontext(String name) throws NamingException {
348: getBoundContext().destroySubcontext(parseName(name));
349: }
350:
351: /**
352: * Creates and binds a new context. Creates a new context with the given
353: * name and binds it in the target context (that named by all but
354: * terminal atomic component of the name). All intermediate contexts and
355: * the target context must already exist.
356: *
357: * @param name the name of the context to create; may not be empty
358: * @return the newly created context
359: * @exception NameAlreadyBoundException if name is already bound
360: * @exception InvalidAttributesException if creation of the subcontext
361: * requires specification of mandatory attributes
362: * @exception NamingException if a naming exception is encountered
363: */
364: public Context createSubcontext(Name name) throws NamingException {
365: return getBoundContext().createSubcontext(parseName(name));
366: }
367:
368: /**
369: * Creates and binds a new context.
370: *
371: * @param name the name of the context to create; may not be empty
372: * @return the newly created context
373: * @exception NameAlreadyBoundException if name is already bound
374: * @exception InvalidAttributesException if creation of the subcontext
375: * requires specification of mandatory attributes
376: * @exception NamingException if a naming exception is encountered
377: */
378: public Context createSubcontext(String name) throws NamingException {
379: return getBoundContext().createSubcontext(parseName(name));
380: }
381:
382: /**
383: * Retrieves the named object, following links except for the terminal
384: * atomic component of the name. If the object bound to name is not a
385: * link, returns the object itself.
386: *
387: * @param name the name of the object to look up
388: * @return the object bound to name, not following the terminal link
389: * (if any).
390: * @exception NamingException if a naming exception is encountered
391: */
392: public Object lookupLink(Name name) throws NamingException {
393: return getBoundContext().lookupLink(parseName(name));
394: }
395:
396: /**
397: * Retrieves the named object, following links except for the terminal
398: * atomic component of the name.
399: *
400: * @param name the name of the object to look up
401: * @return the object bound to name, not following the terminal link
402: * (if any).
403: * @exception NamingException if a naming exception is encountered
404: */
405: public Object lookupLink(String name) throws NamingException {
406: return getBoundContext().lookupLink(parseName(name));
407: }
408:
409: /**
410: * Retrieves the parser associated with the named context. In a
411: * federation of namespaces, different naming systems will parse names
412: * differently. This method allows an application to get a parser for
413: * parsing names into their atomic components using the naming convention
414: * of a particular naming system. Within any single naming system,
415: * NameParser objects returned by this method must be equal (using the
416: * equals() test).
417: *
418: * @param name the name of the context from which to get the parser
419: * @return a name parser that can parse compound names into their atomic
420: * components
421: * @exception NamingException if a naming exception is encountered
422: */
423: public NameParser getNameParser(Name name) throws NamingException {
424: return getBoundContext().getNameParser(parseName(name));
425: }
426:
427: /**
428: * Retrieves the parser associated with the named context.
429: *
430: * @param name the name of the context from which to get the parser
431: * @return a name parser that can parse compound names into their atomic
432: * components
433: * @exception NamingException if a naming exception is encountered
434: */
435: public NameParser getNameParser(String name) throws NamingException {
436: return getBoundContext().getNameParser(parseName(name));
437: }
438:
439: /**
440: * Composes the name of this context with a name relative to this context.
441: * <p>
442: * Given a name (name) relative to this context, and the name (prefix)
443: * of this context relative to one of its ancestors, this method returns
444: * the composition of the two names using the syntax appropriate for the
445: * naming system(s) involved. That is, if name names an object relative
446: * to this context, the result is the name of the same object, but
447: * relative to the ancestor context. None of the names may be null.
448: *
449: * @param name a name relative to this context
450: * @param prefix the name of this context relative to one of its ancestors
451: * @return the composition of prefix and name
452: * @exception NamingException if a naming exception is encountered
453: */
454: public Name composeName(Name name, Name prefix)
455: throws NamingException {
456: prefix = (Name) prefix.clone();
457: return prefix.addAll(name);
458: }
459:
460: /**
461: * Composes the name of this context with a name relative to this context.
462: *
463: * @param name a name relative to this context
464: * @param prefix the name of this context relative to one of its ancestors
465: * @return the composition of prefix and name
466: * @exception NamingException if a naming exception is encountered
467: */
468: public String composeName(String name, String prefix)
469: throws NamingException {
470: return prefix + "/" + name;
471: }
472:
473: /**
474: * Adds a new environment property to the environment of this context. If
475: * the property already exists, its value is overwritten.
476: *
477: * @param propName the name of the environment property to add; may not
478: * be null
479: * @param propVal the value of the property to add; may not be null
480: * @exception NamingException if a naming exception is encountered
481: */
482: public Object addToEnvironment(String propName, Object propVal)
483: throws NamingException {
484: return getBoundContext().addToEnvironment(propName, propVal);
485: }
486:
487: /**
488: * Removes an environment property from the environment of this context.
489: *
490: * @param propName the name of the environment property to remove;
491: * may not be null
492: * @exception NamingException if a naming exception is encountered
493: */
494: public Object removeFromEnvironment(String propName)
495: throws NamingException {
496: return getBoundContext().removeFromEnvironment(propName);
497: }
498:
499: /**
500: * Retrieves the environment in effect for this context. See class
501: * description for more details on environment properties.
502: * The caller should not make any changes to the object returned: their
503: * effect on the context is undefined. The environment of this context
504: * may be changed using addToEnvironment() and removeFromEnvironment().
505: *
506: * @return the environment of this context; never null
507: * @exception NamingException if a naming exception is encountered
508: */
509: public Hashtable getEnvironment() throws NamingException {
510: return getBoundContext().getEnvironment();
511: }
512:
513: /**
514: * Closes this context. This method releases this context's resources
515: * immediately, instead of waiting for them to be released automatically
516: * by the garbage collector.
517: * This method is idempotent: invoking it on a context that has already
518: * been closed has no effect. Invoking any other method on a closed
519: * context is not allowed, and results in undefined behaviour.
520: *
521: * @exception NamingException if a naming exception is encountered
522: */
523: public void close() throws NamingException {
524: getBoundContext().close();
525: }
526:
527: /**
528: * Retrieves the full name of this context within its own namespace.
529: * <p>
530: * Many naming services have a notion of a "full name" for objects in
531: * their respective namespaces. For example, an LDAP entry has a
532: * distinguished name, and a DNS record has a fully qualified name. This
533: * method allows the client application to retrieve this name. The string
534: * returned by this method is not a JNDI composite name and should not be
535: * passed directly to context methods. In naming systems for which the
536: * notion of full name does not make sense,
537: * OperationNotSupportedException is thrown.
538: *
539: * @return this context's name in its own namespace; never null
540: * @exception OperationNotSupportedException if the naming system does
541: * not have the notion of a full name
542: * @exception NamingException if a naming exception is encountered
543: */
544: public String getNameInNamespace() throws NamingException {
545: return prefix;
546: }
547:
548: // ------------------------------------------------------ Protected Methods
549:
550: /**
551: * Get the bound context.
552: */
553: protected Context getBoundContext() throws NamingException {
554:
555: if (initialContext) {
556: String ICName = IC_PREFIX;
557: if (ContextBindings.isThreadBound()) {
558: ICName += ContextBindings.getThreadName();
559: } else if (ContextBindings.isClassLoaderBound()) {
560: ICName += ContextBindings.getClassLoaderName();
561: }
562: Context initialContext = ContextBindings.getContext(ICName);
563: if (initialContext == null) {
564: // Allocating a new context and binding it to the appropriate
565: // name
566: initialContext = new NamingContext(env, ICName);
567: ContextBindings.bindContext(ICName, initialContext);
568: }
569: return initialContext;
570: } else {
571: if (ContextBindings.isThreadBound()) {
572: return ContextBindings.getThread();
573: } else {
574: return ContextBindings.getClassLoader();
575: }
576: }
577:
578: }
579:
580: /**
581: * Strips the URL header.
582: *
583: * @return the parsed name
584: * @exception NamingException if there is no "java:" header or if no
585: * naming context has been bound to this thread
586: */
587: protected String parseName(String name) throws NamingException {
588:
589: if ((!initialContext) && (name.startsWith(prefix))) {
590: return (name.substring(prefixLength));
591: } else {
592: if (initialContext) {
593: return (name);
594: } else {
595: throw new NamingException(sm
596: .getString("selectorContext.noJavaUrl"));
597: }
598: }
599:
600: }
601:
602: /**
603: * Strips the URL header.
604: *
605: * @return the parsed name
606: * @exception NamingException if there is no "java:" header or if no
607: * naming context has been bound to this thread
608: */
609: protected Name parseName(Name name) throws NamingException {
610:
611: if ((!initialContext) && (!name.isEmpty())
612: && (name.get(0).equals(prefix))) {
613: return (name.getSuffix(1));
614: } else {
615: if (initialContext) {
616: return (name);
617: } else {
618: throw new NamingException(sm
619: .getString("selectorContext.noJavaUrl"));
620: }
621: }
622:
623: }
624:
625: }
|