View Javadoc

1   /***
2    *
3    * Copyright 2003-2004 The Apache Software Foundation
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  
18  package org.codehaus.activemq.jndi;
19  
20  import javax.naming.*;
21  import javax.naming.spi.NamingManager;
22  import java.io.Serializable;
23  import java.util.Collections;
24  import java.util.HashMap;
25  import java.util.Hashtable;
26  import java.util.Iterator;
27  import java.util.Map;
28  
29  /***
30   * A read-only Context
31   * <p/>
32   * This version assumes it and all its subcontext are read-only and any attempt
33   * to modify (e.g. through bind) will result in an OperationNotSupportedException.
34   * Each Context in the tree builds a cache of the entries in all sub-contexts
35   * to optimise the performance of lookup.
36   * </p>
37   * <p>This implementation is intended to optimise the performance of lookup(String)
38   * to about the level of a HashMap get. It has been observed that the scheme
39   * resolution phase performed by the JVM takes considerably longer, so for
40   * optimum performance lookups should be coded like:</p>
41   * <code>
42   * Context componentContext = (Context)new InitialContext().lookup("java:comp");
43   * String envEntry = (String) componentContext.lookup("env/myEntry");
44   * String envEntry2 = (String) componentContext.lookup("env/myEntry2");
45   * </code>
46   *
47   * @version $Revision: 1.3 $ $Date: 2004/09/01 10:18:41 $
48   */
49  public class ReadOnlyContext implements Context, Serializable {
50      private static final long serialVersionUID = -5754338187296859149L;
51      protected static final NameParser nameParser = new NameParserImpl();
52  
53      protected final Hashtable environment;        // environment for this context
54      protected final Map bindings;         // bindings at my level
55      protected final Map treeBindings;     // all bindings under me
56  
57      private boolean frozen = false;
58  
59      public ReadOnlyContext() {
60          environment = new Hashtable();
61          bindings = new HashMap();
62          treeBindings = new HashMap();
63      }
64  
65      public ReadOnlyContext(Hashtable env) {
66          if (env == null) {
67              this.environment = new Hashtable();
68          }
69          else {
70              this.environment = new Hashtable(env);
71          }
72          this.bindings = Collections.EMPTY_MAP;
73          this.treeBindings = Collections.EMPTY_MAP;
74      }
75  
76      public ReadOnlyContext(Hashtable environment, Map bindings) {
77          if (environment == null) {
78              this.environment = new Hashtable();
79          }
80          else {
81              this.environment = new Hashtable(environment);
82          }
83          this.bindings = bindings;
84          treeBindings = new HashMap();
85          frozen = true;
86      }
87  
88      protected ReadOnlyContext(ReadOnlyContext clone, Hashtable env) {
89          this.bindings = clone.bindings;
90          this.treeBindings = clone.treeBindings;
91          this.environment = new Hashtable(env);
92      }
93  
94      public void freeze() {
95          frozen = true;
96      }
97  
98      boolean isFrozen() {
99          return frozen;
100     }
101 
102     /***
103      * internalBind is intended for use only during setup or possibly by suitably synchronized superclasses.
104      * It binds every possible lookup into a map in each context.  To do this, each context
105      * strips off one name segment and if necessary creates a new context for it. Then it asks that context
106      * to bind the remaining name.  It returns a map containing all the bindings from the next context, plus
107      * the context it just created (if it in fact created it). (the names are suitably extended by the segment
108      * originally lopped off).
109      *
110      * @param name
111      * @param value
112      * @return
113      * @throws javax.naming.NamingException
114      */
115     protected Map internalBind(String name, Object value) throws NamingException {
116         assert name != null && name.length() > 0;
117         assert !frozen;
118 
119         Map newBindings = new HashMap();
120         int pos = name.indexOf('/');
121         if (pos == -1) {
122             if (treeBindings.put(name, value) != null) {
123                 throw new NamingException("Something already bound at " + name);
124             }
125             bindings.put(name, value);
126             newBindings.put(name, value);
127         }
128         else {
129             String segment = name.substring(0, pos);
130             assert segment != null;
131             assert !segment.equals("");
132             Object o = treeBindings.get(segment);
133             if (o == null) {
134                 o = newContext();
135                 treeBindings.put(segment, o);
136                 bindings.put(segment, o);
137                 newBindings.put(segment, o);
138             }
139             else if (!(o instanceof ReadOnlyContext)) {
140                 throw new NamingException("Something already bound where a subcontext should go");
141             }
142             ReadOnlyContext readOnlyContext = (ReadOnlyContext) o;
143             String remainder = name.substring(pos + 1);
144             Map subBindings = readOnlyContext.internalBind(remainder, value);
145             for (Iterator iterator = subBindings.entrySet().iterator(); iterator.hasNext();) {
146                 Map.Entry entry = (Map.Entry) iterator.next();
147                 String subName = segment + "/" + (String) entry.getKey();
148                 Object bound = entry.getValue();
149                 treeBindings.put(subName, bound);
150                 newBindings.put(subName, bound);
151             }
152         }
153         return newBindings;
154     }
155 
156     protected ReadOnlyContext newContext() {
157         return new ReadOnlyContext();
158     }
159 
160     public Object addToEnvironment(String propName, Object propVal) throws NamingException {
161         return environment.put(propName, propVal);
162     }
163 
164     public Hashtable getEnvironment() throws NamingException {
165         return (Hashtable) environment.clone();
166     }
167 
168     public Object removeFromEnvironment(String propName) throws NamingException {
169         return environment.remove(propName);
170     }
171 
172     public Object lookup(String name) throws NamingException {
173         if (name.length() == 0) {
174             return this;
175         }
176         Object result = treeBindings.get(name);
177         if (result == null) {
178             int pos = name.indexOf(':');
179             if (pos > 0) {
180                 String scheme = name.substring(0, pos);
181                 Context ctx = NamingManager.getURLContext(scheme, environment);
182                 if (ctx == null) {
183                     throw new NamingException("scheme " + scheme + " not recognized");
184                 }
185                 return ctx.lookup(name);
186             }
187             else {
188                 // Split out the first name of the path
189                 // and look for it in the bindings map.
190                 CompositeName path = new CompositeName(name);
191 
192                 if (path.size() == 0) {
193                     return this;
194                 }
195                 else {
196                     Object obj = bindings.get(path.get(0));
197                     if (obj == null) {
198                         throw new NameNotFoundException(name);
199                     }
200                     else if (obj instanceof Context && path.size() > 1) {
201                         Context subContext = (Context) obj;
202                         obj = subContext.lookup(path.getSuffix(1));
203                     }
204                     return obj;
205                 }
206             }
207         }
208         if (result instanceof LinkRef) {
209             LinkRef ref = (LinkRef) result;
210             result = lookup(ref.getLinkName());
211         }
212         if (result instanceof Reference) {
213             try {
214                 result = NamingManager.getObjectInstance(result, null, null, this.environment);
215             }
216             catch (NamingException e) {
217                 throw e;
218             }
219             catch (Exception e) {
220                 throw (NamingException) new NamingException("could not look up : " + name).initCause(e);
221             }
222         }
223         if (result instanceof ReadOnlyContext) {
224             result = new ReadOnlyContext((ReadOnlyContext) result, environment);
225         }
226         return result;
227     }
228 
229     public Object lookup(Name name) throws NamingException {
230         return lookup(name.toString());
231     }
232 
233     public Object lookupLink(String name) throws NamingException {
234         return lookup(name);
235     }
236 
237     public Name composeName(Name name, Name prefix) throws NamingException {
238         Name result = (Name) prefix.clone();
239         result.addAll(name);
240         return result;
241     }
242 
243     public String composeName(String name, String prefix) throws NamingException {
244         CompositeName result = new CompositeName(prefix);
245         result.addAll(new CompositeName(name));
246         return result.toString();
247     }
248 
249     public NamingEnumeration list(String name) throws NamingException {
250         Object o = lookup(name);
251         if (o == this) {
252             return new ListEnumeration();
253         }
254         else if (o instanceof Context) {
255             return ((Context) o).list("");
256         }
257         else {
258             throw new NotContextException();
259         }
260     }
261 
262     public NamingEnumeration listBindings(String name) throws NamingException {
263         Object o = lookup(name);
264         if (o == this) {
265             return new ListBindingEnumeration();
266         }
267         else if (o instanceof Context) {
268             return ((Context) o).listBindings("");
269         }
270         else {
271             throw new NotContextException();
272         }
273     }
274 
275     public Object lookupLink(Name name) throws NamingException {
276         return lookupLink(name.toString());
277     }
278 
279     public NamingEnumeration list(Name name) throws NamingException {
280         return list(name.toString());
281     }
282 
283     public NamingEnumeration listBindings(Name name) throws NamingException {
284         return listBindings(name.toString());
285     }
286 
287     public void bind(Name name, Object obj) throws NamingException {
288         throw new OperationNotSupportedException();
289     }
290 
291     public void bind(String name, Object obj) throws NamingException {
292         throw new OperationNotSupportedException();
293     }
294 
295     public void close() throws NamingException {
296         // ignore
297     }
298 
299     public Context createSubcontext(Name name) throws NamingException {
300         throw new OperationNotSupportedException();
301     }
302 
303     public Context createSubcontext(String name) throws NamingException {
304         throw new OperationNotSupportedException();
305     }
306 
307     public void destroySubcontext(Name name) throws NamingException {
308         throw new OperationNotSupportedException();
309     }
310 
311     public void destroySubcontext(String name) throws NamingException {
312         throw new OperationNotSupportedException();
313     }
314 
315     public String getNameInNamespace() throws NamingException {
316         throw new OperationNotSupportedException();
317     }
318 
319     public NameParser getNameParser(Name name) throws NamingException {
320         return nameParser;
321     }
322 
323     public NameParser getNameParser(String name) throws NamingException {
324         return nameParser;
325     }
326 
327     public void rebind(Name name, Object obj) throws NamingException {
328         throw new OperationNotSupportedException();
329     }
330 
331     public void rebind(String name, Object obj) throws NamingException {
332         throw new OperationNotSupportedException();
333     }
334 
335     public void rename(Name oldName, Name newName) throws NamingException {
336         throw new OperationNotSupportedException();
337     }
338 
339     public void rename(String oldName, String newName) throws NamingException {
340         throw new OperationNotSupportedException();
341     }
342 
343     public void unbind(Name name) throws NamingException {
344         throw new OperationNotSupportedException();
345     }
346 
347     public void unbind(String name) throws NamingException {
348         throw new OperationNotSupportedException();
349     }
350 
351     private abstract class LocalNamingEnumeration implements NamingEnumeration {
352         private Iterator i = bindings.entrySet().iterator();
353 
354         public boolean hasMore() throws NamingException {
355             return i.hasNext();
356         }
357 
358         public boolean hasMoreElements() {
359             return i.hasNext();
360         }
361 
362         protected Map.Entry getNext() {
363             return (Map.Entry) i.next();
364         }
365 
366         public void close() throws NamingException {
367         }
368     }
369 
370     private class ListEnumeration extends LocalNamingEnumeration {
371         public Object next() throws NamingException {
372             return nextElement();
373         }
374 
375         public Object nextElement() {
376             Map.Entry entry = getNext();
377             return new NameClassPair((String) entry.getKey(), entry.getValue().getClass().getName());
378         }
379     }
380 
381     private class ListBindingEnumeration extends LocalNamingEnumeration {
382         public Object next() throws NamingException {
383             return nextElement();
384         }
385 
386         public Object nextElement() {
387             Map.Entry entry = getNext();
388             return new Binding((String) entry.getKey(), entry.getValue());
389         }
390     }
391 }