View Javadoc

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