/*
 *
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * Initial developer(s): ____________________________________.
 * Contributor(s): ______________________________________.
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas.naming;

import java.util.Hashtable;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.objectweb.jonas.common.Log;
import org.objectweb.jonas.common.JProp;
import org.objectweb.common.Env;
import org.enhydra.naming.ContainerNaming;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.BasicLevel;


/**
 * Naming Manager for an EJB Server.
 * this singleton class must exist in each jonas server.
 *
 * @author Philippe Durieux
 * Contributor(s): 
 * Philippe Coq Monolog
 */
public class NamingManager implements ContainerNaming {

    static private Logger logger = null;

    private static final String JNDI_PREFIX = "java:comp/env/";

    // Naming Context associated with the thread
    private ThreadLocal threadContext = new ThreadLocal();

    // Contexts
    private InitialContext ictx = null;
    private Context serverContext = null;

    // context to bind CORBA object in CosNaming
    // This variable is used only when using David
    private InitialContext corbaIctx = null;
    
    // Env.
    private Hashtable myEnv = null;

    // ------------------------------------------------------------------
    // Singleton management:
    // - the constructor is private.
    // - use static method getInstance to retrieve/create the instance.
    // ------------------------------------------------------------------
    private static NamingManager unique = null;

    /**
     * Create the naming manager.
     */
    private NamingManager() throws NamingException {
        logger = Log.getLogger(Log.JONAS_NAMING_PREFIX);
	// Create the initial context
	// Don't use jonas.properties anymore for jndi properties
	// jndi.properties will be used instead.
	try {
	    ictx = new InitialContext();
	    myEnv = ictx.getEnvironment();
	} catch (NamingException n) {
	    logger.log(BasicLevel.ERROR, "NamingManager: "+n.getExplanation());
	    Throwable t = n.getRootCause();
	    if (t != null) {
		if (t.getMessage().startsWith("Connection refused to host:")) {
		    logger.log(BasicLevel.ERROR, "NamingManager: rmi registry not started ?");
		} else if (t.getMessage().startsWith("error during remote invocation")) {
		    logger.log(BasicLevel.ERROR, "NamingManager: jrmi registry not started ?");
		} else {
		    logger.log(BasicLevel.ERROR, "NamingManager: "+t.getMessage());
		}
	    }
	    throw n;
	}

	if (Env.isDavid()) {
	    logger.log(BasicLevel.DEBUG, "CosNaming Context Init");
	    Properties props = new Properties();
	    props.put("java.naming.factory.initial", "com.sun.jndi.cosnaming.CNCtxFactory");
	    String host = System.getProperty("david.CosNaming.default_host", "localhost");
	    String port = System.getProperty("david.CosNaming.default_port", "14727");
	    props.put("java.naming.provider.url", "iiop://" + host + ":" + port);  	    
	    try {
		corbaIctx = new InitialContext(props);
		myEnv = corbaIctx.getEnvironment();
	    } catch (NamingException n) {
		logger.log(BasicLevel.ERROR, "NamingManager (Corba): "+n.getExplanation());
		throw n;
	    }
	}


	// Create a CompNamingContext global for this server
	// not really used today, but could be useful later.
	serverContext = new CompNamingContext("server", myEnv);
    }

    public static NamingManager getInstance() throws NamingException {
	if (unique == null) {
	    unique = new NamingManager();
	}
	return unique;
    }


    // ------------------------------------------------------------------
    // ContainerNaming implementation
    // ------------------------------------------------------------------

    /**
     * return the initialContext used in this jonas server
     */
    public InitialContext getInitialContext() {
	return ictx;
    }

    /**
     * return the initialContext used to bind CORBA objects
     */
    public InitialContext getCorbaInitialContext() {
	return corbaIctx;
    }

    /**
     * Create Context for application and component environments.
     * (formally known as createComponentContext)
     */
    public Context createEnvironmentContext(String namespace) throws NamingException {
	CompNamingContext ctx = new CompNamingContext(namespace);
	return (Context) ctx;
    }

    /**
     * return the Context associated with the current thread.
     */
    public Context getComponentContext() {

	Context ctx = (Context) threadContext.get();
	if (ctx == null) {
	    logger.log(BasicLevel.DEBUG, "null context");
	} else {
	    try {
		logger.log(BasicLevel.DEBUG, " "+ctx.getNameInNamespace());
	    } catch (NamingException e) {
		logger.log(BasicLevel.ERROR, " (bad name)");
	    }
	}
	return ctx;
    }

    /**
     * associate this CompNamingContext with the current thread.
     * this method should be called in preinvoke/postinvoke
     * and when we build the bean environment.
     */
    public Context setComponentContext(Context ctx) {
	if (ctx == null) {
	    logger.log(BasicLevel.DEBUG, "reset to null");
	} else {
	    try {
		logger.log(BasicLevel.DEBUG, " "+ctx.getNameInNamespace());
	    } catch (NamingException e) {
		logger.log(BasicLevel.ERROR, " setComponentContext: (bad name)");
	    }
	}
	Context ret = (Context) threadContext.get();
	threadContext.set(ctx);
	return ret;
    }

    /**
     * Return the environment for JNDI
     * This is used only for handles today.
     */
    public Hashtable getEnv() {
	return myEnv;
    }

    public Context createImmutableEnvironmentContext(String namespace) throws NamingException {
	return null;
    }

    // ------------------------------------------------------------------
    // other proprietary methods
    // ------------------------------------------------------------------

    /**
     * gets the server component context
     * This is used only internally in the jonas NamingManager.
     */
    public Context getServerContext() {
	return serverContext;
    }



}
