1 /* 2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.jndi.toolkit.ctx; 27 28 import java.util.Hashtable; 29 import java.util.Enumeration; 30 31 import javax.naming.*; 32 import javax.naming.spi.Resolver; 33 import javax.naming.spi.ResolveResult; 34 import javax.naming.spi.NamingManager; 35 36 /** 37 * PartialCompositeContext implements Context operations on 38 * composite names using implementations of the p_ interfaces 39 * defined by its subclasses. 40 * 41 * The main purpose provided by this class is that it deals with 42 * partial resolutions and continuations, so that callers of the 43 * Context operation don't have to. 44 * 45 * Types of clients that will be direct subclasses of 46 * PartialCompositeContext may be service providers that implement 47 * one of the JNDI protocols, but which do not deal with 48 * continuations. Usually, service providers will be using 49 * one of the subclasses of PartialCompositeContext. 50 * 51 * @author Rosanna Lee 52 */ 53 54 55 public abstract class PartialCompositeContext implements Context, Resolver { 56 protected static final int _PARTIAL = 1; 57 protected static final int _COMPONENT = 2; 58 protected static final int _ATOMIC = 3; 59 60 protected int _contextType = _PARTIAL; 61 62 static final CompositeName _EMPTY_NAME = new CompositeName(); 63 static CompositeName _NNS_NAME; 64 65 static { 66 try { 67 _NNS_NAME = new CompositeName("/"); 68 } catch (InvalidNameException e) { 69 // Should never happen 70 } 71 } 72 73 protected PartialCompositeContext() { 74 } 75 76 // ------ Abstract methods whose implementations come from subclasses 77 78 /* Equivalent to method in Resolver interface */ 79 protected abstract ResolveResult p_resolveToClass(Name name, 80 Class<?> contextType, Continuation cont) throws NamingException; 81 82 /* Equivalent to methods in Context interface */ 83 protected abstract Object p_lookup(Name name, Continuation cont) 84 throws NamingException; 85 protected abstract Object p_lookupLink(Name name, Continuation cont) 86 throws NamingException; 87 protected abstract NamingEnumeration<NameClassPair> p_list(Name name, 88 Continuation cont) throws NamingException; 89 protected abstract NamingEnumeration<Binding> p_listBindings(Name name, 90 Continuation cont) throws NamingException; 91 protected abstract void p_bind(Name name, Object obj, Continuation cont) 92 throws NamingException; 93 protected abstract void p_rebind(Name name, Object obj, Continuation cont) 94 throws NamingException; 95 protected abstract void p_unbind(Name name, Continuation cont) 96 throws NamingException; 97 protected abstract void p_destroySubcontext(Name name, Continuation cont) 98 throws NamingException; 99 protected abstract Context p_createSubcontext(Name name, Continuation cont) 100 throws NamingException; 101 protected abstract void p_rename(Name oldname, Name newname, 102 Continuation cont) 103 throws NamingException; 104 protected abstract NameParser p_getNameParser(Name name, Continuation cont) 105 throws NamingException; 106 107 // ------ should be overridden by subclass; 108 // ------ not abstract only for backward compatibility 109 110 /** 111 * A cheap way of getting the environment. 112 * Default implementation is NOT cheap because it simply calls 113 * getEnvironment(), which most implementations clone before returning. 114 * Subclass should ALWAYS override this with the cheapest possible way. 115 * The toolkit knows to clone when necessary. 116 * @return The possibly null environment of the context. 117 */ 118 protected Hashtable<?,?> p_getEnvironment() throws NamingException { 119 return getEnvironment(); 120 } 121 122 123 // ------ implementations of methods in Resolver and Context 124 // ------ using corresponding p_ methods provided by subclass 125 126 /* implementations for method in Resolver interface using p_ method */ 127 128 public ResolveResult resolveToClass(String name, 129 Class<? extends Context> contextType) 130 throws NamingException 131 { 132 return resolveToClass(new CompositeName(name), contextType); 133 } 134 135 public ResolveResult resolveToClass(Name name, 136 Class<? extends Context> contextType) 137 throws NamingException 138 { 139 PartialCompositeContext ctx = this; 140 Hashtable<?,?> env = p_getEnvironment(); 141 Continuation cont = new Continuation(name, env); 142 ResolveResult answer; 143 Name nm = name; 144 145 try { 146 answer = ctx.p_resolveToClass(nm, contextType, cont); 147 while (cont.isContinue()) { 148 nm = cont.getRemainingName(); 149 ctx = getPCContext(cont); 150 answer = ctx.p_resolveToClass(nm, contextType, cont); 151 } 152 } catch (CannotProceedException e) { 153 Context cctx = NamingManager.getContinuationContext(e); 154 if (!(cctx instanceof Resolver)) { 155 throw e; 156 } 157 answer = ((Resolver)cctx).resolveToClass(e.getRemainingName(), 158 contextType); 159 } 160 return answer; 161 } 162 163 /* implementations for methods in Context interface using p_ methods */ 164 165 public Object lookup(String name) throws NamingException { 166 return lookup(new CompositeName(name)); 167 } 168 169 public Object lookup(Name name) throws NamingException { 170 PartialCompositeContext ctx = this; 171 Hashtable<?,?> env = p_getEnvironment(); 172 Continuation cont = new Continuation(name, env); 173 Object answer; 174 Name nm = name; 175 176 try { 177 answer = ctx.p_lookup(nm, cont); 178 while (cont.isContinue()) { 179 nm = cont.getRemainingName(); 180 ctx = getPCContext(cont); 181 answer = ctx.p_lookup(nm, cont); 182 } 183 } catch (CannotProceedException e) { 184 Context cctx = NamingManager.getContinuationContext(e); 185 answer = cctx.lookup(e.getRemainingName()); 186 } 187 return answer; 188 } 189 190 public void bind(String name, Object newObj) throws NamingException { 191 bind(new CompositeName(name), newObj); 192 } 193 194 public void bind(Name name, Object newObj) throws NamingException { 195 PartialCompositeContext ctx = this; 196 Name nm = name; 197 Hashtable<?,?> env = p_getEnvironment(); 198 Continuation cont = new Continuation(name, env); 199 200 try { 201 ctx.p_bind(nm, newObj, cont); 202 while (cont.isContinue()) { 203 nm = cont.getRemainingName(); 204 ctx = getPCContext(cont); 205 ctx.p_bind(nm, newObj, cont); 206 } 207 } catch (CannotProceedException e) { 208 Context cctx = NamingManager.getContinuationContext(e); 209 cctx.bind(e.getRemainingName(), newObj); 210 } 211 } 212 213 public void rebind(String name, Object newObj) throws NamingException { 214 rebind(new CompositeName(name), newObj); 215 } 216 public void rebind(Name name, Object newObj) throws NamingException { 217 PartialCompositeContext ctx = this; 218 Name nm = name; 219 Hashtable<?,?> env = p_getEnvironment(); 220 Continuation cont = new Continuation(name, env); 221 222 try { 223 ctx.p_rebind(nm, newObj, cont); 224 while (cont.isContinue()) { 225 nm = cont.getRemainingName(); 226 ctx = getPCContext(cont); 227 ctx.p_rebind(nm, newObj, cont); 228 } 229 } catch (CannotProceedException e) { 230 Context cctx = NamingManager.getContinuationContext(e); 231 cctx.rebind(e.getRemainingName(), newObj); 232 } 233 } 234 235 public void unbind(String name) throws NamingException { 236 unbind(new CompositeName(name)); 237 } 238 public void unbind(Name name) throws NamingException { 239 PartialCompositeContext ctx = this; 240 Name nm = name; 241 Hashtable<?,?> env = p_getEnvironment(); 242 Continuation cont = new Continuation(name, env); 243 244 try { 245 ctx.p_unbind(nm, cont); 246 while (cont.isContinue()) { 247 nm = cont.getRemainingName(); 248 ctx = getPCContext(cont); 249 ctx.p_unbind(nm, cont); 250 } 251 } catch (CannotProceedException e) { 252 Context cctx = NamingManager.getContinuationContext(e); 253 cctx.unbind(e.getRemainingName()); 254 } 255 } 256 257 public void rename(String oldName, String newName) throws NamingException { 258 rename(new CompositeName(oldName), new CompositeName(newName)); 259 } 260 public void rename(Name oldName, Name newName) 261 throws NamingException 262 { 263 PartialCompositeContext ctx = this; 264 Name nm = oldName; 265 Hashtable<?,?> env = p_getEnvironment(); 266 Continuation cont = new Continuation(oldName, env); 267 268 try { 269 ctx.p_rename(nm, newName, cont); 270 while (cont.isContinue()) { 271 nm = cont.getRemainingName(); 272 ctx = getPCContext(cont); 273 ctx.p_rename(nm, newName, cont); 274 } 275 } catch (CannotProceedException e) { 276 Context cctx = NamingManager.getContinuationContext(e); 277 if (e.getRemainingNewName() != null) { 278 // %%% e.getRemainingNewName() should never be null 279 newName = e.getRemainingNewName(); 280 } 281 cctx.rename(e.getRemainingName(), newName); 282 } 283 } 284 285 public NamingEnumeration<NameClassPair> list(String name) 286 throws NamingException 287 { 288 return list(new CompositeName(name)); 289 } 290 291 public NamingEnumeration<NameClassPair> list(Name name) 292 throws NamingException 293 { 294 PartialCompositeContext ctx = this; 295 Name nm = name; 296 NamingEnumeration<NameClassPair> answer; 297 Hashtable<?,?> env = p_getEnvironment(); 298 Continuation cont = new Continuation(name, env); 299 300 try { 301 answer = ctx.p_list(nm, cont); 302 while (cont.isContinue()) { 303 nm = cont.getRemainingName(); 304 ctx = getPCContext(cont); 305 answer = ctx.p_list(nm, cont); 306 } 307 } catch (CannotProceedException e) { 308 Context cctx = NamingManager.getContinuationContext(e); 309 answer = cctx.list(e.getRemainingName()); 310 } 311 return answer; 312 } 313 314 public NamingEnumeration<Binding> listBindings(String name) 315 throws NamingException 316 { 317 return listBindings(new CompositeName(name)); 318 } 319 320 public NamingEnumeration<Binding> listBindings(Name name) 321 throws NamingException 322 { 323 PartialCompositeContext ctx = this; 324 Name nm = name; 325 NamingEnumeration<Binding> answer; 326 Hashtable<?,?> env = p_getEnvironment(); 327 Continuation cont = new Continuation(name, env); 328 329 try { 330 answer = ctx.p_listBindings(nm, cont); 331 while (cont.isContinue()) { 332 nm = cont.getRemainingName(); 333 ctx = getPCContext(cont); 334 answer = ctx.p_listBindings(nm, cont); 335 } 336 } catch (CannotProceedException e) { 337 Context cctx = NamingManager.getContinuationContext(e); 338 answer = cctx.listBindings(e.getRemainingName()); 339 } 340 return answer; 341 } 342 343 public void destroySubcontext(String name) throws NamingException { 344 destroySubcontext(new CompositeName(name)); 345 } 346 347 public void destroySubcontext(Name name) throws NamingException { 348 PartialCompositeContext ctx = this; 349 Name nm = name; 350 Hashtable<?,?> env = p_getEnvironment(); 351 Continuation cont = new Continuation(name, env); 352 353 try { 354 ctx.p_destroySubcontext(nm, cont); 355 while (cont.isContinue()) { 356 nm = cont.getRemainingName(); 357 ctx = getPCContext(cont); 358 ctx.p_destroySubcontext(nm, cont); 359 } 360 } catch (CannotProceedException e) { 361 Context cctx = NamingManager.getContinuationContext(e); 362 cctx.destroySubcontext(e.getRemainingName()); 363 } 364 } 365 366 public Context createSubcontext(String name) throws NamingException { 367 return createSubcontext(new CompositeName(name)); 368 } 369 370 public Context createSubcontext(Name name) throws NamingException { 371 PartialCompositeContext ctx = this; 372 Name nm = name; 373 Context answer; 374 Hashtable<?,?> env = p_getEnvironment(); 375 Continuation cont = new Continuation(name, env); 376 377 try { 378 answer = ctx.p_createSubcontext(nm, cont); 379 while (cont.isContinue()) { 380 nm = cont.getRemainingName(); 381 ctx = getPCContext(cont); 382 answer = ctx.p_createSubcontext(nm, cont); 383 } 384 } catch (CannotProceedException e) { 385 Context cctx = NamingManager.getContinuationContext(e); 386 answer = cctx.createSubcontext(e.getRemainingName()); 387 } 388 return answer; 389 } 390 391 public Object lookupLink(String name) throws NamingException { 392 return lookupLink(new CompositeName(name)); 393 } 394 395 public Object lookupLink(Name name) throws NamingException { 396 PartialCompositeContext ctx = this; 397 Hashtable<?,?> env = p_getEnvironment(); 398 Continuation cont = new Continuation(name, env); 399 Object answer; 400 Name nm = name; 401 402 try { 403 answer = ctx.p_lookupLink(nm, cont); 404 while (cont.isContinue()) { 405 nm = cont.getRemainingName(); 406 ctx = getPCContext(cont); 407 answer = ctx.p_lookupLink(nm, cont); 408 } 409 } catch (CannotProceedException e) { 410 Context cctx = NamingManager.getContinuationContext(e); 411 answer = cctx.lookupLink(e.getRemainingName()); 412 } 413 return answer; 414 } 415 416 public NameParser getNameParser(String name) throws NamingException { 417 return getNameParser(new CompositeName(name)); 418 } 419 420 public NameParser getNameParser(Name name) throws NamingException { 421 PartialCompositeContext ctx = this; 422 Name nm = name; 423 NameParser answer; 424 Hashtable<?,?> env = p_getEnvironment(); 425 Continuation cont = new Continuation(name, env); 426 427 try { 428 answer = ctx.p_getNameParser(nm, cont); 429 while (cont.isContinue()) { 430 nm = cont.getRemainingName(); 431 ctx = getPCContext(cont); 432 answer = ctx.p_getNameParser(nm, cont); 433 } 434 } catch (CannotProceedException e) { 435 Context cctx = NamingManager.getContinuationContext(e); 436 answer = cctx.getNameParser(e.getRemainingName()); 437 } 438 return answer; 439 } 440 441 public String composeName(String name, String prefix) 442 throws NamingException { 443 Name fullName = composeName(new CompositeName(name), 444 new CompositeName(prefix)); 445 return fullName.toString(); 446 } 447 448 /** 449 * This default implementation simply concatenates the two names. 450 * There's one twist when the "java.naming.provider.compose.elideEmpty" 451 * environment setting is set to "true": if each name contains a 452 * nonempty component, and if 'prefix' ends with an empty component or 453 * 'name' starts with one, then one empty component is dropped. 454 * For example: 455 * <pre>{@code 456 * elideEmpty=false elideEmpty=true 457 * {"a"} + {"b"} => {"a", "b"} {"a", "b"} 458 * {"a"} + {""} => {"a", ""} {"a", ""} 459 * {"a"} + {"", "b"} => {"a", "", "b"} {"a", "b"} 460 * {"a", ""} + {"b", ""} => {"a", "", "b", ""} {"a", "b", ""} 461 * {"a", ""} + {"", "b"} => {"a", "", "", "b"} {"a", "", "b"} 462 * }</pre> 463 */ 464 public Name composeName(Name name, Name prefix) throws NamingException { 465 Name res = (Name)prefix.clone(); 466 if (name == null) { 467 return res; 468 } 469 res.addAll(name); 470 471 String elide = (String) 472 p_getEnvironment().get("java.naming.provider.compose.elideEmpty"); 473 if (elide == null || !elide.equalsIgnoreCase("true")) { 474 return res; 475 } 476 477 int len = prefix.size(); 478 479 if (!allEmpty(prefix) && !allEmpty(name)) { 480 if (res.get(len - 1).isEmpty()) { 481 res.remove(len - 1); 482 } else if (res.get(len).isEmpty()) { 483 res.remove(len); 484 } 485 } 486 return res; 487 } 488 489 490 // ------ internal methods used by PartialCompositeContext 491 492 /** 493 * Tests whether a name contains a nonempty component. 494 */ 495 protected static boolean allEmpty(Name name) { 496 Enumeration<String> enum_ = name.getAll(); 497 while (enum_.hasMoreElements()) { 498 if (!enum_.nextElement().isEmpty()) { 499 return false; 500 } 501 } 502 return true; 503 } 504 505 /** 506 * Retrieves a PartialCompositeContext for the resolved object in 507 * cont. Throws CannotProceedException if not successful. 508 */ 509 protected static PartialCompositeContext getPCContext(Continuation cont) 510 throws NamingException { 511 512 Object obj = cont.getResolvedObj(); 513 PartialCompositeContext pctx = null; 514 515 if (obj instanceof PartialCompositeContext) { 516 // Just cast if octx already is PartialCompositeContext 517 // %%% ignoring environment for now 518 return (PartialCompositeContext)obj; 519 } else { 520 throw cont.fillInException(new CannotProceedException()); 521 } 522 } 523 };