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.cosnaming;
  27 
  28 import javax.naming.*;
  29 import javax.naming.spi.NamingManager;
  30 import javax.naming.spi.ResolveResult;
  31 
  32 import java.util.Hashtable;
  33 import java.net.MalformedURLException;
  34 import java.net.URL;
  35 import java.io.InputStream;
  36 import java.io.InputStreamReader;
  37 import java.io.BufferedReader;
  38 import java.io.IOException;
  39 
  40 import org.omg.CosNaming.*;
  41 import org.omg.CosNaming.NamingContextPackage.*;
  42 import org.omg.CORBA.*;
  43 
  44 import com.sun.jndi.toolkit.corba.CorbaUtils;
  45 
  46 // Needed for creating default ORB
  47 import java.applet.Applet;
  48 
  49 /**
  50   * Provides a bridge to the CosNaming server provided by
  51   * JavaIDL. This class provides the InitialContext from CosNaming.
  52   *
  53   * @author Raj Krishnamurthy
  54   * @author Rosanna Lee
  55   */
  56 
  57 public class CNCtx implements javax.naming.Context {
  58 
  59     private final static boolean debug = false;
  60 
  61     ORB _orb;                   // used by ExceptionMapper and RMI/IIOP factory
  62     public NamingContext _nc;   // public for accessing underlying NamingContext
  63     private NameComponent[] _name = null;
  64 
  65     Hashtable<String, java.lang.Object> _env; // used by ExceptionMapper
  66     static final CNNameParser parser = new CNNameParser();
  67 
  68     private static final String FED_PROP = "com.sun.jndi.cosnaming.federation";
  69     boolean federation = false;
  70 
  71     // Reference counter for tracking _orb references
  72     OrbReuseTracker orbTracker = null;
  73     int enumCount;
  74     boolean isCloseCalled = false;
  75 
  76     /**
  77       * Create a CNCtx object. Gets the initial naming
  78       * reference for the COS Naming Service from the ORB.
  79       * The ORB can be passed in via the java.naming.corba.orb property
  80       * or be created using properties in the environment properties.
  81       * @param env Environment properties for initializing name service.
  82       * @exception NamingException Cannot initialize ORB or naming context.
  83       */
  84     @SuppressWarnings("unchecked")
  85     CNCtx(Hashtable<?,?> env) throws NamingException {
  86         if (env != null) {
  87             env = (Hashtable<?,?>)env.clone();
  88         }
  89         _env = (Hashtable<String, java.lang.Object>)env;
  90         federation = "true".equals(env != null ? env.get(FED_PROP) : null);
  91         initOrbAndRootContext(env);
  92     }
  93 
  94     private CNCtx() {
  95     }
  96 
  97     /**
  98      * This method is used by the iiop and iiopname URL Context factories.
  99      */
 100     @SuppressWarnings("unchecked")
 101     public static ResolveResult createUsingURL(String url, Hashtable<?,?> env)
 102     throws NamingException {
 103         CNCtx ctx = new CNCtx();
 104         if (env != null) {
 105             env = (Hashtable<?,?>) env.clone();
 106         }
 107         ctx._env = (Hashtable<String, java.lang.Object>)env;
 108         String rest = ctx.initUsingUrl(
 109             env != null ?
 110                 (org.omg.CORBA.ORB) env.get("java.naming.corba.orb")
 111                 : null,
 112             url, env);
 113 
 114         // rest is the INS name
 115         // Return the parsed form to prevent subsequent lookup
 116         // from parsing the string as a composite name
 117         // The caller should be aware that a toString() of the name
 118         // will yield its INS syntax, rather than a composite syntax
 119         return new ResolveResult(ctx, parser.parse(rest));
 120     }
 121 
 122     /**
 123       * Creates a CNCtx object which supports the javax.naming
 124       * apis given a COS Naming Context object.
 125       * @param orb The ORB used by this context
 126       * @param tracker The ORB reuse tracker for tracking references to the
 127       *  orb object
 128       * @param nctx The COS NamingContext object associated with this context
 129       * @param name The name of this context relative to the root
 130       */
 131 
 132     CNCtx(ORB orb, OrbReuseTracker tracker, NamingContext nctx,
 133           Hashtable<String, java.lang.Object> env, NameComponent[]name)
 134         throws NamingException {
 135             if (orb == null || nctx == null)
 136                 throw new ConfigurationException(
 137                     "Must supply ORB or NamingContext");
 138             _orb = orb;
 139             orbTracker = tracker;
 140             if (orbTracker != null) {
 141                 orbTracker.incRefCount();
 142             }
 143             _nc = nctx;
 144             _env = env;
 145             _name = name;
 146             federation = "true".equals(env != null ? env.get(FED_PROP) : null);
 147     }
 148 
 149     NameComponent[] makeFullName(NameComponent[] child) {
 150         if (_name == null || _name.length == 0) {
 151             return child;
 152         }
 153         NameComponent[] answer = new NameComponent[_name.length+child.length];
 154 
 155         // parent
 156         System.arraycopy(_name, 0, answer, 0, _name.length);
 157 
 158         // child
 159         System.arraycopy(child, 0, answer, _name.length, child.length);
 160         return answer;
 161     }
 162 
 163 
 164     public String getNameInNamespace() throws NamingException {
 165         if (_name == null || _name.length == 0) {
 166             return "";
 167         }
 168         return CNNameParser.cosNameToInsString(_name);
 169     }
 170 
 171     /**
 172      * These are the URL schemes that need to be processed.
 173      * IOR and corbaloc URLs can be passed directly to ORB.string_to_object()
 174      */
 175     private static boolean isCorbaUrl(String url) {
 176         return url.startsWith("iiop://")
 177             || url.startsWith("iiopname://")
 178             || url.startsWith("corbaname:")
 179             ;
 180     }
 181 
 182     /**
 183       * Initializes the COS Naming Service.
 184       * This method initializes the three instance fields:
 185       * _nc : The root naming context.
 186       * _orb: The ORB to use for connecting RMI/IIOP stubs and for
 187       *       getting the naming context (_nc) if one was not specified
 188       *       explicitly via PROVIDER_URL.
 189       * _name: The name of the root naming context.
 190       *<p>
 191       * _orb is obtained from java.naming.corba.orb if it has been set.
 192       * Otherwise, _orb is created using the host/port from PROVIDER_URL
 193       * (if it contains an "iiop" or "iiopname" URL), or from initialization
 194       * properties specified in env.
 195       *<p>
 196       * _nc is obtained from the IOR stored in PROVIDER_URL if it has been
 197       * set and does not contain an "iiop" or "iiopname" URL. It can be
 198       * a stringified IOR, "corbaloc" URL, "corbaname" URL,
 199       * or a URL (such as file/http/ftp) to a location
 200       * containing a stringified IOR. If PROVIDER_URL has not been
 201       * set in this way, it is obtained from the result of
 202       *     ORB.resolve_initial_reference("NameService");
 203       *<p>
 204       * _name is obtained from the "iiop", "iiopname", or "corbaname" URL.
 205       * It is the empty name by default.
 206       *
 207       * @param env Environment The possibly null environment.
 208       * @exception NamingException When an error occurs while initializing the
 209       * ORB or the naming context.
 210       */
 211     private void initOrbAndRootContext(Hashtable<?,?> env) throws NamingException {
 212         org.omg.CORBA.ORB inOrb = null;
 213         String ncIor = null;
 214 
 215         if (env != null) {
 216             inOrb = (org.omg.CORBA.ORB) env.get("java.naming.corba.orb");
 217         }
 218 
 219         // Extract PROVIDER_URL from environment
 220         String provUrl = null;
 221         if (env != null) {
 222             provUrl = (String)env.get(javax.naming.Context.PROVIDER_URL);
 223         }
 224 
 225         if (provUrl != null && !isCorbaUrl(provUrl)) {
 226             // Initialize the root naming context by using the IOR supplied
 227             // in the PROVIDER_URL
 228             ncIor = getStringifiedIor(provUrl);
 229 
 230             if (inOrb == null) {
 231 
 232                 // no ORB instance specified; create one using env and defaults
 233                 inOrb = CorbaUtils.getOrb(null, -1, env);
 234                 orbTracker = new OrbReuseTracker(inOrb);
 235             }
 236             setOrbAndRootContext(inOrb, ncIor);
 237         } else if (provUrl != null) {
 238             // Initialize the root naming context by using the URL supplied
 239             // in the PROVIDER_URL
 240             String insName = initUsingUrl(inOrb, provUrl, env);
 241 
 242             // If name supplied in URL, resolve it to a NamingContext
 243             if (insName.length() > 0) {
 244                 _name = CNNameParser.nameToCosName(parser.parse(insName));
 245                 try {
 246                     org.omg.CORBA.Object obj = _nc.resolve(_name);
 247                     _nc = NamingContextHelper.narrow(obj);
 248                     if (_nc == null) {
 249                         throw new ConfigurationException(insName +
 250                             " does not name a NamingContext");
 251                     }
 252                 } catch (org.omg.CORBA.BAD_PARAM e) {
 253                     throw new ConfigurationException(insName +
 254                         " does not name a NamingContext");
 255                 } catch (Exception e) {
 256                     throw ExceptionMapper.mapException(e, this, _name);
 257                 }
 258             }
 259         } else {
 260             // No PROVIDER_URL supplied; initialize using defaults
 261             if (inOrb == null) {
 262 
 263                 // No ORB instance specified; create one using env and defaults
 264                 inOrb = CorbaUtils.getOrb(null, -1, env);
 265                 orbTracker = new OrbReuseTracker(inOrb);
 266                 if (debug) {
 267                     System.err.println("Getting default ORB: " + inOrb + env);
 268                 }
 269             }
 270             setOrbAndRootContext(inOrb, (String)null);
 271         }
 272     }
 273 
 274 
 275     private String initUsingUrl(ORB orb, String url, Hashtable<?,?> env)
 276         throws NamingException {
 277         if (url.startsWith("iiop://") || url.startsWith("iiopname://")) {
 278             return initUsingIiopUrl(orb, url, env);
 279         } else {
 280             return initUsingCorbanameUrl(orb, url, env);
 281         }
 282     }
 283 
 284     /**
 285      * Handles "iiop" and "iiopname" URLs (INS 98-10-11)
 286      */
 287     private String initUsingIiopUrl(ORB defOrb, String url, Hashtable<?,?> env)
 288         throws NamingException {
 289         try {
 290             IiopUrl parsedUrl = new IiopUrl(url);
 291 
 292             NamingException savedException = null;
 293 
 294             for (IiopUrl.Address addr : parsedUrl.getAddresses()) {
 295 
 296                 try {
 297                     if (defOrb != null) {
 298                         try {
 299                             String tmpUrl = "corbaloc:iiop:" + addr.host
 300                                 + ":" + addr.port + "/NameService";
 301                             if (debug) {
 302                                 System.err.println("Using url: " + tmpUrl);
 303                             }
 304                             org.omg.CORBA.Object rootCtx =
 305                                 defOrb.string_to_object(tmpUrl);
 306                             setOrbAndRootContext(defOrb, rootCtx);
 307                             return parsedUrl.getStringName();
 308                         } catch (Exception e) {} // keep going
 309                     }
 310 
 311                     // Get ORB
 312                     if (debug) {
 313                         System.err.println("Getting ORB for " + addr.host
 314                             + " and port " + addr.port);
 315                     }
 316 
 317                     // Get ORB
 318                     ORB orb = CorbaUtils.getOrb(addr.host, addr.port, env);
 319                     orbTracker = new OrbReuseTracker(orb);
 320 
 321                     // Assign to fields
 322                     setOrbAndRootContext(orb, (String)null);
 323                     return parsedUrl.getStringName();
 324 
 325                 } catch (NamingException ne) {
 326                     savedException = ne;
 327                 }
 328             }
 329             if (savedException != null) {
 330                 throw savedException;
 331             } else {
 332                 throw new ConfigurationException("Problem with URL: " + url);
 333             }
 334         } catch (MalformedURLException e) {
 335             throw new ConfigurationException(e.getMessage());
 336         }
 337     }
 338 
 339     /**
 340      * Initializes using "corbaname" URL (INS 99-12-03)
 341      */
 342     private String initUsingCorbanameUrl(ORB orb, String url, Hashtable<?,?> env)
 343         throws NamingException {
 344         try {
 345             CorbanameUrl parsedUrl = new CorbanameUrl(url);
 346 
 347             String corbaloc = parsedUrl.getLocation();
 348             String cosName = parsedUrl.getStringName();
 349 
 350             if (orb == null) {
 351 
 352                 // No ORB instance specified; create one using env and defaults
 353                 orb = CorbaUtils.getOrb(null, -1, env);
 354                 orbTracker = new OrbReuseTracker(orb);
 355             }
 356             setOrbAndRootContext(orb, corbaloc);
 357 
 358             return parsedUrl.getStringName();
 359         } catch (MalformedURLException e) {
 360             throw new ConfigurationException(e.getMessage());
 361         }
 362     }
 363 
 364     private void setOrbAndRootContext(ORB orb, String ncIor)
 365         throws NamingException {
 366         _orb = orb;
 367         try {
 368             org.omg.CORBA.Object ncRef;
 369             if (ncIor != null) {
 370                 if (debug) {
 371                     System.err.println("Passing to string_to_object: " + ncIor);
 372                 }
 373                 ncRef = _orb.string_to_object(ncIor);
 374             } else {
 375                 ncRef = _orb.resolve_initial_references("NameService");
 376             }
 377             if (debug) {
 378                 System.err.println("Naming Context Ref: " + ncRef);
 379             }
 380             _nc = NamingContextHelper.narrow(ncRef);
 381             if (_nc == null) {
 382                 if (ncIor != null) {
 383                     throw new ConfigurationException(
 384                         "Cannot convert IOR to a NamingContext: " + ncIor);
 385                 } else {
 386                     throw new ConfigurationException(
 387 "ORB.resolve_initial_references(\"NameService\") does not return a NamingContext");
 388                 }
 389             }
 390         } catch (org.omg.CORBA.ORBPackage.InvalidName in) {
 391             NamingException ne =
 392                 new ConfigurationException(
 393 "COS Name Service not registered with ORB under the name 'NameService'");
 394             ne.setRootCause(in);
 395             throw ne;
 396         } catch (org.omg.CORBA.COMM_FAILURE e) {
 397             NamingException ne =
 398                 new CommunicationException("Cannot connect to ORB");
 399             ne.setRootCause(e);
 400             throw ne;
 401         } catch (org.omg.CORBA.BAD_PARAM e) {
 402             NamingException ne = new ConfigurationException(
 403                 "Invalid URL or IOR: " + ncIor);
 404             ne.setRootCause(e);
 405             throw ne;
 406         } catch (org.omg.CORBA.INV_OBJREF e) {
 407             NamingException ne = new ConfigurationException(
 408                 "Invalid object reference: " + ncIor);
 409             ne.setRootCause(e);
 410             throw ne;
 411         }
 412     }
 413 
 414     private void setOrbAndRootContext(ORB orb, org.omg.CORBA.Object ncRef)
 415         throws NamingException {
 416         _orb = orb;
 417         try {
 418             _nc = NamingContextHelper.narrow(ncRef);
 419             if (_nc == null) {
 420                 throw new ConfigurationException(
 421                     "Cannot convert object reference to NamingContext: " + ncRef);
 422             }
 423         } catch (org.omg.CORBA.COMM_FAILURE e) {
 424             NamingException ne =
 425                 new CommunicationException("Cannot connect to ORB");
 426             ne.setRootCause(e);
 427             throw ne;
 428         }
 429     }
 430 
 431     private String getStringifiedIor(String url) throws NamingException {
 432         if (url.startsWith("IOR:") || url.startsWith("corbaloc:")) {
 433             return url;
 434         } else {
 435             InputStream in = null;
 436             try {
 437                 URL u = new URL(url);
 438                 in = u.openStream();
 439                 if (in != null) {
 440                     BufferedReader bufin =
 441                         new BufferedReader(new InputStreamReader(in, "8859_1"));
 442                     String str;
 443                     while ((str = bufin.readLine()) != null) {
 444                         if (str.startsWith("IOR:")) {
 445                             return str;
 446                         }
 447                     }
 448                 }
 449             } catch (IOException e) {
 450                 NamingException ne =
 451                     new ConfigurationException("Invalid URL: " + url);
 452                 ne.setRootCause(e);
 453                 throw ne;
 454             } finally {
 455                 try {
 456                     if (in != null) {
 457                         in.close();
 458                     }
 459                 } catch (IOException e) {
 460                     NamingException ne =
 461                         new ConfigurationException("Invalid URL: " + url);
 462                     ne.setRootCause(e);
 463                     throw ne;
 464                 }
 465             }
 466             throw new ConfigurationException(url + " does not contain an IOR");
 467         }
 468     }
 469 
 470 
 471     /**
 472       * Does the job of calling the COS Naming API,
 473       * resolve, and performs the exception mapping. If the resolved
 474       * object is a COS Naming Context (sub-context), then this function
 475       * returns a new JNDI naming context object.
 476       * @param path the NameComponent[] object.
 477       * @exception NotFound No objects under the name.
 478       * @exception CannotProceed Unable to obtain a continuation context
 479       * @exception InvalidName Name not understood.
 480       * @return Resolved object returned by the COS Name Server.
 481       */
 482     java.lang.Object callResolve(NameComponent[] path)
 483         throws NamingException {
 484             try {
 485                 org.omg.CORBA.Object obj = _nc.resolve(path);
 486                 try {
 487                     NamingContext nc =
 488                         NamingContextHelper.narrow(obj);
 489                     if (nc != null) {
 490                         return new CNCtx(_orb, orbTracker, nc, _env,
 491                                         makeFullName(path));
 492                     } else {
 493                         return obj;
 494                     }
 495                 } catch (org.omg.CORBA.SystemException e) {
 496                     return obj;
 497                 }
 498             } catch (Exception e) {
 499                 throw ExceptionMapper.mapException(e, this, path);
 500             }
 501     }
 502 
 503     /**
 504       * Converts the "String" name into a CompositeName
 505       * returns the object resolved by the COS Naming api,
 506       * resolve. Returns the current context if the name is empty.
 507       * Returns either an org.omg.CORBA.Object or javax.naming.Context object.
 508       * @param name string used to resolve the object.
 509       * @exception NamingException See callResolve.
 510       * @return the resolved object
 511       */
 512     public java.lang.Object lookup(String name) throws NamingException {
 513         if (debug) {
 514             System.out.println("Looking up: " + name);
 515         }
 516         return lookup(new CompositeName(name));
 517     }
 518 
 519     /**
 520       * Converts the "Name" name into a NameComponent[] object and
 521       * returns the object resolved by the COS Naming api,
 522       * resolve. Returns the current context if the name is empty.
 523       * Returns either an org.omg.CORBA.Object or javax.naming.Context object.
 524       * @param name JNDI Name used to resolve the object.
 525       * @exception NamingException See callResolve.
 526       * @return the resolved object
 527       */
 528     public java.lang.Object lookup(Name name)
 529         throws NamingException {
 530             if (_nc == null)
 531                 throw new ConfigurationException(
 532                     "Context does not have a corresponding NamingContext");
 533             if (name.size() == 0 )
 534                 return this; // %%% should clone() so that env can be changed
 535             NameComponent[] path = CNNameParser.nameToCosName(name);
 536 
 537             try {
 538                 java.lang.Object answer = callResolve(path);
 539 
 540                 try {
 541                     return NamingManager.getObjectInstance(answer, name, this, _env);
 542                 } catch (NamingException e) {
 543                     throw e;
 544                 } catch (Exception e) {
 545                     NamingException ne = new NamingException(
 546                         "problem generating object using object factory");
 547                     ne.setRootCause(e);
 548                     throw ne;
 549                 }
 550             } catch (CannotProceedException cpe) {
 551                 javax.naming.Context cctx = getContinuationContext(cpe);
 552                 return cctx.lookup(cpe.getRemainingName());
 553             }
 554     }
 555 
 556     /**
 557       * Performs bind or rebind in the context depending on whether the
 558       * flag rebind is set. The only objects allowed to be bound are of
 559       * types org.omg.CORBA.Object, org.omg.CosNaming.NamingContext.
 560       * You can use a state factory to turn other objects (such as
 561       * Remote) into these acceptable forms.
 562       *
 563       * Uses the COS Naming apis bind/rebind or
 564       * bind_context/rebind_context.
 565       * @param pth NameComponent[] object
 566       * @param obj Object to be bound.
 567       * @param rebind perform rebind ? if true performs a rebind.
 568       * @exception NotFound No objects under the name.
 569       * @exception CannotProceed Unable to obtain a continuation context
 570       * @exception AlreadyBound An object is already bound to this name.
 571       */
 572     private void callBindOrRebind(NameComponent[] pth, Name name,
 573         java.lang.Object obj, boolean rebind) throws NamingException {
 574             if (_nc == null)
 575                 throw new ConfigurationException(
 576                     "Context does not have a corresponding NamingContext");
 577             try {
 578                 // Call state factories to convert
 579                 obj = NamingManager.getStateToBind(obj, name, this, _env);
 580 
 581                 if (obj instanceof CNCtx) {
 582                     // Use naming context object reference
 583                     obj = ((CNCtx)obj)._nc;
 584                 }
 585 
 586                 if ( obj instanceof org.omg.CosNaming.NamingContext) {
 587                     NamingContext nobj =
 588                         NamingContextHelper.narrow((org.omg.CORBA.Object)obj);
 589                     if (rebind)
 590                         _nc.rebind_context(pth,nobj);
 591                     else
 592                         _nc.bind_context(pth,nobj);
 593 
 594                 } else if (obj instanceof org.omg.CORBA.Object) {
 595                     if (rebind)
 596                         _nc.rebind(pth,(org.omg.CORBA.Object)obj);
 597                     else
 598                         _nc.bind(pth,(org.omg.CORBA.Object)obj);
 599                 }
 600                 else
 601                     throw new IllegalArgumentException(
 602                 "Only instances of org.omg.CORBA.Object can be bound");
 603             } catch (BAD_PARAM e) {
 604                 // probably narrow() failed?
 605                 NamingException ne = new NotContextException(name.toString());
 606                 ne.setRootCause(e);
 607                 throw ne;
 608             } catch (Exception e) {
 609                 throw ExceptionMapper.mapException(e, this, pth);
 610             }
 611     }
 612 
 613     /**
 614       * Converts the "Name" name into a NameComponent[] object and
 615       * performs the bind operation. Uses callBindOrRebind. Throws an
 616       * invalid name exception if the name is empty. We need a name to
 617       * bind the object even when we work within the current context.
 618       * @param name JNDI Name object
 619       * @param obj Object to be bound.
 620       * @exception NamingException See callBindOrRebind
 621       */
 622     public  void bind(Name name, java.lang.Object obj)
 623         throws NamingException {
 624             if (name.size() == 0 ) {
 625                 throw new InvalidNameException("Name is empty");
 626             }
 627 
 628             if (debug) {
 629                 System.out.println("Bind: " + name);
 630             }
 631             NameComponent[] path = CNNameParser.nameToCosName(name);
 632 
 633             try {
 634                 callBindOrRebind(path, name, obj, false);
 635             } catch (CannotProceedException e) {
 636                 javax.naming.Context cctx = getContinuationContext(e);
 637                 cctx.bind(e.getRemainingName(), obj);
 638             }
 639     }
 640 
 641     static private javax.naming.Context
 642         getContinuationContext(CannotProceedException cpe)
 643         throws NamingException {
 644         try {
 645             return NamingManager.getContinuationContext(cpe);
 646         } catch (CannotProceedException e) {
 647             java.lang.Object resObj = e.getResolvedObj();
 648             if (resObj instanceof Reference) {
 649                 Reference ref = (Reference)resObj;
 650                 RefAddr addr = ref.get("nns");
 651                 if (addr.getContent() instanceof javax.naming.Context) {
 652                     NamingException ne = new NameNotFoundException(
 653                         "No object reference bound for specified name");
 654                     ne.setRootCause(cpe.getRootCause());
 655                     ne.setRemainingName(cpe.getRemainingName());
 656                     throw ne;
 657                 }
 658             }
 659             throw e;
 660         }
 661     }
 662 
 663     /**
 664       * Converts the "String" name into a CompositeName object and
 665       * performs the bind operation. Uses callBindOrRebind. Throws an
 666       * invalid name exception if the name is empty.
 667       * @param name string
 668       * @param obj Object to be bound.
 669       * @exception NamingException See callBindOrRebind
 670       */
 671     public void bind(String name, java.lang.Object obj) throws NamingException {
 672         bind(new CompositeName(name), obj);
 673     }
 674 
 675     /**
 676       * Converts the "Name" name into a NameComponent[] object and
 677       * performs the rebind operation. Uses callBindOrRebind. Throws an
 678       * invalid name exception if the name is empty. We must have a name
 679       * to rebind the object to even if we are working within the current
 680       * context.
 681       * @param name string
 682       * @param obj Object to be bound.
 683       * @exception NamingException See callBindOrRebind
 684       */
 685     public  void rebind(Name name, java.lang.Object obj)
 686         throws NamingException {
 687             if (name.size() == 0 ) {
 688                 throw new InvalidNameException("Name is empty");
 689             }
 690             NameComponent[] path = CNNameParser.nameToCosName(name);
 691             try {
 692                 callBindOrRebind(path, name, obj, true);
 693             } catch (CannotProceedException e) {
 694                 javax.naming.Context cctx = getContinuationContext(e);
 695                 cctx.rebind(e.getRemainingName(), obj);
 696             }
 697     }
 698 
 699     /**
 700       * Converts the "String" name into a CompositeName object and
 701       * performs the rebind operation. Uses callBindOrRebind. Throws an
 702       * invalid name exception if the name is an empty string.
 703       * @param name string
 704       * @param obj Object to be bound.
 705       * @exception NamingException See callBindOrRebind
 706       */
 707     public  void rebind(String name, java.lang.Object obj)
 708         throws NamingException {
 709             rebind(new CompositeName(name), obj);
 710     }
 711 
 712     /**
 713       * Calls the unbind api of COS Naming and uses the exception mapper
 714       * class  to map the exceptions
 715       * @param path NameComponent[] object
 716       * @exception NotFound No objects under the name. If leaf
 717       * is not found, that's OK according to the JNDI spec
 718       * @exception CannotProceed Unable to obtain a continuation context
 719       * @exception InvalidName Name not understood.
 720       */
 721     private void callUnbind(NameComponent[] path) throws NamingException {
 722             if (_nc == null)
 723                 throw new ConfigurationException(
 724                     "Context does not have a corresponding NamingContext");
 725             try {
 726                 _nc.unbind(path);
 727             } catch (NotFound e) {
 728                 // If leaf is the one missing, return success
 729                 // as per JNDI spec
 730 
 731                 if (leafNotFound(e, path[path.length-1])) {
 732                     // do nothing
 733                 } else {
 734                     throw ExceptionMapper.mapException(e, this, path);
 735                 }
 736             } catch (Exception e) {
 737                 throw ExceptionMapper.mapException(e, this, path);
 738             }
 739     }
 740 
 741     private boolean leafNotFound(NotFound e, NameComponent leaf) {
 742 
 743         // This test is not foolproof because some name servers
 744         // always just return one component in rest_of_name
 745         // so you might not be able to tell whether that is
 746         // the leaf (e.g. aa/aa/aa, which one is missing?)
 747 
 748         NameComponent rest;
 749         return e.why.value() == NotFoundReason._missing_node &&
 750             e.rest_of_name.length == 1 &&
 751             (rest=e.rest_of_name[0]).id.equals(leaf.id) &&
 752             (rest.kind == leaf.kind ||
 753              (rest.kind != null && rest.kind.equals(leaf.kind)));
 754     }
 755 
 756     /**
 757       * Converts the "String" name into a CompositeName object and
 758       * performs the unbind operation. Uses callUnbind. If the name is
 759       * empty, throws an invalid name exception. Do we unbind the
 760       * current context (JNDI spec says work with the current context if
 761       * the name is empty) ?
 762       * @param name string
 763       * @exception NamingException See callUnbind
 764       */
 765     public  void unbind(String name) throws NamingException {
 766         unbind(new CompositeName(name));
 767     }
 768 
 769     /**
 770       * Converts the "Name" name into a NameComponent[] object and
 771       * performs the unbind operation. Uses callUnbind. Throws an
 772       * invalid name exception if the name is empty.
 773       * @param name string
 774       * @exception NamingException See callUnbind
 775       */
 776     public  void unbind(Name name)
 777         throws NamingException {
 778             if (name.size() == 0 )
 779                 throw new InvalidNameException("Name is empty");
 780             NameComponent[] path = CNNameParser.nameToCosName(name);
 781             try {
 782                 callUnbind(path);
 783             } catch (CannotProceedException e) {
 784                 javax.naming.Context cctx = getContinuationContext(e);
 785                 cctx.unbind(e.getRemainingName());
 786             }
 787     }
 788 
 789     /**
 790       * Renames an object. Since COS Naming does not support a rename
 791       * api, this method unbinds the object with the "oldName" and
 792       * creates a new binding.
 793       * @param oldName string, existing name for the binding.
 794       * @param newName string, name used to replace.
 795       * @exception NamingException See bind
 796       */
 797     public  void rename(String oldName,String newName)
 798         throws NamingException {
 799             rename(new CompositeName(oldName), new CompositeName(newName));
 800     }
 801 
 802     /**
 803       * Renames an object. Since COS Naming does not support a rename
 804       * api, this method unbinds the object with the "oldName" and
 805       * creates a new binding.
 806       * @param oldName JNDI Name, existing name for the binding.
 807       * @param newName JNDI Name, name used to replace.
 808       * @exception NamingException See bind
 809       */
 810     public  void rename(Name oldName,Name newName)
 811         throws NamingException {
 812             if (_nc == null)
 813                 throw new ConfigurationException(
 814                     "Context does not have a corresponding NamingContext");
 815             if (oldName.size() == 0 || newName.size() == 0)
 816                 throw new InvalidNameException("One or both names empty");
 817             java.lang.Object obj = lookup(oldName);
 818             bind(newName,obj);
 819             unbind(oldName);
 820     }
 821 
 822     /**
 823       * Returns a NameClassEnumeration object which has a list of name
 824       * class pairs. Lists the current context if the name is empty.
 825       * @param name string
 826       * @exception NamingException All exceptions thrown by lookup
 827       * with a non-null argument
 828       * @return a list of name-class objects as a NameClassEnumeration.
 829       */
 830     public  NamingEnumeration<NameClassPair> list(String name) throws NamingException {
 831             return list(new CompositeName(name));
 832     }
 833 
 834     /**
 835       * Returns a NameClassEnumeration object which has a list of name
 836       * class pairs. Lists the current context if the name is empty.
 837       * @param name JNDI Name
 838       * @exception NamingException All exceptions thrown by lookup
 839       * @return a list of name-class objects as a NameClassEnumeration.
 840       */
 841     @SuppressWarnings("unchecked")
 842     public  NamingEnumeration<NameClassPair> list(Name name)
 843         throws NamingException {
 844             return (NamingEnumeration)listBindings(name);
 845     }
 846 
 847     /**
 848       * Returns a BindingEnumeration object which has a list of name
 849       * object pairs. Lists the current context if the name is empty.
 850       * @param name string
 851       * @exception NamingException all exceptions returned by lookup
 852       * @return a list of bindings as a BindingEnumeration.
 853       */
 854     public  NamingEnumeration<javax.naming.Binding> listBindings(String name)
 855         throws NamingException {
 856             return listBindings(new CompositeName(name));
 857     }
 858 
 859     /**
 860       * Returns a BindingEnumeration object which has a list of name
 861       * class pairs. Lists the current context if the name is empty.
 862       * @param name JNDI Name
 863       * @exception NamingException all exceptions returned by lookup.
 864       * @return a list of bindings as a BindingEnumeration.
 865       */
 866     public  NamingEnumeration<javax.naming.Binding> listBindings(Name name)
 867         throws NamingException {
 868             if (_nc == null)
 869                 throw new ConfigurationException(
 870                     "Context does not have a corresponding NamingContext");
 871             if (name.size() > 0) {
 872                 try {
 873                     java.lang.Object obj = lookup(name);
 874                     if (obj instanceof CNCtx) {
 875                         return new CNBindingEnumeration(
 876                                         (CNCtx) obj, true, _env);
 877                     } else {
 878                         throw new NotContextException(name.toString());
 879                     }
 880                 } catch (NamingException ne) {
 881                     throw ne;
 882                 } catch (BAD_PARAM e) {
 883                     NamingException ne =
 884                         new NotContextException(name.toString());
 885                     ne.setRootCause(e);
 886                     throw ne;
 887                 }
 888             }
 889             return new CNBindingEnumeration(this, false, _env);
 890     }
 891 
 892     /**
 893       * Calls the destroy on the COS Naming Server
 894       * @param nc The NamingContext object to use.
 895       * @exception NotEmpty when the context is not empty and cannot be destroyed.
 896       */
 897     private void callDestroy(NamingContext nc)
 898         throws NamingException {
 899             if (_nc == null)
 900                 throw new ConfigurationException(
 901                     "Context does not have a corresponding NamingContext");
 902             try {
 903                 nc.destroy();
 904             } catch (Exception e) {
 905                 throw ExceptionMapper.mapException(e, this, null);
 906             }
 907     }
 908 
 909     /**
 910       * Uses the callDestroy function to destroy the context. If name is
 911       * empty destroys the current context.
 912       * @param name string
 913       * @exception OperationNotSupportedException when list is invoked
 914       * with a non-null argument
 915       */
 916     public  void destroySubcontext(String name) throws NamingException {
 917         destroySubcontext(new CompositeName(name));
 918     }
 919 
 920     /**
 921       * Uses the callDestroy function to destroy the context. Destroys
 922       * the current context if name is empty.
 923       * @param name JNDI Name
 924       * @exception OperationNotSupportedException when list is invoked
 925       * with a non-null argument
 926       */
 927     public  void destroySubcontext(Name name)
 928         throws NamingException {
 929             if (_nc == null)
 930                 throw new ConfigurationException(
 931                     "Context does not have a corresponding NamingContext");
 932             NamingContext the_nc = _nc;
 933             NameComponent[] path = CNNameParser.nameToCosName(name);
 934             if ( name.size() > 0) {
 935                 try {
 936                     javax.naming.Context ctx =
 937                         (javax.naming.Context) callResolve(path);
 938                     CNCtx cnc = (CNCtx)ctx;
 939                     the_nc = cnc._nc;
 940                     cnc.close(); //remove the reference to the context
 941                 } catch (ClassCastException e) {
 942                     throw new NotContextException(name.toString());
 943                 } catch (CannotProceedException e) {
 944                     javax.naming.Context cctx = getContinuationContext(e);
 945                     cctx.destroySubcontext(e.getRemainingName());
 946                     return;
 947                 } catch (NameNotFoundException e) {
 948                     // If leaf is the one missing, return success
 949                     // as per JNDI spec
 950 
 951                     if (e.getRootCause() instanceof NotFound &&
 952                         leafNotFound((NotFound)e.getRootCause(),
 953                             path[path.length-1])) {
 954                         return; // leaf missing OK
 955                     }
 956                     throw e;
 957                 } catch (NamingException e) {
 958                     throw e;
 959                 }
 960             }
 961             callDestroy(the_nc);
 962             callUnbind(path);
 963     }
 964 
 965     /**
 966       * Calls the bind_new_context COS naming api to create a new subcontext.
 967       * @param path NameComponent[] object
 968       * @exception NotFound No objects under the name.
 969       * @exception CannotProceed Unable to obtain a continuation context
 970       * @exception InvalidName Name not understood.
 971       * @exception AlreadyBound An object is already bound to this name.
 972       * @return the new context object.
 973       */
 974     private javax.naming.Context callBindNewContext(NameComponent[] path)
 975         throws NamingException {
 976             if (_nc == null)
 977                 throw new ConfigurationException(
 978                     "Context does not have a corresponding NamingContext");
 979             try {
 980                 NamingContext nctx = _nc.bind_new_context(path);
 981                 return new CNCtx(_orb, orbTracker, nctx, _env,
 982                                         makeFullName(path));
 983             } catch (Exception e) {
 984                 throw ExceptionMapper.mapException(e, this, path);
 985             }
 986     }
 987 
 988     /**
 989       * Uses the callBindNewContext convenience function to create a new
 990       * context. Throws an invalid name exception if the name is empty.
 991       * @param name string
 992       * @exception NamingException See callBindNewContext
 993       * @return the new context object.
 994       */
 995     public  javax.naming.Context createSubcontext(String name)
 996         throws NamingException {
 997             return createSubcontext(new CompositeName(name));
 998     }
 999 
1000     /**
1001       * Uses the callBindNewContext convenience function to create a new
1002       * context. Throws an invalid name exception if the name is empty.
1003       * @param name string
1004       * @exception NamingException See callBindNewContext
1005       * @return the new context object.
1006       */
1007     public  javax.naming.Context createSubcontext(Name name)
1008         throws NamingException {
1009             if (name.size() == 0 )
1010                 throw new InvalidNameException("Name is empty");
1011             NameComponent[] path = CNNameParser.nameToCosName(name);
1012             try {
1013                 return callBindNewContext(path);
1014             } catch (CannotProceedException e) {
1015                 javax.naming.Context cctx = getContinuationContext(e);
1016                 return cctx.createSubcontext(e.getRemainingName());
1017             }
1018     }
1019 
1020     /**
1021       * Is mapped to resolve in the COS Naming api.
1022       * @param name string
1023       * @exception NamingException See lookup.
1024       * @return the resolved object.
1025       */
1026     public  java.lang.Object lookupLink(String name) throws NamingException {
1027             return lookupLink(new CompositeName(name));
1028     }
1029 
1030     /**
1031       * Is mapped to resolve in the COS Naming api.
1032       * @param name string
1033       * @exception NamingException See lookup.
1034       * @return the resolved object.
1035       */
1036     public  java.lang.Object lookupLink(Name name) throws NamingException {
1037             return lookup(name);
1038     }
1039 
1040     /**
1041       * Allow access to the name parser object.
1042       * @param String JNDI name, is ignored since there is only one Name
1043       * Parser object.
1044       * @exception NamingException --
1045       * @return NameParser object
1046       */
1047     public  NameParser getNameParser(String name) throws NamingException {
1048         return parser;
1049     }
1050 
1051     /**
1052       * Allow access to the name parser object.
1053       * @param Name JNDI name, is ignored since there is only one Name
1054       * Parser object.
1055       * @exception NamingException --
1056       * @return NameParser object
1057       */
1058     public  NameParser getNameParser(Name name) throws NamingException {
1059         return parser;
1060     }
1061 
1062     /**
1063       * Returns the current environment.
1064       * @return Environment.
1065       */
1066     @SuppressWarnings("unchecked")
1067     public  Hashtable<String, java.lang.Object> getEnvironment() throws NamingException {
1068         if (_env == null) {
1069             return new Hashtable<>(5, 0.75f);
1070         } else {
1071             return (Hashtable<String, java.lang.Object>)_env.clone();
1072         }
1073     }
1074 
1075     public String composeName(String name, String prefix) throws NamingException {
1076         return composeName(new CompositeName(name),
1077             new CompositeName(prefix)).toString();
1078     }
1079 
1080     public Name composeName(Name name, Name prefix) throws NamingException {
1081         Name result = (Name)prefix.clone();
1082         return result.addAll(name);
1083     }
1084 
1085     /**
1086       * Adds to the environment for the current context.
1087       * Record change but do not reinitialize ORB.
1088       *
1089       * @param propName The property name.
1090       * @param propVal  The ORB.
1091       * @return the previous value of this property if any.
1092       */
1093     @SuppressWarnings("unchecked")
1094     public java.lang.Object addToEnvironment(String propName,
1095         java.lang.Object propValue)
1096         throws NamingException {
1097             if (_env == null) {
1098                 _env = new Hashtable<>(7, 0.75f);
1099             } else {
1100                 // copy-on-write
1101                 _env = (Hashtable<String, java.lang.Object>)_env.clone();
1102             }
1103 
1104             return _env.put(propName, propValue);
1105     }
1106 
1107     // Record change but do not reinitialize ORB
1108     @SuppressWarnings("unchecked")
1109     public java.lang.Object removeFromEnvironment(String propName)
1110         throws NamingException {
1111             if (_env != null  && _env.get(propName) != null) {
1112                 // copy-on-write
1113                 _env = (Hashtable<String, java.lang.Object>)_env.clone();
1114                 return _env.remove(propName);
1115             }
1116             return null;
1117     }
1118 
1119     synchronized public void incEnumCount() {
1120         if (orbTracker == null) {
1121             return;
1122         }
1123         enumCount++;
1124         if (debug) {
1125             System.out.println("incEnumCount, new count:" + enumCount);
1126         }
1127     }
1128 
1129     synchronized public void decEnumCount()
1130             throws NamingException {
1131         if (orbTracker == null) {
1132             return;
1133         }
1134         enumCount--;
1135         if (debug) {
1136             System.out.println("decEnumCount, new count:" + enumCount +
1137                         "    isCloseCalled:" + isCloseCalled);
1138         }
1139         if ((enumCount == 0) && isCloseCalled) {
1140             close();
1141         }
1142     }
1143 
1144     synchronized public void close() throws NamingException {
1145         if (orbTracker == null) {
1146             return;
1147         }
1148         if (enumCount > 0) {
1149             isCloseCalled = true;
1150             return;
1151         }
1152         orbTracker.decRefCount();
1153     }
1154 
1155     protected void finalize() {
1156         try {
1157             close();
1158         } catch (NamingException e) {
1159             // ignore failures
1160         }
1161     }
1162 }