001: /*
002: * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: */
007: package winstone.jndi;
008:
009: import java.util.ArrayList;
010: import java.util.Hashtable;
011: import java.util.Iterator;
012: import java.util.List;
013: import java.util.Map;
014:
015: import javax.naming.CompositeName;
016: import javax.naming.Context;
017: import javax.naming.Name;
018: import javax.naming.NameNotFoundException;
019: import javax.naming.NameParser;
020: import javax.naming.NamingEnumeration;
021: import javax.naming.NamingException;
022: import javax.naming.NotContextException;
023: import javax.naming.OperationNotSupportedException;
024: import javax.naming.spi.NamingManager;
025:
026: import winstone.Logger;
027:
028: /**
029: * The main jndi context implementation class.
030: *
031: * @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
032: * @version $Id: WinstoneContext.java,v 1.3 2006/02/28 07:32:48 rickknowles Exp $
033: */
034: public class WinstoneContext implements Context {
035: static final String PREFIX = "java:";
036: static final String FIRST_CHILD = "comp";
037: static final String BODGED_PREFIX = "java:comp";
038:
039: private Hashtable environment;
040: private Hashtable bindings;
041: private final static NameParser nameParser = new WinstoneNameParser();
042: private WinstoneContext parent;
043: private String myAbsoluteName;
044: private Object contextLock;
045:
046: /**
047: * Constructor - sets up environment
048: */
049: public WinstoneContext(Map sourceEnvironment,
050: WinstoneContext parent, String absoluteName,
051: Object contextLock) throws NamingException {
052: this .environment = new Hashtable();
053: List sourceKeys = new ArrayList(sourceEnvironment.keySet());
054: for (Iterator i = sourceKeys.iterator(); i.hasNext();) {
055: String key = (String) i.next();
056: addToEnvironment(key, sourceEnvironment.get(key));
057: }
058: this .parent = parent;
059: this .myAbsoluteName = absoluteName;
060: this .contextLock = contextLock;
061: this .bindings = new Hashtable();
062: Logger.log(Logger.FULL_DEBUG,
063: ContainerJNDIManager.JNDI_RESOURCES,
064: "WinstoneContext.Initialised", this .myAbsoluteName);
065: }
066:
067: /**
068: * Constructor - sets up environment and copies the bindings across
069: */
070: protected WinstoneContext(Map sourceEnvironment,
071: WinstoneContext parent, String absoluteName,
072: Object contextLock, Hashtable bindings)
073: throws NamingException {
074: this .environment = new Hashtable();
075: List sourceKeys = new ArrayList(sourceEnvironment.keySet());
076: for (Iterator i = sourceKeys.iterator(); i.hasNext();) {
077: String key = (String) i.next();
078: addToEnvironment(key, sourceEnvironment.get(key));
079: }
080: this .parent = parent;
081: this .myAbsoluteName = absoluteName;
082: this .contextLock = contextLock;
083: this .bindings = bindings;
084: Logger.log(Logger.FULL_DEBUG,
085: ContainerJNDIManager.JNDI_RESOURCES,
086: "WinstoneContext.Copied", this .myAbsoluteName);
087: }
088:
089: public void close() throws NamingException {
090: }
091:
092: public Hashtable getEnvironment() throws NamingException {
093: return new Hashtable(this .environment);
094: }
095:
096: public Object removeFromEnvironment(String property)
097: throws NamingException {
098: return this .environment.remove(property);
099: }
100:
101: public Object addToEnvironment(String property, Object value)
102: throws NamingException {
103: return this .environment.put(property, value);
104: }
105:
106: /**
107: * Handles the processing of relative and absolute names. If a relative name
108: * is detected, it is processed by the name parser. If an absolute name is
109: * detected, it determines first if the absolute name refers to this
110: * context. If not, it then determines whether the request can be passed
111: * back to the parent or not, and returns null if it can, and throws an
112: * exception otherwise.
113: */
114: protected Name validateName(Name name) throws NamingException {
115: // Check for absolute urls and redirect or correct
116: if (name.isEmpty())
117: return name;
118: else if (name.get(0).equals(BODGED_PREFIX)) {
119: Name newName = name.getSuffix(1).add(0, FIRST_CHILD).add(0,
120: PREFIX);
121: return validateName(newName);
122: } else if (name.get(0).equals(PREFIX)) {
123: String stringName = name.toString();
124: if (stringName.equals(this .myAbsoluteName))
125: return nameParser.parse("");
126: else if (stringName.startsWith(this .myAbsoluteName))
127: return nameParser.parse(stringName
128: .substring(this .myAbsoluteName.length() + 1));
129: else if (this .parent != null)
130: return null;
131: else
132: throw new NameNotFoundException(
133: ContainerJNDIManager.JNDI_RESOURCES.getString(
134: "WinstoneContext.NameNotFound", name
135: .toString()));
136: } else if (name instanceof CompositeName)
137: return nameParser.parse(name.toString());
138: else
139: return name;
140: }
141:
142: /**
143: * Lookup an object in the context. Returns a copy of this context if the
144: * name is empty, or the specified resource (if we have it). If the name is
145: * unknown, throws a NameNotFoundException.
146: */
147: public Object lookup(Name name) throws NamingException {
148: Name searchName = validateName(name);
149:
150: // If null, it means we don't know how to handle this -> throw to the
151: // parent
152: if (searchName == null)
153: return this .parent.lookup(name);
154: // If empty name, return a copy of this Context
155: else if (searchName.isEmpty())
156: return new WinstoneContext(this .environment, this .parent,
157: this .myAbsoluteName, this .contextLock,
158: this .bindings);
159:
160: String this Name = searchName.get(0);
161: synchronized (this .contextLock) {
162: Object this Value = bindings.get(this Name);
163:
164: // If the name points to something in this level, try to find it,
165: // and give
166: // an error if not available
167: if (searchName.size() == 1) {
168: if (this Value == null)
169: throw new NameNotFoundException(
170: ContainerJNDIManager.JNDI_RESOURCES
171: .getString(
172: "WinstoneContext.NameNotFound",
173: name.toString()));
174:
175: try {
176: return NamingManager.getObjectInstance(this Value,
177: new CompositeName().add(this Name), this ,
178: this .environment);
179: } catch (Exception e) {
180: NamingException ne = new NamingException(
181: ContainerJNDIManager.JNDI_RESOURCES
182: .getString("WinstoneContext.FailedToGetInstance"));
183: ne.setRootCause(e);
184: throw ne;
185: }
186: }
187:
188: else if (this Value == null)
189: throw new NameNotFoundException(
190: ContainerJNDIManager.JNDI_RESOURCES.getString(
191: "WinstoneContext.NameNotFound",
192: this Name.toString()));
193:
194: // If it's not in this level and what we found is not a context,
195: // complain
196: else if (!(this Value instanceof Context))
197: throw new NotContextException(
198: ContainerJNDIManager.JNDI_RESOURCES
199: .getString(
200: "WinstoneContext.NotContext",
201: new String[] {
202: this Name.toString(),
203: this Value.getClass()
204: .getName() }));
205:
206: // Open the context, perform a lookup, then close the context we
207: // opened
208: else
209: try {
210: return ((Context) this Value).lookup(searchName
211: .getSuffix(1));
212: } finally {
213: ((Context) this Value).close();
214: }
215: }
216: }
217:
218: public Object lookup(String name) throws NamingException {
219: return lookup(new CompositeName(name));
220: }
221:
222: public Object lookupLink(Name name) throws NamingException {
223: Logger.log(Logger.WARNING, ContainerJNDIManager.JNDI_RESOURCES,
224: "WinstoneContext.LinkRefUnsupported");
225: return lookup(name);
226: }
227:
228: public Object lookupLink(String name) throws NamingException {
229: return lookupLink(new CompositeName(name));
230: }
231:
232: /**
233: * Returns a list of objects bound to the context
234: */
235: public NamingEnumeration list(Name name) throws NamingException {
236: Name searchName = validateName(name);
237:
238: // If null, it means we don't know how to handle this -> throw to the
239: // parent
240: if (searchName == null)
241: return this .parent.list(name);
242: // If empty name, return a copy of this Context
243: else if (searchName.isEmpty()) {
244: NamingEnumeration e = null;
245: synchronized (this .contextLock) {
246: e = new WinstoneNameEnumeration(this .bindings);
247: }
248: return e;
249: }
250:
251: // Lookup the object - if it's not a context, throw an error
252: else {
253: Object ctx = this .lookup(searchName);
254: if (ctx instanceof Context)
255: try {
256: return ((Context) ctx).list(new CompositeName(""));
257: } finally {
258: ((Context) ctx).close();
259: }
260: else if (ctx == null)
261: throw new NameNotFoundException(
262: ContainerJNDIManager.JNDI_RESOURCES.getString(
263: "WinstoneContext.NameNotFound",
264: searchName.toString()));
265: else
266: throw new NotContextException(
267: ContainerJNDIManager.JNDI_RESOURCES.getString(
268: "WinstoneContext.NotContext",
269: new String[] { searchName.toString(),
270: ctx.getClass().getName() }));
271: }
272: }
273:
274: public NamingEnumeration list(String name) throws NamingException {
275: return list(new CompositeName(name));
276: }
277:
278: public NamingEnumeration listBindings(Name name)
279: throws NamingException {
280: Name searchName = validateName(name);
281:
282: // If null, it means we don't know how to handle this -> throw to the
283: // parent
284: if (searchName == null)
285: return this .parent.list(name);
286: // If empty name, return a copy of this Context
287: else if (searchName.isEmpty()) {
288: NamingEnumeration e = null;
289: synchronized (this .contextLock) {
290: e = new WinstoneBindingEnumeration(this .bindings,
291: this .environment, this );
292: }
293: return e;
294: }
295:
296: // Lookup the object - if it's not a context, throw an error
297: else {
298: Object ctx = this .lookup(searchName);
299: if (ctx instanceof Context)
300: try {
301: return ((Context) ctx)
302: .listBindings(new CompositeName(""));
303: } finally {
304: ((Context) ctx).close();
305: }
306: else if (ctx == null)
307: throw new NameNotFoundException(
308: ContainerJNDIManager.JNDI_RESOURCES.getString(
309: "WinstoneContext.NameNotFound",
310: searchName.toString()));
311: else
312: throw new NotContextException(
313: ContainerJNDIManager.JNDI_RESOURCES.getString(
314: "WinstoneContext.NotContext",
315: new String[] { searchName.toString(),
316: ctx.getClass().getName() }));
317: }
318: }
319:
320: public NamingEnumeration listBindings(String name)
321: throws NamingException {
322: return listBindings(new CompositeName(name));
323: }
324:
325: public NameParser getNameParser(Name name) throws NamingException {
326: Object obj = lookup(name);
327: if (obj instanceof Context) {
328: ((Context) obj).close();
329: }
330: return nameParser;
331: }
332:
333: public NameParser getNameParser(String name) throws NamingException {
334: return getNameParser(new CompositeName(name));
335: }
336:
337: public String getNameInNamespace() throws NamingException {
338: return this .myAbsoluteName;
339: }
340:
341: /***************************************************************************
342: * Below here is for read-write contexts ... *
343: **************************************************************************/
344:
345: public void bind(String name, Object value) throws NamingException {
346: bind(new CompositeName(name), value);
347: }
348:
349: public void bind(Name name, Object value) throws NamingException {
350: bind(name, value, false);
351: }
352:
353: protected void bind(Name name, Object value, boolean allowOverwrites)
354: throws NamingException {
355: Name bindName = validateName(name);
356:
357: // If null, it means we don't know how to handle this -> throw to the
358: // parent
359: if (bindName == null)
360: this .parent.bind(name, value, allowOverwrites);
361: // If empty name, complain - we should have a child name here
362: else if (bindName.isEmpty())
363: throw new NamingException(
364: ContainerJNDIManager.JNDI_RESOURCES.getString(
365: "WinstoneContext.AlreadyExists", name
366: .toString()));
367: else if (bindName.size() > 1) {
368: Object ctx = lookup(bindName.get(0));
369: if (!(ctx instanceof Context))
370: throw new NotContextException(
371: ContainerJNDIManager.JNDI_RESOURCES.getString(
372: "WinstoneContext.NotContext",
373: new String[] { bindName.get(0),
374: ctx.getClass().getName() }));
375: else if (ctx == null)
376: throw new NameNotFoundException(
377: ContainerJNDIManager.JNDI_RESOURCES.getString(
378: "WinstoneContext.NameNotFound",
379: bindName.get(0)));
380: else
381: try {
382: if (allowOverwrites)
383: ((Context) ctx).rebind(bindName.getSuffix(1),
384: value);
385: else
386: ((Context) ctx).bind(bindName.getSuffix(1),
387: value);
388: } finally {
389: ((Context) ctx).close();
390: }
391: } else if ((!allowOverwrites)
392: && this .bindings.get(name.get(0)) != null)
393: throw new NamingException(
394: ContainerJNDIManager.JNDI_RESOURCES.getString(
395: "WinstoneContext.AlreadyExists", name
396: .toString()));
397: else {
398: value = NamingManager.getStateToBind(value,
399: new CompositeName().add(bindName.get(0)), this ,
400: this .environment);
401: synchronized (this .contextLock) {
402: this .bindings.put(bindName.get(0), value);
403: }
404: }
405: }
406:
407: public void rebind(String name, Object value)
408: throws NamingException {
409: rebind(new CompositeName(name), value);
410: }
411:
412: public void rebind(Name name, Object value) throws NamingException {
413: bind(name, value, true);
414: }
415:
416: public void unbind(String name) throws NamingException {
417: unbind(new CompositeName(name));
418: }
419:
420: public void unbind(Name name) throws NamingException {
421: Name unbindName = validateName(name);
422:
423: // If null, it means we don't know how to handle this -> throw to the
424: // parent
425: if (unbindName == null)
426: this .parent.unbind(name);
427: // If empty name, complain - we should have a child name here
428: else if (unbindName.isEmpty())
429: throw new NamingException(
430: ContainerJNDIManager.JNDI_RESOURCES
431: .getString("WinstoneContext.CantUnbindEmptyName"));
432: else if (unbindName.size() > 1) {
433: Object ctx = lookup(unbindName.get(0));
434: if (!(ctx instanceof Context))
435: throw new NotContextException(
436: ContainerJNDIManager.JNDI_RESOURCES.getString(
437: "WinstoneContext.NotContext",
438: new String[] { unbindName.get(0),
439: ctx.getClass().getName() }));
440: else if (ctx == null)
441: throw new NameNotFoundException(
442: ContainerJNDIManager.JNDI_RESOURCES.getString(
443: "WinstoneContext.NameNotFound",
444: unbindName.get(0)));
445: else
446: try {
447: ((Context) ctx).unbind(unbindName.getSuffix(1));
448: } finally {
449: ((Context) ctx).close();
450: }
451: } else if (this .bindings.get(name.get(0)) == null)
452: throw new NamingException(
453: ContainerJNDIManager.JNDI_RESOURCES.getString(
454: "WinstoneContext.NameNotFound", name
455: .toString()));
456: else {
457: synchronized (this .contextLock) {
458: // Object removing = this.bindings.get(unbindName.get(0));
459: this .bindings.remove(unbindName.get(0));
460: }
461: }
462: }
463:
464: public void rename(Name oldName, Name newName)
465: throws NamingException {
466: throw new OperationNotSupportedException(
467: "rename not supported in Winstone java:/ context");
468: }
469:
470: public void rename(String oldName, String newName)
471: throws NamingException {
472: rename(new CompositeName(oldName), new CompositeName(newName));
473: }
474:
475: public Context createSubcontext(String name) throws NamingException {
476: return createSubcontext(new CompositeName(name));
477: }
478:
479: public Context createSubcontext(Name name) throws NamingException {
480: Name childName = validateName(name);
481:
482: // If null, it means we don't know how to handle this -> throw to the
483: // parent
484: if (childName == null)
485: return this .parent.createSubcontext(name);
486: // If empty name, complain - we should have a child name here
487: else if (childName.isEmpty())
488: throw new NamingException(
489: ContainerJNDIManager.JNDI_RESOURCES.getString(
490: "WinstoneContext.AlreadyExists", name
491: .toString()));
492: else if (childName.size() > 1) {
493: Object ctx = lookup(childName.get(0));
494: if (!(ctx instanceof Context))
495: throw new NotContextException(
496: ContainerJNDIManager.JNDI_RESOURCES.getString(
497: "WinstoneContext.NotContext",
498: new String[] { childName.get(0),
499: ctx.getClass().getName() }));
500: else if (ctx == null)
501: throw new NameNotFoundException(
502: ContainerJNDIManager.JNDI_RESOURCES.getString(
503: "WinstoneContext.NameNotFound",
504: childName.get(0)));
505: else
506: try {
507: ((Context) ctx).createSubcontext(childName
508: .getSuffix(1));
509: } finally {
510: ((Context) ctx).close();
511: }
512: }
513:
514: Context childContext = null;
515: synchronized (this .contextLock) {
516: if (this .bindings.get(childName.get(0)) != null)
517: throw new NamingException(
518: ContainerJNDIManager.JNDI_RESOURCES.getString(
519: "WinstoneContext.AlreadyExists",
520: childName.get(0)));
521: else {
522: childContext = new WinstoneContext(this .environment,
523: this , this .myAbsoluteName + "/"
524: + childName.get(0), new Boolean(true));
525: this .bindings.put(childName.get(0), childContext);
526: }
527: }
528: return childContext;
529: }
530:
531: public void destroySubcontext(String name) throws NamingException {
532: destroySubcontext(new CompositeName(name));
533: }
534:
535: public void destroySubcontext(Name name) throws NamingException {
536: Name childName = validateName(name);
537:
538: // If null, it means we don't know how to handle this -> throw to the parent
539: if (childName == null)
540: this .parent.destroySubcontext(name);
541: // If absolutely referring to this context, tell the parent to delete this context
542: else if (childName.isEmpty()) {
543: if (!name.isEmpty())
544: this .parent.destroySubcontext(name.getSuffix(name
545: .size() - 2));
546: else
547: throw new NamingException(
548: ContainerJNDIManager.JNDI_RESOURCES
549: .getString("WinstoneContext.CantDestroyEmptyName"));
550: } else if (childName.size() > 1) {
551: Object ctx = lookup(childName.get(0));
552: if (!(ctx instanceof Context))
553: throw new NotContextException(
554: ContainerJNDIManager.JNDI_RESOURCES.getString(
555: "WinstoneContext.NotContext",
556: new String[] { childName.get(0),
557: ctx.getClass().getName() }));
558: else if (ctx == null)
559: throw new NameNotFoundException(
560: ContainerJNDIManager.JNDI_RESOURCES.getString(
561: "WinstoneContext.NameNotFound",
562: childName.get(0)));
563: else
564: try {
565: ((Context) ctx).destroySubcontext(childName
566: .getSuffix(1));
567: } finally {
568: ((Context) ctx).close();
569: }
570: } else
571: synchronized (this .contextLock) {
572: Context childContext = (Context) lookup(childName
573: .get(0));
574: childContext.close();
575: this .bindings.remove(childName.get(0));
576: }
577: }
578:
579: public String composeName(String name1, String name2)
580: throws NamingException {
581: Name name = composeName(new CompositeName(name1),
582: new CompositeName(name2));
583: return name == null ? null : name.toString();
584: }
585:
586: public Name composeName(Name name1, Name name2)
587: throws NamingException {
588: throw new OperationNotSupportedException(
589: "composeName not supported in Winstone java:/ namespace");
590: }
591: }
|