001 /** 002 * 003 * Copyright 2003-2004 The Apache Software Foundation 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.activemq.jndi; 019 020 import javax.naming.*; 021 import javax.naming.spi.NamingManager; 022 import java.io.Serializable; 023 import java.util.Collections; 024 import java.util.HashMap; 025 import java.util.Hashtable; 026 import java.util.Iterator; 027 import java.util.Map; 028 029 /** 030 * A read-only Context 031 * <p/> 032 * This version assumes it and all its subcontext are read-only and any attempt 033 * to modify (e.g. through bind) will result in an OperationNotSupportedException. 034 * Each Context in the tree builds a cache of the entries in all sub-contexts 035 * to optimise the performance of lookup. 036 * </p> 037 * <p>This implementation is intended to optimise the performance of lookup(String) 038 * to about the level of a HashMap get. It has been observed that the scheme 039 * resolution phase performed by the JVM takes considerably longer, so for 040 * optimum performance lookups should be coded like:</p> 041 * <code> 042 * Context componentContext = (Context)new InitialContext().lookup("java:comp"); 043 * String envEntry = (String) componentContext.lookup("env/myEntry"); 044 * String envEntry2 = (String) componentContext.lookup("env/myEntry2"); 045 * </code> 046 * 047 * @version $Revision: 1.1.1.1 $ $Date: 2005/03/11 21:14:27 $ 048 */ 049 public class ReadOnlyContext implements Context, Serializable { 050 private static final long serialVersionUID = -5754338187296859149L; 051 protected static final NameParser nameParser = new NameParserImpl(); 052 053 protected final Hashtable environment; // environment for this context 054 protected final Map bindings; // bindings at my level 055 protected final Map treeBindings; // all bindings under me 056 057 private boolean frozen = false; 058 private String nameInNamespace = ""; 059 public static final String SEPARATOR = "/"; 060 061 public ReadOnlyContext() { 062 environment = new Hashtable(); 063 bindings = new HashMap(); 064 treeBindings = new HashMap(); 065 } 066 067 public ReadOnlyContext(Hashtable env) { 068 if (env == null) { 069 this.environment = new Hashtable(); 070 } 071 else { 072 this.environment = new Hashtable(env); 073 } 074 this.bindings = Collections.EMPTY_MAP; 075 this.treeBindings = Collections.EMPTY_MAP; 076 } 077 078 public ReadOnlyContext(Hashtable environment, Map bindings) { 079 if (environment == null) { 080 this.environment = new Hashtable(); 081 } 082 else { 083 this.environment = new Hashtable(environment); 084 } 085 this.bindings = bindings; 086 treeBindings = new HashMap(); 087 frozen = true; 088 } 089 090 public ReadOnlyContext(Hashtable environment, Map bindings, String nameInNamespace) { 091 this(environment, bindings); 092 this.nameInNamespace = nameInNamespace; 093 } 094 095 protected ReadOnlyContext(ReadOnlyContext clone, Hashtable env) { 096 this.bindings = clone.bindings; 097 this.treeBindings = clone.treeBindings; 098 this.environment = new Hashtable(env); 099 } 100 101 protected ReadOnlyContext(ReadOnlyContext clone, Hashtable env, String nameInNamespace) { 102 this(clone, env); 103 this.nameInNamespace = nameInNamespace; 104 } 105 106 public void freeze() { 107 frozen = true; 108 } 109 110 boolean isFrozen() { 111 return frozen; 112 } 113 114 /** 115 * internalBind is intended for use only during setup or possibly by suitably synchronized superclasses. 116 * It binds every possible lookup into a map in each context. To do this, each context 117 * strips off one name segment and if necessary creates a new context for it. Then it asks that context 118 * to bind the remaining name. It returns a map containing all the bindings from the next context, plus 119 * the context it just created (if it in fact created it). (the names are suitably extended by the segment 120 * originally lopped off). 121 * 122 * @param name 123 * @param value 124 * @return 125 * @throws javax.naming.NamingException 126 */ 127 protected Map internalBind(String name, Object value) throws NamingException { 128 assert name != null && name.length() > 0; 129 assert !frozen; 130 131 Map newBindings = new HashMap(); 132 int pos = name.indexOf('/'); 133 if (pos == -1) { 134 if (treeBindings.put(name, value) != null) { 135 throw new NamingException("Something already bound at " + name); 136 } 137 bindings.put(name, value); 138 newBindings.put(name, value); 139 } 140 else { 141 String segment = name.substring(0, pos); 142 assert segment != null; 143 assert !segment.equals(""); 144 Object o = treeBindings.get(segment); 145 if (o == null) { 146 o = newContext(); 147 treeBindings.put(segment, o); 148 bindings.put(segment, o); 149 newBindings.put(segment, o); 150 } 151 else if (!(o instanceof ReadOnlyContext)) { 152 throw new NamingException("Something already bound where a subcontext should go"); 153 } 154 ReadOnlyContext readOnlyContext = (ReadOnlyContext) o; 155 String remainder = name.substring(pos + 1); 156 Map subBindings = readOnlyContext.internalBind(remainder, value); 157 for (Iterator iterator = subBindings.entrySet().iterator(); iterator.hasNext();) { 158 Map.Entry entry = (Map.Entry) iterator.next(); 159 String subName = segment + "/" + (String) entry.getKey(); 160 Object bound = entry.getValue(); 161 treeBindings.put(subName, bound); 162 newBindings.put(subName, bound); 163 } 164 } 165 return newBindings; 166 } 167 168 protected ReadOnlyContext newContext() { 169 return new ReadOnlyContext(); 170 } 171 172 public Object addToEnvironment(String propName, Object propVal) throws NamingException { 173 return environment.put(propName, propVal); 174 } 175 176 public Hashtable getEnvironment() throws NamingException { 177 return (Hashtable) environment.clone(); 178 } 179 180 public Object removeFromEnvironment(String propName) throws NamingException { 181 return environment.remove(propName); 182 } 183 184 public Object lookup(String name) throws NamingException { 185 if (name.length() == 0) { 186 return this; 187 } 188 Object result = treeBindings.get(name); 189 if (result == null) { 190 result = bindings.get(name); 191 } 192 if (result == null) { 193 int pos = name.indexOf(':'); 194 if (pos > 0) { 195 String scheme = name.substring(0, pos); 196 Context ctx = NamingManager.getURLContext(scheme, environment); 197 if (ctx == null) { 198 throw new NamingException("scheme " + scheme + " not recognized"); 199 } 200 return ctx.lookup(name); 201 } 202 else { 203 // Split out the first name of the path 204 // and look for it in the bindings map. 205 CompositeName path = new CompositeName(name); 206 207 if (path.size() == 0) { 208 return this; 209 } 210 else { 211 String first = path.get(0); 212 Object obj = bindings.get(first); 213 if (obj == null) { 214 throw new NameNotFoundException(name); 215 } 216 else if (obj instanceof Context && path.size() > 1) { 217 Context subContext = (Context) obj; 218 obj = subContext.lookup(path.getSuffix(1)); 219 } 220 return obj; 221 } 222 } 223 } 224 if (result instanceof LinkRef) { 225 LinkRef ref = (LinkRef) result; 226 result = lookup(ref.getLinkName()); 227 } 228 if (result instanceof Reference) { 229 try { 230 result = NamingManager.getObjectInstance(result, null, null, this.environment); 231 } 232 catch (NamingException e) { 233 throw e; 234 } 235 catch (Exception e) { 236 throw (NamingException) new NamingException("could not look up : " + name).initCause(e); 237 } 238 } 239 if (result instanceof ReadOnlyContext) { 240 String prefix = getNameInNamespace(); 241 if (prefix.length() > 0) { 242 prefix = prefix + SEPARATOR; 243 } 244 result = new ReadOnlyContext((ReadOnlyContext) result, environment, prefix + name); 245 } 246 return result; 247 } 248 249 public Object lookup(Name name) throws NamingException { 250 return lookup(name.toString()); 251 } 252 253 public Object lookupLink(String name) throws NamingException { 254 return lookup(name); 255 } 256 257 public Name composeName(Name name, Name prefix) throws NamingException { 258 Name result = (Name) prefix.clone(); 259 result.addAll(name); 260 return result; 261 } 262 263 public String composeName(String name, String prefix) throws NamingException { 264 CompositeName result = new CompositeName(prefix); 265 result.addAll(new CompositeName(name)); 266 return result.toString(); 267 } 268 269 public NamingEnumeration list(String name) throws NamingException { 270 Object o = lookup(name); 271 if (o == this) { 272 return new ListEnumeration(); 273 } 274 else if (o instanceof Context) { 275 return ((Context) o).list(""); 276 } 277 else { 278 throw new NotContextException(); 279 } 280 } 281 282 public NamingEnumeration listBindings(String name) throws NamingException { 283 Object o = lookup(name); 284 if (o == this) { 285 return new ListBindingEnumeration(); 286 } 287 else if (o instanceof Context) { 288 return ((Context) o).listBindings(""); 289 } 290 else { 291 throw new NotContextException(); 292 } 293 } 294 295 public Object lookupLink(Name name) throws NamingException { 296 return lookupLink(name.toString()); 297 } 298 299 public NamingEnumeration list(Name name) throws NamingException { 300 return list(name.toString()); 301 } 302 303 public NamingEnumeration listBindings(Name name) throws NamingException { 304 return listBindings(name.toString()); 305 } 306 307 public void bind(Name name, Object obj) throws NamingException { 308 throw new OperationNotSupportedException(); 309 } 310 311 public void bind(String name, Object obj) throws NamingException { 312 throw new OperationNotSupportedException(); 313 } 314 315 public void close() throws NamingException { 316 // ignore 317 } 318 319 public Context createSubcontext(Name name) throws NamingException { 320 throw new OperationNotSupportedException(); 321 } 322 323 public Context createSubcontext(String name) throws NamingException { 324 throw new OperationNotSupportedException(); 325 } 326 327 public void destroySubcontext(Name name) throws NamingException { 328 throw new OperationNotSupportedException(); 329 } 330 331 public void destroySubcontext(String name) throws NamingException { 332 throw new OperationNotSupportedException(); 333 } 334 335 public String getNameInNamespace() throws NamingException { 336 return nameInNamespace; 337 } 338 339 public NameParser getNameParser(Name name) throws NamingException { 340 return nameParser; 341 } 342 343 public NameParser getNameParser(String name) throws NamingException { 344 return nameParser; 345 } 346 347 public void rebind(Name name, Object obj) throws NamingException { 348 throw new OperationNotSupportedException(); 349 } 350 351 public void rebind(String name, Object obj) throws NamingException { 352 throw new OperationNotSupportedException(); 353 } 354 355 public void rename(Name oldName, Name newName) throws NamingException { 356 throw new OperationNotSupportedException(); 357 } 358 359 public void rename(String oldName, String newName) throws NamingException { 360 throw new OperationNotSupportedException(); 361 } 362 363 public void unbind(Name name) throws NamingException { 364 throw new OperationNotSupportedException(); 365 } 366 367 public void unbind(String name) throws NamingException { 368 throw new OperationNotSupportedException(); 369 } 370 371 private abstract class LocalNamingEnumeration implements NamingEnumeration { 372 private Iterator i = bindings.entrySet().iterator(); 373 374 public boolean hasMore() throws NamingException { 375 return i.hasNext(); 376 } 377 378 public boolean hasMoreElements() { 379 return i.hasNext(); 380 } 381 382 protected Map.Entry getNext() { 383 return (Map.Entry) i.next(); 384 } 385 386 public void close() throws NamingException { 387 } 388 } 389 390 private class ListEnumeration extends LocalNamingEnumeration { 391 public Object next() throws NamingException { 392 return nextElement(); 393 } 394 395 public Object nextElement() { 396 Map.Entry entry = getNext(); 397 return new NameClassPair((String) entry.getKey(), entry.getValue().getClass().getName()); 398 } 399 } 400 401 private class ListBindingEnumeration extends LocalNamingEnumeration { 402 public Object next() throws NamingException { 403 return nextElement(); 404 } 405 406 public Object nextElement() { 407 Map.Entry entry = getNext(); 408 return new Binding((String) entry.getKey(), entry.getValue()); 409 } 410 } 411 }