dev@glassfish.java.net

Re: [GFv3] Locating InitialContextFactory without using jndi-properties.jar

From: Kenneth Saks <Kenneth.Saks_at_Sun.COM>
Date: Thu, 28 May 2009 10:34:40 -0400

On May 27, 2009, at 11:57 PM, Sahoo wrote:

> Kenneth Saks wrote:
>>
>> On May 26, 2009, at 4:40 PM, Sahoo wrote:
>>
>>> Jerome, Mahesh, Ken S.,
>>>
>>> Currently, we have jndi-properties.jar in glassfish/lib. The jar
>>> file contains a single resource called jndi.properties file which
>>> has the following entry in it:
>>>
>>> java
>>> .naming
>>> .factory
>>> .initial=com.sun.enterprise.naming.impl.SerialInitContextFactory
>>>
>>> Since this jar file is visible to all J2EE apps, when they do new
>>> InitialContext(), the appropriate initial context factory is used
>>> by naming module (we actually use JDK's naming module). The
>>> problem comes when an application can't see lib/jndi.properties
>>> file. e.g., when an OSGi bundle does new InitialContext().
>>
>>> So, I suggest we do something like this to avoid dependency on lib
>>> dir:
>>>
>>> @Service
>>> public class GlassFishNamingBuilder implements
>>> javax.naming.spi.InitialContextFactoryBuilder,
>>> org,glassfish.api.Startup, org.jvnet.hk2.component.PostConstruct {
>>> public InitialContextFactory
>>> createInitialContextFactory(Hashtable<?,?> environment) {
>>> return new
>>> com.sun.enterprise.naming.impl.SerialInitContextFactory();
>>> }
>>
>> This will work in the case that the caller actually wants our
>> default no-arg InitialContext, but what if they're trying to
>> explicitly instantiate some other InitialContext?
> You are absolutely right. The code was incomplete; I just wanted to
> convey the idea. The actual code will look something like the
> attached file, where environment is used to see if user wants us to
> use a different InitialConbtextFactory class. If yes, we use
> Thread's context class loader to load it and instantiate the same.

Looks good to me.

  --ken

>
> Thanks,
> Sahoo
> /*
> * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
> *
> * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
> *
> * The contents of this file are subject to the terms of either the GNU
> * General Public License Version 2 only ("GPL") or the Common
> Development
> * and Distribution License("CDDL") (collectively, the "License"). You
> * may not use this file except in compliance with the License. You
> can obtain
> * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
> * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the
> specific
> * language governing permissions and limitations under the License.
> *
> * When distributing the software, include this License Header Notice
> in each
> * file and include the License file at glassfish/bootstrap/legal/
> LICENSE.txt.
> * Sun designates this particular file as subject to the "Classpath"
> exception
> * as provided by Sun in the GPL Version 2 section of the License
> file that
> * accompanied this code. If applicable, add the following below the
> License
> * Header, with the fields enclosed by brackets [] replaced by your own
> * identifying information: "Portions Copyrighted [year]
> * [name of copyright owner]"
> *
> * Contributor(s):
> *
> * If you wish your version of this file to be governed by only the
> CDDL or
> * only the GPL Version 2, indicate your decision by adding
> "[Contributor]
> * elects to include this software in this distribution under the
> [CDDL or GPL
> * Version 2] license." If you don't indicate a single choice of
> license, a
> * recipient has the option to distribute your version of this file
> under
> * either the CDDL, the GPL Version 2 or to extend the choice of
> license to
> * its licensees as provided above. However, if you add GPL Version
> 2 code
> * and therefore, elected the GPL Version 2 license, then the option
> applies
> * only if the new code is made subject to such option by the copyright
> * holder.
> */
>
>
> package com.sun.enterprise.naming;
>
> import org.glassfish.api.Startup;
> import org.jvnet.hk2.annotations.Service;
>
> import javax.naming.Context;
> import javax.naming.NamingException;
> import javax.naming.NoInitialContextException;
> import javax.naming.spi.InitialContextFactory;
> import javax.naming.spi.InitialContextFactoryBuilder;
> import javax.naming.spi.NamingManager;
> import java.security.AccessController;
> import java.security.PrivilegedActionException;
> import java.security.PrivilegedExceptionAction;
> import java.util.Hashtable;
>
> /**
> * This is both a {_at_link Startup} service as well as our
> implementation of
> * {_at_link InitialContextFactoryBuilder}. When GlassFish starts up, this
> * startup service configures NamingManager with appropriate builder
> by calling
> * {_at_link
> javax.naming.spi.NamingManager#setInitialContextFactoryBuilder}.
> * Once the builder is setup, when ever new InitialContext() is called,
> * builder can instantiate our {_at_link SerialInitContextFactory},
> which is our
> * implementation of {_at_link InitialContextFactory}.
> *
> * @author Sanjeeb.Sahoo_at_Sun.COM
> */
> @Service
> public class GlassFishNamingBuilder implements
> InitialContextFactoryBuilder, Startup
> {
> public GlassFishNamingBuilder()
> {
> try
> {
> SecurityManager sm = System.getSecurityManager();
> if (sm != null)
> {
> try
> {
> AccessController.doPrivileged(new
> PrivilegedExceptionAction<Void>()
> {
> public Void run() throws NamingException
> {
>
> NamingManager
> .setInitialContextFactoryBuilder(GlassFishNamingBuilder.this);
> return null; //Nothing to return
> }
> });
> }
> catch (PrivilegedActionException e)
> {
> if (e.getCause() instanceof NamingException)
> {
> throw (NamingException) e.getCause();
> }
> throw new RuntimeException(e); // should never
> get here
> }
> }
> else
> {
> NamingManager.setInitialContextFactoryBuilder(this);
> }
> }
> catch (NamingException e)
> {
> throw new RuntimeException(e);
> }
> }
>
> public InitialContextFactory
> createInitialContextFactory(Hashtable<?, ?> environment) throws
> NamingException
> {
> if (environment != null)
> {
> // As per the documentation of
> Context.INITIAL_CONTEXT_FACTORY,
> // it represents a fully qualified class name.
> String className = (String)
> environment.get(Context.INITIAL_CONTEXT_FACTORY);
> if (className != null)
> {
> try
> {
> return (InitialContextFactory)
> (loadClass(className).newInstance());
> }
> catch (Exception e)
> {
> NoInitialContextException ne =
> new NoInitialContextException(
> "Cannot instantiate class: " +
> className);
> ne.setRootCause(e);
> throw ne;
> }
> }
> }
> // default case
> return new SerialInitContextFactory();
> }
>
> public Lifecycle getLifecycle()
> {
> return Lifecycle.START;
> }
>
> private Class loadClass(String className) throws
> ClassNotFoundException
> {
> ClassLoader cl =
> Thread.currentThread().getContextClassLoader();
> return Class.forName(className, true, cl);
> }
> }