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