1 /* 2 * Copyright (c) 1999, 2011, 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 javax.naming.*; 29 30 /** 31 * Clients: deal only with names for its own naming service 32 * and deals with single contexts that can be built up into 33 * hierarchical naming systems. 34 * Direct subclasses of AtomicContext must provide implementations for 35 * the abstract a_ Context methods, and c_parseComponent(). 36 * 37 * If the subclass implements the notion of implicit nns, 38 * it must override the a_*_nns Context methods as well. 39 * 40 * @author Rosanna Lee 41 * 42 */ 43 44 public abstract class AtomicContext extends ComponentContext { 45 private static int debug = 0; 46 47 protected AtomicContext () { 48 _contextType = _ATOMIC; 49 } 50 51 // ------ Abstract methods whose implementation are provided by subclasses 52 53 54 /* Equivalent to Context methods */ 55 protected abstract Object a_lookup(String name, Continuation cont) 56 throws NamingException; 57 protected abstract Object a_lookupLink(String name, Continuation cont) 58 throws NamingException; 59 60 protected abstract NamingEnumeration<NameClassPair> a_list( 61 Continuation cont) throws NamingException; 62 protected abstract NamingEnumeration<Binding> a_listBindings( 63 Continuation cont) throws NamingException; 64 protected abstract void a_bind(String name, Object obj, Continuation cont) 65 throws NamingException; 66 protected abstract void a_rebind(String name, Object obj, Continuation cont) 67 throws NamingException; 68 protected abstract void a_unbind(String name, Continuation cont) 69 throws NamingException; 70 protected abstract void a_destroySubcontext(String name, Continuation cont) 71 throws NamingException; 72 protected abstract Context a_createSubcontext(String name, 73 Continuation cont) throws NamingException; 74 protected abstract void a_rename(String oldname, Name newname, 75 Continuation cont) throws NamingException; 76 protected abstract NameParser a_getNameParser(Continuation cont) 77 throws NamingException; 78 79 /* Parsing */ 80 /** 81 * Parse 'inputName' into two parts: 82 * head: the first component in this name 83 * tail: the rest of the unused name. 84 * 85 * Subclasses should provide an implementation for this method 86 * which parses inputName using its own name syntax. 87 */ 88 protected abstract StringHeadTail c_parseComponent(String inputName, 89 Continuation cont) throws NamingException; 90 91 92 // ------ Methods that need to be overridden by subclass 93 94 /* Resolution method for supporting federation */ 95 /** 96 * Resolves the nns for 'name' when the named context is acting 97 * as an intermediate context. 98 * 99 * For a system that supports junctions, this would be equivalent to 100 * a_lookup(name, cont); 101 * because for junctions, an intermediate slash simply signifies 102 * a syntactic separator. 103 * 104 * For a system that supports implicit nns, this would be equivalent to 105 * a_lookup_nns(name, cont); 106 * because for implicit nns, a slash always signifies the implicit nns, 107 * regardless of whether it is intermediate or trailing. 108 * 109 * By default this method supports junctions, and also allows for an 110 * implicit nns to be dynamically determined through the use of the 111 * "nns" reference (see a_processJunction_nns()). 112 * Contexts that implement implicit nns directly should provide an 113 * appropriate override. 114 */ 115 protected Object a_resolveIntermediate_nns(String name, Continuation cont) 116 throws NamingException { 117 try { 118 final Object obj = a_lookup(name, cont); 119 120 // Do not append "" to Continuation 'cont' even if set 121 // because the intention is to ignore the nns 122 123 // 124 if (obj != null && getClass().isInstance(obj)) { 125 // If "obj" is in the same type as this object, it must 126 // not be a junction. Continue the lookup with "/". 127 128 cont.setContinueNNS(obj, name, this); 129 return null; 130 131 } else if (obj != null && !(obj instanceof Context)) { 132 // obj is not even a context, so try to find its nns 133 // dynamically by constructing a Reference containing obj. 134 RefAddr addr = new RefAddr("nns") { 135 public Object getContent() { 136 return obj; 137 } 138 private static final long serialVersionUID = 139 -3399518522645918499L; 140 }; 141 Reference ref = new Reference("java.lang.Object", addr); 142 143 // Resolved name has trailing slash to indicate nns 144 CompositeName resName = new CompositeName(); 145 resName.add(name); 146 resName.add(""); // add trailing slash 147 148 // Set continuation leave it to 149 // PartialCompositeContext.getPCContext() to throw CPE. 150 // Do not use setContinueNNS() because we've already 151 // consumed "/" (i.e., moved it to resName). 152 153 cont.setContinue(ref, resName, this); 154 return null; 155 156 } else { 157 return obj; 158 } 159 160 } catch (NamingException e) { 161 e.appendRemainingComponent(""); // add nns back 162 throw e; 163 } 164 } 165 166 /* Equivalent of Context Methods for supporting nns */ 167 168 // The following methods are called when the DirContext methods 169 // are invoked with a name that has a trailing slash. 170 // For naming systems that support implicit nns, 171 // the trailing slash signifies the implicit nns. 172 // For such naming systems, override these a_*_nns methods. 173 // 174 // For naming systems that support junctions (explicit nns), 175 // the trailing slash is meaningless because a junction does not 176 // have an implicit nns. The default implementation here 177 // throws a NameNotFoundException for such names. 178 // If a context wants to accept a trailing slash as having 179 // the same meaning as the same name without a trailing slash, 180 // then it should override these a_*_nns methods. 181 182 183 protected Object a_lookup_nns(String name, Continuation cont) 184 throws NamingException { 185 a_processJunction_nns(name, cont); 186 return null; 187 } 188 189 protected Object a_lookupLink_nns(String name, Continuation cont) 190 throws NamingException { 191 a_processJunction_nns(name, cont); 192 return null; 193 } 194 195 protected NamingEnumeration<NameClassPair> a_list_nns(Continuation cont) 196 throws NamingException { 197 a_processJunction_nns(cont); 198 return null; 199 } 200 protected NamingEnumeration<Binding> a_listBindings_nns(Continuation cont) 201 throws NamingException { 202 a_processJunction_nns(cont); 203 return null; 204 } 205 206 protected void a_bind_nns(String name, Object obj, Continuation cont) 207 throws NamingException { 208 a_processJunction_nns(name, cont); 209 } 210 211 protected void a_rebind_nns(String name, Object obj, Continuation cont) 212 throws NamingException { 213 a_processJunction_nns(name, cont); 214 } 215 216 protected void a_unbind_nns(String name, Continuation cont) 217 throws NamingException { 218 a_processJunction_nns(name, cont); 219 } 220 221 protected Context a_createSubcontext_nns(String name, Continuation cont) 222 throws NamingException { 223 a_processJunction_nns(name, cont); 224 return null; 225 } 226 227 protected void a_destroySubcontext_nns(String name, Continuation cont) 228 throws NamingException { 229 a_processJunction_nns(name, cont); 230 } 231 232 protected void a_rename_nns(String oldname, Name newname, Continuation cont) 233 throws NamingException { 234 a_processJunction_nns(oldname, cont); 235 } 236 237 protected NameParser a_getNameParser_nns(Continuation cont) 238 throws NamingException { 239 a_processJunction_nns(cont); 240 return null; 241 } 242 243 244 245 protected boolean isEmpty(String name) { 246 return name == null || name.equals(""); 247 } 248 249 // ------ implementations of c_ and c_*_nns methods using 250 // ------ the corresponding a_ and a_*_nns methods 251 252 /* Equivalent to methods in Context interface */ 253 254 protected Object c_lookup(Name name, Continuation cont) 255 throws NamingException { 256 Object ret = null; 257 if (resolve_to_penultimate_context(name, cont)) { 258 ret = a_lookup(name.toString(), cont); 259 if (ret != null && ret instanceof LinkRef) { 260 cont.setContinue(ret, name, this); 261 ret = null; 262 } 263 } 264 return ret; 265 } 266 267 protected Object c_lookupLink(Name name, Continuation cont) 268 throws NamingException { 269 if (resolve_to_penultimate_context(name, cont)) { 270 return a_lookupLink(name.toString(), cont); 271 } 272 return null; 273 } 274 275 protected NamingEnumeration<NameClassPair> c_list(Name name, 276 Continuation cont) throws NamingException { 277 if (resolve_to_context(name, cont)) { 278 return a_list(cont); 279 } 280 return null; 281 } 282 283 protected NamingEnumeration<Binding> c_listBindings(Name name, 284 Continuation cont) throws NamingException { 285 if (resolve_to_context(name, cont)) { 286 return a_listBindings(cont); 287 } 288 return null; 289 } 290 291 protected void c_bind(Name name, Object obj, Continuation cont) 292 throws NamingException { 293 if (resolve_to_penultimate_context(name, cont)) 294 a_bind(name.toString(), obj, cont); 295 } 296 297 protected void c_rebind(Name name, Object obj, Continuation cont) 298 throws NamingException { 299 if (resolve_to_penultimate_context(name, cont)) 300 a_rebind(name.toString(), obj, cont); 301 } 302 303 protected void c_unbind(Name name, Continuation cont) 304 throws NamingException { 305 if (resolve_to_penultimate_context(name, cont)) 306 a_unbind(name.toString(), cont); 307 } 308 309 protected void c_destroySubcontext(Name name, Continuation cont) 310 throws NamingException { 311 if (resolve_to_penultimate_context(name, cont)) 312 a_destroySubcontext(name.toString(), cont); 313 } 314 315 protected Context c_createSubcontext(Name name, 316 Continuation cont) throws NamingException { 317 if (resolve_to_penultimate_context(name, cont)) 318 return a_createSubcontext(name.toString(), cont); 319 else 320 return null; 321 } 322 323 protected void c_rename(Name oldname, Name newname, 324 Continuation cont) throws NamingException { 325 if (resolve_to_penultimate_context(oldname, cont)) 326 a_rename(oldname.toString(), newname, cont); 327 } 328 329 protected NameParser c_getNameParser(Name name, 330 Continuation cont) throws NamingException { 331 if (resolve_to_context(name, cont)) 332 return a_getNameParser(cont); 333 return null; 334 } 335 336 /* The following are overridden only for AtomicContexts. 337 * AtomicContext is used by PartialCompositeDirContext and ComponentDirContext 338 * in the inheritance tree to make use of methods in 339 * PartialCompositeContext and ComponentContext. We only want to use the 340 * atomic forms when we're actually an atomic context. 341 */ 342 343 /* From ComponentContext */ 344 345 protected Object c_resolveIntermediate_nns(Name name, Continuation cont) 346 throws NamingException { 347 if (_contextType == _ATOMIC) { 348 Object ret = null; 349 if (resolve_to_penultimate_context_nns(name, cont)) { 350 ret = a_resolveIntermediate_nns(name.toString(), cont); 351 if (ret != null && ret instanceof LinkRef) { 352 cont.setContinue(ret, name, this); 353 ret = null; 354 } 355 } 356 return ret; 357 } else { 358 // use ComponentContext 359 return super.c_resolveIntermediate_nns(name, cont); 360 } 361 } 362 363 /* Equivalent to methods in Context interface for nns */ 364 365 protected Object c_lookup_nns(Name name, Continuation cont) 366 throws NamingException { 367 if (_contextType == _ATOMIC) { 368 Object ret = null; 369 if (resolve_to_penultimate_context_nns(name, cont)) { 370 ret = a_lookup_nns(name.toString(), cont); 371 if (ret != null && ret instanceof LinkRef) { 372 cont.setContinue(ret, name, this); 373 ret = null; 374 } 375 } 376 return ret; 377 } else { 378 return super.c_lookup_nns(name, cont); 379 } 380 } 381 382 protected Object c_lookupLink_nns(Name name, Continuation cont) 383 throws NamingException { 384 if (_contextType == _ATOMIC) { 385 // %%% check logic 386 resolve_to_nns_and_continue(name, cont); 387 return null; 388 } else { 389 // use ComponentContext 390 return super.c_lookupLink_nns(name, cont); 391 } 392 } 393 394 protected NamingEnumeration<NameClassPair> c_list_nns(Name name, 395 Continuation cont) throws NamingException { 396 if (_contextType == _ATOMIC) { 397 resolve_to_nns_and_continue(name, cont); 398 return null; 399 } else { 400 // use ComponentContext 401 return super.c_list_nns(name, cont); 402 } 403 } 404 405 protected NamingEnumeration<Binding> c_listBindings_nns(Name name, 406 Continuation cont) throws NamingException { 407 if (_contextType == _ATOMIC) { 408 resolve_to_nns_and_continue(name, cont); 409 return null; 410 } else { 411 // use ComponentContext 412 return super.c_listBindings_nns(name, cont); 413 } 414 } 415 416 protected void c_bind_nns(Name name, Object obj, Continuation cont) 417 throws NamingException { 418 if (_contextType == _ATOMIC) { 419 if (resolve_to_penultimate_context_nns(name, cont)) 420 a_bind_nns(name.toString(), obj, cont); 421 } else { 422 // use ComponentContext 423 super.c_bind_nns(name, obj, cont); 424 } 425 } 426 427 protected void c_rebind_nns(Name name, Object obj, Continuation cont) 428 throws NamingException { 429 if (_contextType == _ATOMIC) { 430 if (resolve_to_penultimate_context_nns(name, cont)) 431 a_rebind_nns(name.toString(), obj, cont); 432 } else { 433 // use ComponentContext 434 super.c_rebind_nns(name, obj, cont); 435 } 436 } 437 438 protected void c_unbind_nns(Name name, Continuation cont) 439 throws NamingException { 440 if (_contextType == _ATOMIC) { 441 if (resolve_to_penultimate_context_nns(name, cont)) 442 a_unbind_nns(name.toString(), cont); 443 } else { 444 // use ComponentContext 445 super.c_unbind_nns(name, cont); 446 } 447 } 448 449 protected Context c_createSubcontext_nns(Name name, 450 Continuation cont) throws NamingException { 451 if (_contextType == _ATOMIC) { 452 if (resolve_to_penultimate_context_nns(name, cont)) 453 return a_createSubcontext_nns(name.toString(), cont); 454 else 455 return null; 456 } else { 457 // use ComponentContext 458 return super.c_createSubcontext_nns(name, cont); 459 } 460 } 461 462 protected void c_destroySubcontext_nns(Name name, Continuation cont) 463 throws NamingException { 464 if (_contextType == _ATOMIC) { 465 if (resolve_to_penultimate_context_nns(name, cont)) 466 a_destroySubcontext_nns(name.toString(), cont); 467 } else { 468 // use ComponentContext 469 super.c_destroySubcontext_nns(name, cont); 470 } 471 } 472 473 protected void c_rename_nns(Name oldname, Name newname, Continuation cont) 474 throws NamingException { 475 if (_contextType == _ATOMIC) { 476 if (resolve_to_penultimate_context_nns(oldname, cont)) 477 a_rename_nns(oldname.toString(), newname, cont); 478 } else { 479 // use ComponentContext 480 super.c_rename_nns(oldname, newname, cont); 481 } 482 } 483 484 protected NameParser c_getNameParser_nns(Name name, Continuation cont) 485 throws NamingException { 486 if (_contextType == _ATOMIC) { 487 resolve_to_nns_and_continue(name, cont); 488 return null; 489 } else { 490 // use ComponentContext 491 return super.c_getNameParser_nns(name, cont); 492 } 493 } 494 495 // -------------- internal methods used by this class 496 497 /* Handles nns for junctions */ 498 /** 499 * This function is used when implementing a naming system that 500 * supports junctions. For example, when the a_bind_nns(name, newobj) 501 * method is invoked, that means the caller is attempting to bind the 502 * object 'newobj' to the nns of 'name'. For context that supports 503 * junctions, 'name' names a junction and is pointing to the root 504 * of another naming system, which in turn might have an nns. 505 * This means that a_bind_nns() should first resolve 'name' and attempt to 506 * continue the operation in the context named by 'name'. (i.e. bind 507 * to the nns of the context named by 'name'). 508 * If name is already empty, then throw NameNotFoundException because 509 * this context by default does not have any nns. 510 */ 511 protected void a_processJunction_nns(String name, Continuation cont) 512 throws NamingException { 513 if (name.equals("")) { 514 NameNotFoundException e = new NameNotFoundException(); 515 cont.setErrorNNS(this, name); 516 throw cont.fillInException(e); 517 } 518 try { 519 // lookup name to continue operation in nns 520 Object target = a_lookup(name, cont); 521 if (cont.isContinue()) 522 cont.appendRemainingComponent(""); // add nns back 523 else { 524 cont.setContinueNNS(target, name, this); 525 } 526 } catch (NamingException e) { 527 e.appendRemainingComponent(""); // add nns back 528 throw e; 529 } 530 } 531 532 /** 533 * This function is used when implementing a naming system that 534 * supports junctions. For example, when the a_list_nns(newobj) 535 * method is invoked, that means the caller is attempting to list the 536 * the nns context of this context. For a context that supports 537 * junctions, it by default does not have any nns. Consequently, 538 * a NameNotFoundException is thrown. 539 */ 540 protected void a_processJunction_nns(Continuation cont) throws NamingException { 541 542 // Construct a new Reference that contains this context. 543 RefAddr addr = new RefAddr("nns") { 544 public Object getContent() { 545 return AtomicContext.this; 546 } 547 private static final long serialVersionUID = 3449785852664978312L; 548 }; 549 Reference ref = new Reference("java.lang.Object", addr); 550 551 // Set continuation leave it to PartialCompositeContext.getPCContext() 552 // to throw the exception. 553 // Do not use setContinueNNS() because we've are 554 // setting relativeResolvedName to "/". 555 cont.setContinue(ref, _NNS_NAME, this); 556 } 557 558 /* *********** core resolution routines ******************* */ 559 560 /** Resolve to context named by 'name'. 561 * Returns true if at named context (i.e. 'name' is empty name). 562 * Returns false otherwise, and sets Continuation on parts of 'name' 563 * not yet resolved. 564 */ 565 protected boolean resolve_to_context(Name name, Continuation cont) 566 throws NamingException { 567 String target = name.toString(); 568 569 570 StringHeadTail ht = c_parseComponent(target, cont); 571 String tail = ht.getTail(); 572 String head = ht.getHead(); 573 574 if (debug > 0) 575 System.out.println("RESOLVE TO CONTEXT(" + target + ") = {" + 576 head + ", " + tail + "}"); 577 578 if (head == null) { 579 // something is wrong; no name at all 580 InvalidNameException e = new InvalidNameException(); 581 throw cont.fillInException(e); 582 } 583 if (!isEmpty(head)) { 584 // if there is head is a non-empty name 585 // this means more resolution to be done 586 try { 587 Object headCtx = a_lookup(head, cont); 588 // System.out.println("answer " + headCtx); 589 if (headCtx != null) 590 cont.setContinue(headCtx, head, this, (tail == null ? "" : tail)); 591 else if (cont.isContinue()) 592 cont.appendRemainingComponent(tail); 593 } catch (NamingException e) { 594 e.appendRemainingComponent(tail); 595 throw e; 596 } 597 } else { 598 cont.setSuccess(); // clear 599 return true; 600 } 601 return false; 602 } 603 604 /** 605 * Resolves to penultimate context named by 'name'. 606 * Returns true if penultimate context has been reached (i.e. name 607 * only has one atomic component left). 608 * Returns false otherwise, and sets Continuation to parts of name 609 * not yet resolved. 610 */ 611 protected boolean resolve_to_penultimate_context(Name name, Continuation cont) 612 throws NamingException { 613 String target = name.toString(); 614 615 if (debug > 0) 616 System.out.println("RESOLVE TO PENULTIMATE" + target); 617 618 StringHeadTail ht = c_parseComponent(target, cont); 619 String tail = ht.getTail(); 620 String head = ht.getHead(); 621 if (head == null) { 622 // something is wrong; no name at all 623 InvalidNameException e = new InvalidNameException(); 624 throw cont.fillInException(e); 625 } 626 627 if (!isEmpty(tail)) { 628 // more components; hence not at penultimate context yet 629 try { 630 Object headCtx = a_lookup(head, cont); 631 if (headCtx != null) 632 cont.setContinue(headCtx, head, this, tail); 633 else if (cont.isContinue()) 634 cont.appendRemainingComponent(tail); 635 } catch (NamingException e) { 636 e.appendRemainingComponent(tail); 637 throw e; 638 } 639 } else { 640 // already at penultimate context 641 cont.setSuccess(); // clear 642 return true; 643 } 644 return false; 645 } 646 647 /** 648 * This function is similar to resolve_to_penultimate_context() 649 * except it should only be called by the nns() functions. 650 * This function fixes any exception or continuations so that 651 * it will have the proper nns name. 652 */ 653 protected boolean resolve_to_penultimate_context_nns(Name name, 654 Continuation cont) 655 throws NamingException { 656 try { 657 if (debug > 0) 658 System.out.println("RESOLVE TO PENULTIMATE NNS" + name.toString()); 659 boolean answer = resolve_to_penultimate_context(name, cont); 660 661 // resolve_to_penultimate_context() only calls a_lookup(). 662 // Any continuation it sets is lacking the nns, so 663 // we need to add it back 664 if (cont.isContinue()) 665 cont.appendRemainingComponent(""); 666 667 return answer; 668 } catch (NamingException e) { 669 // resolve_to_penultimate_context() only calls a_lookup(). 670 // Any exceptions it throws is lacking the nns, so 671 // we need to add it back. 672 e.appendRemainingComponent(""); 673 throw e; 674 } 675 } 676 677 /** 678 * Resolves to nns associated with 'name' and set Continuation 679 * to the result. 680 */ 681 protected void resolve_to_nns_and_continue(Name name, Continuation cont) 682 throws NamingException { 683 if (debug > 0) 684 System.out.println("RESOLVE TO NNS AND CONTINUE" + name.toString()); 685 686 if (resolve_to_penultimate_context_nns(name, cont)) { 687 Object nns = a_lookup_nns(name.toString(), cont); 688 if (nns != null) 689 cont.setContinue(nns, name, this); 690 } 691 } 692 }