001: /**
002: * EasyBeans
003: * Copyright (C) 2006 Bull S.A.S.
004: * Contact: easybeans@ow2.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: ContextImpl.java 1970 2007-10-16 11:49:25Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.ow2.easybeans.naming.context;
025:
026: import java.util.Hashtable;
027:
028: import javax.naming.Binding;
029: import javax.naming.CompositeName;
030: import javax.naming.Context;
031: import javax.naming.InitialContext;
032: import javax.naming.InvalidNameException;
033: import javax.naming.LinkRef;
034: import javax.naming.Name;
035: import javax.naming.NameAlreadyBoundException;
036: import javax.naming.NameClassPair;
037: import javax.naming.NameNotFoundException;
038: import javax.naming.NameParser;
039: import javax.naming.NamingEnumeration;
040: import javax.naming.NamingException;
041: import javax.naming.NotContextException;
042: import javax.naming.OperationNotSupportedException;
043: import javax.naming.RefAddr;
044: import javax.naming.Reference;
045:
046: import org.ow2.util.log.Log;
047: import org.ow2.util.log.LogFactory;
048:
049: /**
050: * Implementation of Context interface.
051: * @author Florent Benoit
052: */
053: public class ContextImpl implements Context {
054:
055: /**
056: * Logger.
057: */
058: private static Log logger = LogFactory.getLog(ContextImpl.class);
059:
060: /**
061: * Environment.
062: */
063: private Hashtable environment = null;
064:
065: /**
066: * Bindings (Name <--> Object).
067: */
068: private Hashtable<String, Object> bindings = new Hashtable<String, Object>();
069:
070: /**
071: * Parser.
072: */
073: private static NameParser myParser = new JavaNameParser();
074:
075: /**
076: * Naming id.
077: */
078: private String compId;
079:
080: /**
081: * Constructor.
082: * @param id id of the context.
083: * @param env initial environment.
084: */
085: public ContextImpl(final String id,
086: final Hashtable<Object, Object> env) {
087: if (env != null) {
088: // clone env to be able to change it.
089: environment = (Hashtable) (env.clone());
090: } else {
091: environment = new Hashtable<Object, Object>();
092: }
093: compId = id;
094: }
095:
096: /**
097: * Constructor.
098: * @param id id of the context.
099: */
100: @SuppressWarnings("unchecked")
101: public ContextImpl(final String id) {
102: this (id, new Hashtable());
103: }
104:
105: /**
106: * Retrieves the named object.
107: * @param name the name of the object to look up
108: * @return the object bound to <tt>name</tt>
109: * @throws NamingException if a naming exception is encountered
110: */
111: public Object lookup(final Name name) throws NamingException {
112: // Just use the string version for now.
113: return lookup(name.toString());
114: }
115:
116: /**
117: * Retrieves the named object.
118: * @param name the name of the object to look up
119: * @return the object bound to name
120: * @throws NamingException if a naming exception is encountered
121: */
122: public Object lookup(final String name) throws NamingException {
123: logger.debug("lookup {0}", name);
124:
125: Name n = new CompositeName(name);
126: if (n.size() < 1) {
127: // Empty name means this context
128: logger.debug("Empty name");
129: return this ;
130: }
131:
132: if (n.size() > 1) {
133: // sub context in the env tree
134: String suffix = n.getSuffix(1).toString();
135: // should throw exception if sub context not found!
136: Context subctx = lookupCtx(n.get(0));
137: return subctx.lookup(suffix);
138: }
139: // leaf in the env tree
140: Object ret = bindings.get(name);
141: if (ret == null) {
142: logger.debug(" {0} not found.", name);
143: throw new NameNotFoundException(name);
144: }
145: if (ret instanceof LinkRef) {
146: // Handle special case of the LinkRef since I think
147: // it's not handled by std NamingManager.getObjectInstance().
148: // The name hidden in linkref is in the initial context.
149:
150: InitialContext ictx = new InitialContext();
151: RefAddr ra = ((Reference) ret).get(0);
152: try {
153: ret = ictx.lookup((String) ra.getContent());
154: } catch (Exception e) {
155: NamingException ne = new NamingException(e.getMessage());
156: ne.setRootCause(e);
157: logger.error("unexpected exception {0}",
158: e.getMessage(), e);
159: throw ne;
160: }
161: } else if (ret instanceof Reference) {
162: // Use NamingManager to build an object
163: try {
164: Object o = javax.naming.spi.NamingManager
165: .getObjectInstance(ret, n, this , environment);
166: ret = o;
167: } catch (NamingException e) {
168: throw e;
169: } catch (Exception e) {
170: NamingException ne = new NamingException(e.getMessage());
171: ne.setRootCause(e);
172: throw ne;
173: }
174: if (ret == null) {
175: logger
176: .error(
177: "Can not build an object with the reference {0}",
178: name);
179: throw new NamingException(
180: "Can not build an object with the reference '"
181: + name + "'");
182: }
183: }
184: return ret;
185:
186: }
187:
188: /**
189: * Binds a name to an object. Delegate to the String version.
190: * @param name the name to bind; may not be empty
191: * @param obj the object to bind; possibly null
192: * @throws NamingException if a naming exception is encountered
193: * @see javax.naming.NameAlreadyBoundException
194: */
195: public void bind(final Name name, final Object obj)
196: throws NamingException {
197: // Just use the string version for now.
198: bind(name.toString(), obj);
199: }
200:
201: /**
202: * Binds a name to an object.
203: * @param name the name to bind; may not be empty
204: * @param obj the object to bind; possibly null
205: * @throws NamingException if a naming exception is encountered
206: * @see javax.naming.NameAlreadyBoundException
207: */
208: public void bind(final String name, final Object obj)
209: throws NamingException {
210: logger.debug("bind {0}", name);
211:
212: Name n = new CompositeName(name);
213: if (n.size() < 1) {
214: logger.error("CompNamingContext bind empty name ?");
215:
216: throw new InvalidNameException(
217: "CompNamingContext cannot bind empty name");
218: }
219:
220: if (n.size() == 1) {
221: // leaf in the env tree
222: if (bindings.get(name) != null) {
223: logger.error("CompNamingContext: trying to overbind");
224: throw new NameAlreadyBoundException(
225: "CompNamingContext: Use rebind to bind over a name");
226: }
227: bindings.put(name, obj);
228: } else {
229: // sub context in the env tree
230: String suffix = n.getSuffix(1).toString();
231: // must create the subcontext first if it does not exist yet.
232: Context subctx;
233: try {
234: subctx = lookupCtx(n.get(0));
235: } catch (NameNotFoundException e) {
236: subctx = createSubcontext(n.get(0));
237: }
238: subctx.bind(suffix, obj);
239: }
240: }
241:
242: /**
243: * Binds a name to an object, overwriting any existing binding.
244: * @param name the name to bind; may not be empty
245: * @param obj the object to bind; possibly null
246: * @throws NamingException if a naming exception is encountered
247: */
248: public void rebind(final Name name, final Object obj)
249: throws NamingException {
250: // Just use the string version for now.
251: rebind(name.toString(), obj);
252: }
253:
254: /**
255: * Binds a name to an object, overwriting any existing binding.
256: * @param name the name to bind; may not be empty
257: * @param obj the object to bind; possibly null
258: * @throws NamingException if a naming exception is encountered
259: * @see javax.naming.InvalidNameException
260: */
261: public void rebind(final String name, final Object obj)
262: throws NamingException {
263:
264: logger.debug("rebind {0}", name);
265:
266: Name n = new CompositeName(name);
267: if (n.size() < 1) {
268: logger.error("CompNamingContext rebind empty name ?");
269: throw new InvalidNameException(
270: "CompNamingContext cannot rebind empty name");
271: }
272:
273: if (n.size() == 1) {
274: // leaf in the env tree
275: bindings.put(name, obj);
276: } else {
277: // sub context in the env tree
278: String suffix = n.getSuffix(1).toString();
279: // must create the subcontext first if it does not exist yet.
280: Context subctx;
281: try {
282: subctx = lookupCtx(n.get(0));
283: } catch (NameNotFoundException e) {
284: subctx = createSubcontext(n.get(0));
285: }
286: subctx.rebind(suffix, obj);
287: }
288: }
289:
290: /**
291: * Unbinds the named object.
292: * @param name the name to unbind; may not be empty
293: * @throws NamingException if a naming exception is encountered
294: * @see javax.naming.NameNotFoundException
295: */
296: public void unbind(final Name name) throws NamingException {
297: // Just use the string version for now.
298: unbind(name.toString());
299: }
300:
301: /**
302: * Unbinds the named object.
303: * @param name the name to unbind; may not be empty
304: * @throws NamingException if a naming exception is encountered
305: * @see javax.naming.NameNotFoundException
306: * @see javax.naming.InvalidNameException
307: */
308: public void unbind(final String name) throws NamingException {
309:
310: logger.debug("unbind {0}", name);
311:
312: Name n = new CompositeName(name);
313: if (n.size() < 1) {
314: logger.error("CompNamingContext rebind empty name ?");
315: throw new InvalidNameException(
316: "CompNamingContext cannot unbind empty name");
317: }
318:
319: if (n.size() == 1) {
320: // leaf in the env tree
321: if (bindings.get(name) == null) {
322: logger.error("CompNamingContext nothing to unbind");
323: throw new NameNotFoundException(name);
324: }
325: bindings.remove(name);
326: } else {
327: // sub context in the env tree
328: String suffix = n.getSuffix(1).toString();
329: // should throw exception if sub context not found!
330: Context subctx = lookupCtx(n.get(0));
331: subctx.unbind(suffix);
332: }
333: }
334:
335: /**
336: * Binds a new name to the object bound to an old name, and unbinds the old
337: * name.
338: * @param oldName the name of the existing binding; may not be empty
339: * @param newName the name of the new binding; may not be empty
340: * @throws NamingException if a naming exception is encountered
341: */
342: public void rename(final Name oldName, final Name newName)
343: throws NamingException {
344: // Just use the string version for now.
345: rename(oldName.toString(), newName.toString());
346: }
347:
348: /**
349: * Binds a new name to the object bound to an old name, and unbinds the old
350: * name.
351: * @param oldName the name of the existing binding; may not be empty
352: * @param newName the name of the new binding; may not be empty
353: * @throws NamingException if a naming exception is encountered
354: */
355: public void rename(final String oldName, final String newName)
356: throws NamingException {
357: logger.debug("CompNamingContext rename {0} in {1}", oldName,
358: newName);
359: Object obj = lookup(oldName);
360: rebind(newName, obj);
361: unbind(oldName);
362: }
363:
364: /**
365: * Enumerates the names bound in the named context, along with the class
366: * names of objects bound to them. The contents of any subcontexts are not
367: * included.
368: * @param name the name of the context to list
369: * @return an enumeration of the names and class names of the bindings in
370: * this context. Each element of the enumeration is of type
371: * NameClassPair.
372: * @throws NamingException if a naming exception is encountered
373: */
374: public NamingEnumeration<NameClassPair> list(final Name name)
375: throws NamingException {
376: // Just use the string version for now.
377: return list(name.toString());
378: }
379:
380: /**
381: * Enumerates the names bound in the named context, along with the class
382: * names of objects bound to them.
383: * @param name the name of the context to list
384: * @return an enumeration of the names and class names of the bindings in
385: * this context. Each element of the enumeration is of type
386: * NameClassPair.
387: * @throws NamingException if a naming exception is encountered
388: */
389: public NamingEnumeration<NameClassPair> list(final String name)
390: throws NamingException {
391: logger.debug("list {0}", name);
392:
393: if (name.length() == 0) {
394: // List this context
395: return new NamingEnumerationImpl(bindings);
396: }
397: Object obj = lookup(name);
398: if (obj instanceof Context) {
399: return ((Context) obj).list("");
400: }
401: throw new NotContextException(name);
402: }
403:
404: /**
405: * Enumerates the names bound in the named context, along with the objects
406: * bound to them. The contents of any subcontexts are not included. If a
407: * binding is added to or removed from this context, its effect on an
408: * enumeration previously returned is undefined.
409: * @param name the name of the context to list
410: * @return an enumeration of the bindings in this context. Each element of
411: * the enumeration is of type Binding.
412: * @throws NamingException if a naming exception is encountered
413: */
414: public NamingEnumeration<Binding> listBindings(final Name name)
415: throws NamingException {
416: // Just use the string version for now.
417: return listBindings(name.toString());
418: }
419:
420: /**
421: * Enumerates the names bound in the named context, along with the objects
422: * bound to them.
423: * @param name the name of the context to list
424: * @return an enumeration of the bindings in this context. Each element of
425: * the enumeration is of type Binding.
426: * @throws NamingException if a naming exception is encountered
427: */
428: public NamingEnumeration<Binding> listBindings(final String name)
429: throws NamingException {
430: logger.debug("listBindings {0}", name);
431:
432: if (name.length() == 0) {
433: // List this context
434: return new BindingsImpl(bindings);
435: }
436: Object obj = lookup(name);
437: if (obj instanceof Context) {
438: return ((Context) obj).listBindings("");
439: }
440: logger.error("CompNamingContext: can only list a Context");
441: throw new NotContextException(name);
442:
443: }
444:
445: /**
446: * Destroys the named context and removes it from the namespace. Not
447: * supported yet.
448: * @param name the name of the context to be destroyed; may not be empty
449: * @throws NamingException if a naming exception is encountered
450: */
451: public void destroySubcontext(final Name name)
452: throws NamingException {
453: // Just use the string version for now.
454: destroySubcontext(name.toString());
455: }
456:
457: /**
458: * Destroys the named context and removes it from the namespace. Not
459: * supported yet.
460: * @param name the name of the context to be destroyed; may not be empty
461: * @throws NamingException if a naming exception is encountered
462: */
463: public void destroySubcontext(final String name)
464: throws NamingException {
465: logger.error("CompNamingContext try to destroySubcontext {0}",
466: name);
467: throw new OperationNotSupportedException(
468: "CompNamingContext: destroySubcontext");
469: }
470:
471: /**
472: * Creates and binds a new context. Creates a new context with the given
473: * name and binds it in the target context.
474: * @param name the name of the context to create; may not be empty
475: * @return the newly created context
476: * @throws NamingException if a naming exception is encountered
477: * @see javax.naming.NameAlreadyBoundException
478: */
479: public Context createSubcontext(final Name name)
480: throws NamingException {
481: // Just use the string version for now.
482: return createSubcontext(name.toString());
483: }
484:
485: /**
486: * Creates and binds a new context.
487: * @param name the name of the context to create; may not be empty
488: * @return the newly created context
489: * @throws NamingException if a naming exception is encountered
490: * @see javax.naming.NameAlreadyBoundException
491: */
492: @SuppressWarnings("unchecked")
493: public Context createSubcontext(final String name)
494: throws NamingException {
495: logger.debug("createSubcontext {0}", name);
496:
497: Name n = new CompositeName(name);
498: if (n.size() < 1) {
499: logger
500: .error("CompNamingContext createSubcontext with empty name ?");
501: throw new InvalidNameException(
502: "CompNamingContext cannot create empty Subcontext");
503: }
504:
505: Context ctx = null; // returned ctx
506: if (n.size() == 1) {
507: // leaf in the env tree: create ctx and bind it in parent.
508: ctx = new ContextImpl(compId, environment);
509: bindings.put(name, ctx);
510: } else {
511: // as for bind, we must create first all the subcontexts
512: // if they don't exist yet.
513: String suffix = n.getSuffix(1).toString();
514: Context subctx;
515: String newName = n.get(0);
516: try {
517: subctx = lookupCtx(newName);
518: } catch (NameNotFoundException e) {
519: subctx = createSubcontext(newName);
520: }
521: ctx = subctx.createSubcontext(suffix);
522: }
523: return ctx;
524: }
525:
526: /**
527: * Retrieves the named object, following links except for the terminal
528: * atomic component of the name. If the object bound to name is not a link,
529: * returns the object itself.
530: * @param name the name of the object to look up
531: * @return the object bound to name, not following the terminal link (if
532: * any).
533: * @throws NamingException if a naming exception is encountered
534: */
535: public Object lookupLink(final Name name) throws NamingException {
536: // Just use the string version for now.
537: return lookupLink(name.toString());
538: }
539:
540: /**
541: * Retrieves the named object, following links except for the terminal
542: * atomic component of the name. If the object bound to name is not a link,
543: * returns the object itself.
544: * @param name the name of the object to look up
545: * @return the object bound to name, not following the terminal link (if
546: * any)
547: * @throws NamingException if a naming exception is encountered
548: */
549: public Object lookupLink(final String name) throws NamingException {
550: logger.debug("lookupLink {0}", name);
551:
552: // To be done. For now: just return the object
553: logger
554: .error("CompNamingContext lookupLink not implemented yet!");
555:
556: return lookup(name);
557: }
558:
559: /**
560: * Retrieves the parser associated with the named context.
561: * @param name the name of the context from which to get the parser
562: * @return a name parser that can parse compound names into their atomic
563: * components
564: * @throws NamingException if a naming exception is encountered
565: */
566: public NameParser getNameParser(final Name name)
567: throws NamingException {
568: return myParser;
569: }
570:
571: /**
572: * Retrieves the parser associated with the named context.
573: * @param name the name of the context from which to get the parser
574: * @return a name parser that can parse compound names into their atomic
575: * components
576: * @throws NamingException if a naming exception is encountered
577: */
578: public NameParser getNameParser(final String name)
579: throws NamingException {
580: return myParser;
581: }
582:
583: /**
584: * Composes the name of this context with a name relative to this context.
585: * @param name a name relative to this context
586: * @param prefix the name of this context relative to one of its ancestors
587: * @return the composition of prefix and name
588: * @throws NamingException if a naming exception is encountered
589: */
590: public Name composeName(final Name name, final Name prefix)
591: throws NamingException {
592: logger
593: .error("CompNamingContext composeName not implemented yet!");
594:
595: throw new OperationNotSupportedException(
596: "CompNamingContext composeName");
597: }
598:
599: /**
600: * Composes the name of this context with a name relative to this context:
601: * Not supported.
602: * @param name a name relative to this context
603: * @param prefix the name of this context relative to one of its ancestors
604: * @return the composition of prefix and name
605: * @throws NamingException if a naming exception is encountered
606: */
607: public String composeName(final String name, final String prefix)
608: throws NamingException {
609: logger.error("CompNamingContext composeName {0} {1}", name,
610: prefix);
611:
612: throw new OperationNotSupportedException(
613: "CompNamingContext composeName");
614: }
615:
616: /**
617: * Adds a new environment property to the environment of this context. If
618: * the property already exists, its value is overwritten.
619: * @param propName the name of the environment property to add; may not be
620: * null
621: * @param propVal the value of the property to add; may not be null
622: * @return the previous value of the property, or null if the property was
623: * not in the environment before
624: * @throws NamingException if a naming exception is encountered
625: */
626: @SuppressWarnings("unchecked")
627: public Object addToEnvironment(final String propName,
628: final Object propVal) throws NamingException {
629: return environment.put(propName, propVal);
630: }
631:
632: /**
633: * Removes an environment property from the environment of this context.
634: * @param propName the name of the environment property to remove; may not
635: * be null
636: * @return the previous value of the property, or null if the property was
637: * not in the environment
638: * @throws NamingException if a naming exception is encountered
639: */
640: public Object removeFromEnvironment(final String propName)
641: throws NamingException {
642:
643: logger.debug("removeFromEnvironment {0}", propName);
644:
645: if (environment == null) {
646: return null;
647: }
648: return environment.remove(propName);
649: }
650:
651: /**
652: * Retrieves the environment in effect for this context.
653: * @return the environment of this context; never null
654: * @throws NamingException if a naming exception is encountered
655: */
656: public Hashtable<?, ?> getEnvironment() throws NamingException {
657: return environment;
658: }
659:
660: /**
661: * Closes this context.
662: * @throws NamingException if a naming exception is encountered
663: */
664: public void close() throws NamingException {
665: environment = null;
666: }
667:
668: /**
669: * Retrieves the full name of this context within its own namespace.
670: * @return this context's name in its own namespace; never null
671: */
672: public String getNameInNamespace() {
673: // this is used today for debug only.
674: return compId;
675: }
676:
677: // ------------------------------------------------------------------
678: // Private Methods
679: // ------------------------------------------------------------------
680:
681: /**
682: * Find if this name is a sub context.
683: * @param name the sub context name
684: * @return the named Context
685: * @throws NamingException When nam?ing fails
686: * @see javax.naming.NameNotFoundException
687: * @see javax.naming.NameAlreadyBoundException
688: */
689: private Context lookupCtx(final String name) throws NamingException {
690: Object obj = bindings.get(name);
691: if (obj == null) {
692: throw new NameNotFoundException();
693: }
694: if (obj instanceof ContextImpl) {
695: return (Context) obj;
696: }
697: throw new NameAlreadyBoundException(name);
698: }
699:
700: }
|