View Javadoc

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