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 }