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