View Javadoc

1   /*
2    * $Id: DefaultSpringJndiContext.java 19191 2010-08-25 21:05:23Z tcarlson $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.config.spring.jndi;
12  
13  import java.io.Serializable;
14  import java.util.HashMap;
15  import java.util.Hashtable;
16  import java.util.Iterator;
17  import java.util.Map;
18  
19  import javax.naming.Binding;
20  import javax.naming.CompositeName;
21  import javax.naming.Context;
22  import javax.naming.LinkRef;
23  import javax.naming.Name;
24  import javax.naming.NameClassPair;
25  import javax.naming.NameNotFoundException;
26  import javax.naming.NameParser;
27  import javax.naming.NamingEnumeration;
28  import javax.naming.NamingException;
29  import javax.naming.NotContextException;
30  import javax.naming.OperationNotSupportedException;
31  import javax.naming.Reference;
32  import javax.naming.spi.NamingManager;
33  /**
34   * TODO
35   */
36  
37  /**
38   * A simple spring based JNDI context which is mutable
39   * <p/>
40   * Borrowed from the XBean (xbean.codehaus.org) project. Thanks guys!
41   */
42  public class DefaultSpringJndiContext implements Context, Serializable
43  {
44  
45      private static final long serialVersionUID = -5754338187296859149L;
46      protected static final NameParser nameParser = new DefaultNameParser();
47  
48      private boolean freeze = false;
49  
50      protected final Hashtable environment;        // environment for this context
51      protected final Map bindings;         // bindings at my level
52      protected final Map treeBindings;     // all bindings under me
53  
54      private boolean frozen = false;
55      private String nameInNamespace = "";
56      public static final String SEPARATOR = "/";
57  
58      public DefaultSpringJndiContext()
59      {
60          environment = new Hashtable();
61          bindings = new HashMap();
62          treeBindings = new HashMap();
63      }
64  
65      public DefaultSpringJndiContext(Hashtable env)
66      {
67          if (env == null)
68          {
69              this.environment = new Hashtable();
70          }
71          else
72          {
73              this.environment = new Hashtable(env);
74          }
75          this.bindings = new HashMap();
76          this.treeBindings = new HashMap();
77      }
78  
79      public DefaultSpringJndiContext(Hashtable environment, Map bindings)
80      {
81          if (environment == null)
82          {
83              this.environment = new Hashtable();
84          }
85          else
86          {
87              this.environment = new Hashtable(environment);
88          }
89          this.bindings = bindings;
90          treeBindings = new HashMap();
91          frozen = true;
92      }
93  
94      public DefaultSpringJndiContext(Hashtable environment, Map bindings, String nameInNamespace)
95      {
96          this(environment, bindings);
97          this.nameInNamespace = nameInNamespace;
98      }
99  
100     protected DefaultSpringJndiContext(DefaultSpringJndiContext clone, Hashtable env)
101     {
102         this.bindings = clone.bindings;
103         this.treeBindings = clone.treeBindings;
104         this.environment = new Hashtable(env);
105     }
106 
107     protected DefaultSpringJndiContext(DefaultSpringJndiContext clone, Hashtable env, String nameInNamespace)
108     {
109         this(clone, env);
110         this.nameInNamespace = nameInNamespace;
111     }
112 
113     public Object addToEnvironment(String propName, Object propVal) throws NamingException
114     {
115         return environment.put(propName, propVal);
116     }
117 
118     public Hashtable getEnvironment() throws NamingException
119     {
120         return (Hashtable) environment.clone();
121     }
122 
123     public Object removeFromEnvironment(String propName) throws NamingException
124     {
125         return environment.remove(propName);
126     }
127 
128     public Object lookup(String name) throws NamingException
129     {
130         if (name.length() == 0)
131         {
132             return this;
133         }
134         Object result = treeBindings.get(name);
135         if (result == null)
136         {
137             result = bindings.get(name);
138         }
139         if (result == null)
140         {
141             int pos = name.indexOf(':');
142             if (pos > 0)
143             {
144                 String scheme = name.substring(0, pos);
145                 Context ctx = NamingManager.getURLContext(scheme, environment);
146                 if (ctx == null)
147                 {
148                     throw new NamingException("scheme " + scheme + " not recognized");
149                 }
150                 return ctx.lookup(name);
151             }
152             else
153             {
154                 // Split out the first name of the path
155                 // and look for it in the bindings map.
156                 CompositeName path = new CompositeName(name);
157 
158                 if (path.size() == 0)
159                 {
160                     return this;
161                 }
162                 else
163                 {
164                     String first = path.get(0);
165                     Object obj = bindings.get(first);
166                     if (obj == null)
167                     {
168                         throw new NameNotFoundException(name);
169                     }
170                     else if (obj instanceof Context && path.size() > 1)
171                     {
172                         Context subContext = (Context) obj;
173                         obj = subContext.lookup(path.getSuffix(1));
174                     }
175                     return obj;
176                 }
177             }
178         }
179         if (result instanceof LinkRef)
180         {
181             LinkRef ref = (LinkRef) result;
182             result = lookup(ref.getLinkName());
183         }
184         if (result instanceof Reference)
185         {
186             try
187             {
188                 result = NamingManager.getObjectInstance(result, null, null, this.environment);
189             }
190             catch (NamingException e)
191             {
192                 throw e;
193             }
194             catch (Exception e)
195             {
196                 throw (NamingException) new NamingException("could not look up : " + name).initCause(e);
197             }
198         }
199         if (result instanceof DefaultSpringJndiContext)
200         {
201             String prefix = getNameInNamespace();
202             if (prefix.length() > 0)
203             {
204                 prefix = prefix + SEPARATOR;
205             }
206             result = new DefaultSpringJndiContext((DefaultSpringJndiContext) result, environment, prefix + name);
207         }
208         return result;
209     }
210 
211     public Object lookup(Name name) throws NamingException
212     {
213         return lookup(name.toString());
214     }
215 
216     public Object lookupLink(String name) throws NamingException
217     {
218         return lookup(name);
219     }
220 
221     public Name composeName(Name name, Name prefix) throws NamingException
222     {
223         Name result = (Name) prefix.clone();
224         result.addAll(name);
225         return result;
226     }
227 
228     public String composeName(String name, String prefix) throws NamingException
229     {
230         CompositeName result = new CompositeName(prefix);
231         result.addAll(new CompositeName(name));
232         return result.toString();
233     }
234 
235     public NamingEnumeration list(String name) throws NamingException
236     {
237         Object o = lookup(name);
238         if (o == this)
239         {
240             return new DefaultSpringJndiContext.ListEnumeration();
241         }
242         else if (o instanceof Context)
243         {
244             return ((Context) o).list("");
245         }
246         else
247         {
248             throw new NotContextException();
249         }
250     }
251 
252     public NamingEnumeration listBindings(String name) throws NamingException
253     {
254         Object o = lookup(name);
255         if (o == this)
256         {
257             return new DefaultSpringJndiContext.ListBindingEnumeration();
258         }
259         else if (o instanceof Context)
260         {
261             return ((Context) o).listBindings("");
262         }
263         else
264         {
265             throw new NotContextException();
266         }
267     }
268 
269     public Object lookupLink(Name name) throws NamingException
270     {
271         return lookupLink(name.toString());
272     }
273 
274     public NamingEnumeration list(Name name) throws NamingException
275     {
276         return list(name.toString());
277     }
278 
279     public NamingEnumeration listBindings(Name name) throws NamingException
280     {
281         return listBindings(name.toString());
282     }
283 
284     public void bind(Name name, Object value) throws NamingException
285     {
286         bind(name.toString(), value);
287     }
288 
289     public void bind(String name, Object value) throws NamingException
290     {
291         checkFrozen();
292         internalBind(name, value);
293     }
294 
295     public void close() throws NamingException
296     {
297         // ignore
298     }
299 
300     public Context createSubcontext(Name name) throws NamingException
301     {
302         throw new OperationNotSupportedException();
303     }
304 
305     public Context createSubcontext(String name) throws NamingException
306     {
307         throw new OperationNotSupportedException();
308     }
309 
310     public void destroySubcontext(Name name) throws NamingException
311     {
312         throw new OperationNotSupportedException();
313     }
314 
315     public void destroySubcontext(String name) throws NamingException
316     {
317         throw new OperationNotSupportedException();
318     }
319 
320     public String getNameInNamespace() throws NamingException
321     {
322         return nameInNamespace;
323     }
324 
325     public NameParser getNameParser(Name name) throws NamingException
326     {
327         return nameParser;
328     }
329 
330     public NameParser getNameParser(String name) throws NamingException
331     {
332         return nameParser;
333     }
334 
335     public void rebind(Name name, Object value) throws NamingException
336     {
337         rebind(name.toString(), value);
338     }
339 
340     public void rebind(String name, Object value) throws NamingException
341     {
342         checkFrozen();
343         internalBind(name, value, true);
344     }
345 
346     public void rename(Name oldName, Name newName) throws NamingException
347     {
348         checkFrozen();
349         Object value = lookup(oldName);
350         unbind(oldName);
351         bind(newName, value);
352     }
353 
354     public void rename(String oldName, String newName) throws NamingException
355     {
356         Object value = lookup(oldName);
357         unbind(oldName);
358         bind(newName, value);
359     }
360 
361     public void unbind(Name name) throws NamingException
362     {
363         unbind(name.toString());
364     }
365 
366     public void unbind(String name) throws NamingException
367     {
368         checkFrozen();
369         internalBind(name, null, true);
370     }
371 
372     private abstract class AbstractLocalNamingEnumeration implements NamingEnumeration
373     {
374 
375         private Iterator i = bindings.entrySet().iterator();
376 
377         public boolean hasMore() throws NamingException
378         {
379             return i.hasNext();
380         }
381 
382         public boolean hasMoreElements()
383         {
384             return i.hasNext();
385         }
386 
387         protected Map.Entry getNext()
388         {
389             return (Map.Entry) i.next();
390         }
391 
392         public void close() throws NamingException
393         {
394         }
395     }
396 
397     private class ListEnumeration extends AbstractLocalNamingEnumeration
398     {
399 
400         public Object next() throws NamingException
401         {
402             return nextElement();
403         }
404 
405         public Object nextElement()
406         {
407             Map.Entry entry = getNext();
408             return new NameClassPair((String) entry.getKey(), entry.getValue().getClass().getName());
409         }
410     }
411 
412     private class ListBindingEnumeration extends AbstractLocalNamingEnumeration
413     {
414 
415         public Object next() throws NamingException
416         {
417             return nextElement();
418         }
419 
420         public Object nextElement()
421         {
422             Map.Entry entry = getNext();
423             return new Binding((String) entry.getKey(), entry.getValue());
424         }
425     }
426 
427     public Map getEntries()
428     {
429         return new HashMap(bindings);
430     }
431 
432     public void setEntries(Map entries) throws NamingException
433     {
434         if (entries != null)
435         {
436             for (Iterator iter = entries.entrySet().iterator(); iter.hasNext();)
437             {
438                 Map.Entry entry = (Map.Entry) iter.next();
439                 String name = (String) entry.getKey();
440                 Object value = entry.getValue();
441                 internalBind(name, value);
442             }
443         }
444     }
445 
446     public boolean isFreeze()
447     {
448         return freeze;
449     }
450 
451     public void setFreeze(boolean freeze)
452     {
453         this.freeze = freeze;
454     }
455 
456     /**
457      * internalBind is intended for use only during setup or possibly by suitably synchronized superclasses.
458      * It binds every possible lookup into a map in each context.  To do this, each context
459      * strips off one name segment and if necessary creates a new context for it. Then it asks that context
460      * to bind the remaining name.  It returns a map containing all the bindings from the next context, plus
461      * the context it just created (if it in fact created it). (the names are suitably extended by the segment
462      * originally lopped off).
463      *
464      * @param name
465      * @param value
466      * @throws javax.naming.NamingException
467      */
468     protected Map internalBind(String name, Object value) throws NamingException
469     {
470         return internalBind(name, value, false);
471 
472     }
473 
474     protected Map internalBind(String name, Object value, boolean allowRebind) throws NamingException
475     {
476         if (name == null || name.length() == 0)
477         {
478             throw new NamingException("Invalid Name " + name);
479         }
480         if (frozen)
481         {
482             throw new NamingException("Read only");
483         }
484 
485         Map newBindings = new HashMap();
486         int pos = name.indexOf('/');
487         if (pos == -1)
488         {
489             Object oldValue = treeBindings.put(name, value);
490             if (!allowRebind && oldValue != null)
491             {
492                 throw new NamingException("Something already bound at " + name);
493             }
494             bindings.put(name, value);
495             newBindings.put(name, value);
496         }
497         else
498         {
499             String segment = name.substring(0, pos);
500 
501             if (segment == null || segment.length() == 0)
502             {
503                 throw new NamingException("Invalid segment " + segment);
504             }
505             Object o = treeBindings.get(segment);
506             if (o == null)
507             {
508                 o = newContext();
509                 treeBindings.put(segment, o);
510                 bindings.put(segment, o);
511                 newBindings.put(segment, o);
512             }
513             else if (!(o instanceof DefaultSpringJndiContext))
514             {
515                 throw new NamingException("Something already bound where a subcontext should go");
516             }
517             DefaultSpringJndiContext defaultContext = (DefaultSpringJndiContext) o;
518             String remainder = name.substring(pos + 1);
519             Map subBindings = defaultContext.internalBind(remainder, value, allowRebind);
520             for (Iterator iterator = subBindings.entrySet().iterator(); iterator.hasNext();)
521             {
522                 Map.Entry entry = (Map.Entry) iterator.next();
523                 String subName = segment + "/" + (String) entry.getKey();
524                 Object bound = entry.getValue();
525                 treeBindings.put(subName, bound);
526                 newBindings.put(subName, bound);
527             }
528         }
529         return newBindings;
530     }
531 
532     protected void checkFrozen() throws OperationNotSupportedException
533     {
534         if (isFreeze())
535         {
536             throw new OperationNotSupportedException("JNDI context is frozen!");
537         }
538     }
539 
540     protected DefaultSpringJndiContext newContext()
541     {
542         return new DefaultSpringJndiContext();
543     }
544 
545 }
546