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