Save This Page
Home » apache-harmony-6.0-src-r917296-snapshot » javax » naming » [javadoc | source]
    1   /* 
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   package javax.naming;
   19   
   20   import java.util.HashMap;
   21   import java.util.Hashtable;
   22   import javax.naming.spi.NamingManager;
   23   
   24   import org.apache.harmony.jndi.internal.UrlParser;
   25   import org.apache.harmony.jndi.internal.EnvironmentReader;
   26   import org.apache.harmony.jndi.internal.nls.Messages;
   27   
   28   /**
   29    * An <code>InitialContext</code> object is required as the starting context
   30    * for any naming operations. Other contexts and subcontexts may be created
   31    * later. Contexts may consist of different implementations according to the
   32    * needs of the application. All naming operations are performed relative to a
   33    * context and names are resolved beginning with the initial context.
   34    * <p>
   35    * When constructing an initial context, environment properties from a range of
   36    * sources may be used to initialize the environment. See the specification of
   37    * the {@link Context} interface for further details of environment properties.
   38    * </p>
   39    * <p>
   40    * The environment at runtime determines the initial context implementation. By
   41    * default, the naming frameworks look for the initial context factory class
   42    * name in the property <code>Context.INITIAL_CONTEXT_FACTORY</code>. When
   43    * URL strings must be resolved, a different policy is used which is described
   44    * below.
   45    * </p>
   46    * <p>
   47    * A <code>NoInitialContextException</code> is thrown when it cannot create an
   48    * initial context. The exception may occur not only during constructor
   49    * invocation, but may occur later. For example, when a subclass of <code>
   50    * InitialContext</code>
   51    * uses the lazy initialization option, <code>
   52    * InitialContext</code> methods
   53    * may be invoked later which require the initialization to be completed at that
   54    * time using the <code>init</code> protected method. In these circumstances,
   55    * <code>NoInitialContextException
   56    * </code> may be thrown some time after the
   57    * constructor was invoked. JNDI applications should be written to be
   58    * independent of when initial context is actually initialized.
   59    * </p>
   60    * <p>
   61    * If environment property <code>Context.INITIAL_CONTEXT_FACTORY</code> has a
   62    * non-null value, then the specified initial context factory may experience a
   63    * problem trying to instantiate an initial context and so throw an exception.
   64    * It is a responsibility of the service provider implementation as to when an
   65    * exception is thrown to report the problem to the JNDI application.
   66    * </p>
   67    * <p>
   68    * URL names comprising a String format described by RFC1738 may be components
   69    * of names passed to naming operations. Typically, the URL is composed of the
   70    * "scheme" - such as one of http, ldap, dns - followed by additional text. If
   71    * the JNDI can identify the URL scheme from the specified name, then it is used
   72    * to construct a classname suffix in the following form:<br>
   73    * 
   74    * <pre>
   75    *            &lt;package_prefix&gt; . &lt;scheme&gt; . &lt;scheme&gt;URLContextFactory
   76    * </pre>
   77    * 
   78    * Several variants of the classname are constructed using each element of the
   79    * <code>Context.URL_PACKAGE_PREFIXES</code> environment property. Note that
   80    * an additional package prefix - "com.sun.jndi.url" - is always considered to
   81    * be at the end of those already present in the value of that environment
   82    * property. Although a service provider may also provide a URL context
   83    * implementation as well as a context implementation, it is not required to do
   84    * so, and so an arbitrary service provider might not provide for creating URL
   85    * contexts.
   86    * </p>
   87    * <p>
   88    * If a URL context is successfully created for a specified URL scheme, the
   89    * factory can create contexts for arbitrary URLs of the same scheme.
   90    * <code>NamingManager.setInitialContextFactoryBuilder</code> may be used to
   91    * specify an alternate policy for locating factories for initial contexts and
   92    * URL contexts.
   93    * </p>
   94    * <p>
   95    * On successful completion of <code>InitialContext</code> initialization, the
   96    * service provider implementation will have returned an appropriate <code>
   97    * Context</code>
   98    * object which can be used for looking up and manipulating names which may or
   99    * may not be URL names. <code>InitialContext</code> methods other than those
  100    * dealing with environments should delegate context operations to that
  101    * <code>Context</code> object.
  102    * </p>
  103    * 
  104    * @see Context
  105    */
  106   public class InitialContext implements Context {
  107   
  108       /**
  109        * Set to the result of the first successful invocation of <code>
  110        * NamingManager.getInitialContext</code>
  111        * by <code>getDefaultInitCtx
  112        * </code>. Initially null.
  113        */
  114       protected Context defaultInitCtx;
  115   
  116       /**
  117        * Set to true when <code>NamingManager.getInitialContext</code> has been
  118        * invoked to obtain an initial context. Initially false.
  119        */
  120       protected boolean gotDefault;
  121   
  122       /**
  123        * Contains all those JNDI environment properties that were found in any of
  124        * the the sources of JNDI environment properties. Initially null.
  125        */
  126       protected Hashtable<Object, Object> myProps;
  127   
  128       /**
  129        * A shortcut method for retrieving the named object by <code>Name</code>.
  130        * It is equivalent to
  131        * 
  132        * <pre>
  133        *    InitialContext icxt = new InitialContext();
  134        *    T obj = icxt.lookup();
  135        * </pre>
  136        * 
  137        * <p>
  138        * Returns a new instance of this context when <code>name</code> is empty.
  139        * The new instance represents the same naming context as this context, but
  140        * may be accessed/modified independently and concurrently.
  141        * </p>
  142        * 
  143        * @param name
  144        *            the name to be looked up
  145        * @return the object bound to <code>name</code>
  146        * @throws NamingException
  147        *             if a naming exception is encountered
  148        * 
  149        * @see #doLookup(String)
  150        * @see #lookup(Name)
  151        * @since 1.6
  152        */
  153       public static <T> T doLookup(Name name) throws NamingException {
  154           return (T) new InitialContext().lookup(name);
  155       }
  156   
  157      /**
  158        * A static method that retrieves the named object by <code>String</code>.
  159        * 
  160        * @param name
  161        *            the name of the object being looked up
  162        * @return the object bound to <code>name</code>
  163        * @throws NamingException
  164        *             if a naming exception is encountered
  165        * 
  166        * @see #doLookup(Name)
  167        * @since 1.6
  168        */
  169       public static <T> T doLookup(String name) throws NamingException {
  170           return (T) new InitialContext().lookup(name);
  171       }
  172   
  173       /**
  174        * Contains loaded properties for each classloader
  175        */
  176       private static Hashtable<ClassLoader, Hashtable<Object, Object>> propsCache = new Hashtable<ClassLoader, Hashtable<Object, Object>>();
  177       
  178       /**
  179        * Contians properties load from java.home/lib/jndi.properties
  180        */
  181       private static Hashtable<Object, Object> libProperties = null;
  182   
  183       /**
  184        * Constructs an <code>InitialContext</code> instance without using any
  185        * environment properties. This constructor is effectively the same as using
  186        * constructor <code>InitialContext((Hashtable)null)</code>.
  187        * 
  188        * @throws NamingException
  189        *             If failed to create an <code>InitialContext</code>.
  190        */
  191       public InitialContext() throws NamingException {
  192           this(null);
  193       }
  194   
  195       /**
  196        * Constructs an <code>InitialContext</code> instance using environment
  197        * properties in the supplied parameter which may be null.
  198        * 
  199        * @param environment
  200        *            the JNDI environment properties used to create the context
  201        * @throws NamingException
  202        *             If failed to create an <code>InitialContext</code>.
  203        */
  204       public InitialContext(Hashtable<?, ?> environment) throws NamingException {
  205           internalInit(environment);
  206       }
  207   
  208       /**
  209        * Constructs an <code>InitialContext</code> instance by indicating
  210        * whether a lazy initialization is desired. Effectively, this is the same
  211        * as using constructor <code>InitialContext()
  212        * </code> if lazy
  213        * initialization is not indicated.
  214        * <p>
  215        * This constructor may be invoked with a parameter value of true and the
  216        * implementation will defer initialization of the instance. This may be
  217        * used in an <code>InitialContext</code> subclass constructor in which
  218        * later action will set up a <code>Hashtable</code> object with
  219        * appropriate environment properties and pass that to the <code>init</code>
  220        * method to complete initialization of the <code>InitialContext</code>
  221        * object.
  222        * </p>
  223        * 
  224        * @param doNotInit
  225        *            Specifies whether to initialize the new instance.
  226        * @throws NamingException
  227        *             If failed to create an <code>InitialContext</code>.
  228        */
  229       protected InitialContext(boolean doNotInit) throws NamingException {
  230           if (!doNotInit) {
  231               internalInit(null);
  232           }
  233       }
  234   
  235       /**
  236        * Does private initialization.
  237        * 
  238        * @param env
  239        *            the JNDI environment properties used to create the context
  240        * @throws NamingException
  241        *             If failed to create an InitialContext.
  242        */
  243       @SuppressWarnings("unchecked")
  244       private void internalInit(Hashtable<?, ?> env) throws NamingException {
  245   
  246           // 1. Read the environment parameter used to create this Context
  247           if (null == env) {
  248               myProps = new Hashtable<Object, Object>();
  249           } else {
  250               myProps = (Hashtable<Object, Object>) env.clone();
  251           }
  252   
  253           // 2. Read Applet parameters
  254           EnvironmentReader.readAppletParameters(myProps.get(Context.APPLET),
  255                   myProps);
  256   
  257           // 3. Read System properties
  258           EnvironmentReader.readSystemProperties(myProps);
  259   
  260           // 4.1 Read application/applet resource files
  261           ClassLoader cl = Thread.currentThread().getContextClassLoader();
  262           if (propsCache.containsKey(cl)) {
  263               EnvironmentReader.mergeEnvironment(propsCache.get(cl), myProps,
  264                       true);
  265           } else {
  266               Hashtable<Object, Object> appProps = new Hashtable<Object, Object>();
  267               EnvironmentReader.readApplicationResourceFiles(appProps);
  268               propsCache.put(cl, appProps);
  269               EnvironmentReader.mergeEnvironment(appProps, myProps, true);
  270           }
  271           
  272           // 4.2 Read "java.home"/lib/jndi.properties
  273           if (libProperties == null) {
  274               Hashtable<Object, Object> props = new Hashtable<Object, Object>();
  275               EnvironmentReader.readLibraryResourceFile(props);
  276               libProperties = props;
  277           }
  278           
  279           EnvironmentReader.mergeEnvironment(libProperties, myProps, true);
  280           
  281           
  282           // 5. No need to read service provider resource files
  283   
  284           // if JNDI standard property "java.naming.factory.initial" has a
  285           // non-null value
  286           if (myProps.containsKey(INITIAL_CONTEXT_FACTORY)) {
  287               // call getDefaultInitCtx() to initialize gotDefault and
  288               // defaultInitCtx
  289               getDefaultInitCtx();
  290           }
  291   
  292       }
  293   
  294       /**
  295        * Uses the specified environment parameter together with other JNDI
  296        * properties to initialize this <code>InitialContext</code> object. The
  297        * <code>myProps</code> field will be filled with found JNDI properties.
  298        * If JNDI standard property "java.naming.factory.initial" has a non-null
  299        * value, then <code>getDefaultInitCtx</code> is invoked to try to
  300        * initialize fields <code>gotDefault</code> and
  301        * <code>defaultInitCtx</code> of the <code>InitialContext</code>
  302        * object.
  303        * 
  304        * @param env
  305        *            the JNDI environment properties supplied to create the context
  306        * @throws NamingException
  307        *             If naming problems are encountered during initialization of
  308        *             these fields.
  309        */
  310       protected void init(Hashtable<?, ?> env) throws NamingException {
  311           this.internalInit(env);
  312       }
  313   
  314       /*
  315        * Initializes the default initial context.
  316        * 
  317        * @throws NamingException If failed to initialize this InitialContext.
  318        */
  319       private void initializeDefaultInitCtx() throws NamingException {
  320           if (!this.gotDefault) {
  321               this.defaultInitCtx = NamingManager.getInitialContext(myProps);
  322               if (null == this.defaultInitCtx) {
  323                   throw new NoInitialContextException(
  324                           "Failed to create an initial context."); //$NON-NLS-1$
  325               }
  326               this.gotDefault = true;
  327           }
  328       }
  329   
  330       /**
  331        * Gets the default underlying <code>Context</code> implementation. If
  332        * <code>gotDefault</code> is true, returns the value of <code>
  333        * defaultInitCtx</code>.
  334        * Otherwise, calls <code>NamingManager.getInitialContext
  335        * </code> to return
  336        * an initial context for the current environment into
  337        * <code>defaultInitCtx</code>, then <code>gotDefault</code> is set
  338        * true. If the resulting context object is null, a
  339        * <code>NoInitialContextException
  340        * </code> is thrown, otherwise the value
  341        * of <code>defaultInitCtx</code> is returned.
  342        * 
  343        * @return the default context
  344        * @throws NoInitialContextException
  345        *             If <code>NamingManager.getInitialContext</code> returns
  346        *             null.
  347        * @throws NamingException
  348        *             If failed to create the default context.
  349        */
  350       protected Context getDefaultInitCtx() throws NamingException {
  351           initializeDefaultInitCtx();
  352           return this.defaultInitCtx;
  353       }
  354   
  355       /**
  356        * Returns a non-null context for the specified name of Name representation.
  357        * <p>
  358        * If an initial context factory builder has been defined, then the
  359        * specified <code>Name</code> parameter is ignored and the result of
  360        * <code>
  361        * getDefaultInitCtx</code> is returned. Otherwise, if the first
  362        * component of the name is not a URL string, then it returns the result of
  363        * invoking <code>getDefaultInitCtx</code>. Otherwise, it attempts to
  364        * return a URL context
  365        * {@link javax.naming.spi.NamingManager#getURLContext(String, Hashtable)},
  366        * but if unsuccessful, returns the result of invoking
  367        * <code>getDefaultInitCtx</code>.
  368        * </p>
  369        * 
  370        * @param name
  371        *            a name used in a naming operation which may not be null
  372        * @return a context which may be a URL context
  373        * @throws NamingException
  374        *             If failed to get the desired context.
  375        */
  376       protected Context getURLOrDefaultInitCtx(Name name) throws NamingException {
  377           // If the name has components
  378           if (0 < name.size()) {
  379               return getURLOrDefaultInitCtx(name.get(0));
  380           }
  381           return getDefaultInitCtx();
  382       }
  383   
  384       /**
  385        * Returns a non-null context for the specified name of string
  386        * representation.
  387        * <p>
  388        * If an initial context factory builder has been defined, then the
  389        * specified name parameter is ignored and the result of <code>
  390        * getDefaultInitCtx</code>
  391        * is returned. Otherwise, if the name is not a URL string, then it returns
  392        * the result of invoking <code>getDefaultInitCtx
  393        * </code>. Otherwise, it
  394        * attempts to return a URL context
  395        * {@link javax.naming.spi.NamingManager#getURLContext(String, Hashtable)},
  396        * but if unsuccessful, returns the result of invoking <code>
  397        * getDefaultInitCtx</code>.
  398        * </p>
  399        * 
  400        * @param name
  401        *            a name used in a naming operation which may not be null
  402        * @return a context which may be a URL context
  403        * @throws NamingException
  404        *             If failed to get the desired context.
  405        */
  406       protected Context getURLOrDefaultInitCtx(String name)
  407               throws NamingException {
  408   
  409           /*
  410            * If an initial context factory builder has been defined, then the
  411            * specified name parameter is ignored and the result of
  412            * getDefaultInitCtx() is returned.
  413            */
  414           if (NamingManager.hasInitialContextFactoryBuilder()) {
  415               return getDefaultInitCtx();
  416           }
  417   
  418           if (null == name) {
  419               // jndi.00=name must not be null
  420               throw new NullPointerException(Messages.getString("jndi.00")); //$NON-NLS-1$
  421           }
  422   
  423           // If the name has components
  424           String scheme = UrlParser.getScheme(name);
  425           Context ctx = null;
  426           if (null != scheme) {
  427               synchronized (contextCache) {
  428                   if (contextCache.containsKey(scheme)) {
  429                       return contextCache.get(scheme);
  430                   }
  431   
  432                   // So the first component is a valid URL
  433                   ctx = NamingManager.getURLContext(scheme, myProps);
  434                   if (null == ctx) {
  435                       ctx = getDefaultInitCtx();
  436                   }
  437                   contextCache.put(scheme, ctx);
  438               }
  439               return ctx;
  440           }
  441           return getDefaultInitCtx();
  442       }
  443   
  444       public Object lookup(Name name) throws NamingException {
  445           return getURLOrDefaultInitCtx(name).lookup(name);
  446       }
  447   
  448       public Object lookup(String name) throws NamingException {
  449           return getURLOrDefaultInitCtx(name).lookup(name);
  450       }
  451   
  452       public void bind(Name name, Object obj) throws NamingException {
  453           getURLOrDefaultInitCtx(name).bind(name, obj);
  454       }
  455   
  456       public void bind(String name, Object obj) throws NamingException {
  457           getURLOrDefaultInitCtx(name).bind(name, obj);
  458       }
  459   
  460       public void rebind(Name name, Object obj) throws NamingException {
  461           getURLOrDefaultInitCtx(name).rebind(name, obj);
  462       }
  463   
  464       public void rebind(String name, Object obj) throws NamingException {
  465           getURLOrDefaultInitCtx(name).rebind(name, obj);
  466       }
  467   
  468       public void unbind(Name name) throws NamingException {
  469           getURLOrDefaultInitCtx(name).unbind(name);
  470       }
  471   
  472       public void unbind(String name) throws NamingException {
  473           getURLOrDefaultInitCtx(name).unbind(name);
  474       }
  475   
  476       public void rename(Name oldName, Name newName) throws NamingException {
  477           getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
  478       }
  479   
  480       public void rename(String oldName, String newName) throws NamingException {
  481           getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
  482       }
  483   
  484       public NamingEnumeration<NameClassPair> list(Name name)
  485               throws NamingException {
  486           return getURLOrDefaultInitCtx(name).list(name);
  487       }
  488   
  489       public NamingEnumeration<NameClassPair> list(String name)
  490               throws NamingException {
  491           return getURLOrDefaultInitCtx(name).list(name);
  492       }
  493   
  494       public NamingEnumeration<Binding> listBindings(Name name)
  495               throws NamingException {
  496           return getURLOrDefaultInitCtx(name).listBindings(name);
  497       }
  498   
  499       public NamingEnumeration<Binding> listBindings(String name)
  500               throws NamingException {
  501           return getURLOrDefaultInitCtx(name).listBindings(name);
  502       }
  503   
  504       public void destroySubcontext(Name name) throws NamingException {
  505           getURLOrDefaultInitCtx(name).destroySubcontext(name);
  506       }
  507   
  508       public void destroySubcontext(String name) throws NamingException {
  509           getURLOrDefaultInitCtx(name).destroySubcontext(name);
  510       }
  511   
  512       public Context createSubcontext(Name name) throws NamingException {
  513           return getURLOrDefaultInitCtx(name).createSubcontext(name);
  514       }
  515   
  516       public Context createSubcontext(String name) throws NamingException {
  517           return getURLOrDefaultInitCtx(name).createSubcontext(name);
  518       }
  519   
  520       public Object lookupLink(Name name) throws NamingException {
  521           return getURLOrDefaultInitCtx(name).lookupLink(name);
  522       }
  523   
  524       public Object lookupLink(String name) throws NamingException {
  525           return getURLOrDefaultInitCtx(name).lookupLink(name);
  526       }
  527   
  528       public NameParser getNameParser(Name name) throws NamingException {
  529           return getURLOrDefaultInitCtx(name).getNameParser(name);
  530       }
  531   
  532       public NameParser getNameParser(String name) throws NamingException {
  533           return getURLOrDefaultInitCtx(name).getNameParser(name);
  534       }
  535   
  536       /**
  537        * Combines two names into a composite name according to the syntax for this
  538        * context. The name <code>prefix</code> is expected to be the name of one
  539        * or more of the immediate parent contexts of this context, so should be an
  540        * empty name for an <code>InitialContext</code>. <code>name</code> is
  541        * a name relative to this context. Neither <code>prefix</code> nor
  542        * <code>name</code> may be null.
  543        * 
  544        * @param name
  545        *            a <code>Name</code>, may not be null
  546        * @param prefix
  547        *            a <code>Name</code> serves as prefix, may not be null
  548        * @return the combined name
  549        * @throws NamingException
  550        *             if an error occurs.
  551        */
  552       public Name composeName(Name name, Name prefix) throws NamingException {
  553           if (null == name) {
  554               throw new NullPointerException();
  555           }
  556           return (Name) name.clone();
  557       }
  558   
  559       /**
  560        * Combines two names into a composite name according to the syntax for this
  561        * context. The name <code>prefix</code> is expected to be the name of one
  562        * or more of the immediate parent contexts of this context, so should be an
  563        * empty string for an <code>InitialContext</code>. <code>name</code>
  564        * is a name relative to this context.
  565        * 
  566        * @param name
  567        *            a <code>Name</code>, may not be null
  568        * @param prefix
  569        *            a <code>Name</code> serves as prefix, may not be null
  570        * @return the combined name
  571        * @throws NamingException
  572        *             if an error occurs.
  573        */
  574       public String composeName(String name, String prefix)
  575               throws NamingException {
  576           return name;
  577       }
  578   
  579       public Object addToEnvironment(String propName, Object propVal)
  580               throws NamingException {
  581           synchronized (contextCache) {
  582               myProps.put(propName, propVal);
  583               contextCache.clear();
  584           }
  585           return getDefaultInitCtx().addToEnvironment(propName, propVal);
  586       }
  587   
  588       public Object removeFromEnvironment(String propName) throws NamingException {
  589           synchronized (contextCache) {
  590               myProps.remove(propName);
  591               contextCache.clear();
  592           }
  593           return getDefaultInitCtx().removeFromEnvironment(propName);
  594       }
  595   
  596       public Hashtable<?, ?> getEnvironment() throws NamingException {
  597           return getDefaultInitCtx().getEnvironment();
  598       }
  599   
  600       public void close() throws NamingException {
  601           if (this.gotDefault) {
  602               getDefaultInitCtx().close();
  603           }
  604       }
  605   
  606       public String getNameInNamespace() throws NamingException {
  607           return getDefaultInitCtx().getNameInNamespace();
  608       }
  609   
  610       private HashMap<String, Context> contextCache = new HashMap<String, Context>();
  611   }

Save This Page
Home » apache-harmony-6.0-src-r917296-snapshot » javax » naming » [javadoc | source]