CNCtx.java revision 820:9205e980062a
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;
39
40import org.omg.CosNaming.*;
41import org.omg.CosNaming.NamingContextPackage.*;
42import org.omg.CORBA.*;
43
44import com.sun.jndi.toolkit.corba.CorbaUtils;
45
46// Needed for creating default ORB
47import 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
57public 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}
1159