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