/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2007 Bull S.A.S.
 * Contact: jonas-team@ow2.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 (at your option) 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * --------------------------------------------------------------------------
 * $Id: SingletonComponentContextFactory.java 15428 2008-10-07 11:20:29Z sauthieg $
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.lib.naming;

import java.util.ArrayList;

import javax.naming.Context;
import javax.naming.NamingException;

import org.ow2.jonas.lib.util.Log;
import org.ow2.jonas.naming.JComponentContextFactory;
import org.ow2.jonas.naming.JComponentContextFactoryDelegate;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

/**
 * Allow to create the context (java:) used in JOnAS application server.
 * @author Guillaume Sauthier
 */
public final class SingletonComponentContextFactory implements JComponentContextFactory {

    /**
     * Sub context name.
     */
    private static final String COMP_SUBCONTEXT = "comp";

    /**
     * Logger used for traces.
     */
    private static Logger logger = Log.getLogger(Log.JONAS_NAMING_PREFIX);

    /**
     * The unique factory instance.
     */
    private static JComponentContextFactory unique;

    /**
     * {@link JComponentContextFactoryDelegate} delegates.
     */
    private ArrayList<JComponentContextFactoryDelegate> delegates = new ArrayList<JComponentContextFactoryDelegate>();

    /**
     * The java:comp/ object is shared by all Context. Only subcontext like
     * java:comp/env, etc are different for each components.
     */
    private static Context sharedCompContext = null;

    /**
     * Default private constructor.
     */
    private SingletonComponentContextFactory() {
        super();
        // Create the shared java:comp/ context
        sharedCompContext = new ComponentContext(COMP_SUBCONTEXT);

        // We must instantiate the unique instance
        // in order to retrieve the same object in traditional or OSGi context
        unique = this;
    }

    /**
     * Return the unique instance of a JComponentContextFactory.
     * @return a <code>JComponentContextFactory</code> the unique instance.
     * @throws NamingException if it failed.
     */
    public static synchronized JComponentContextFactory getInstance() throws NamingException {
        if (unique == null) {
            unique = new SingletonComponentContextFactory();
        }
        return unique;
    }

    /**
     * Add the given {@link JComponentContextFactoryDelegate} to this
     * NamingManager instance.
     * @param extension Added delegate
     * @throws NamingException if delegate is not added
     */
    public synchronized void addDelegate(final JComponentContextFactoryDelegate extension) throws NamingException {
        logger.log(BasicLevel.DEBUG, "add :" + extension);
        delegates.add(extension);
        extension.modify(sharedCompContext);
    }

    /**
     * Remove the given {@link JComponentContextFactoryDelegate} from this
     * NamingManager instance.
     * @param extension Removed delegate
     * @throws NamingException if delegate is not removed
     */
    public synchronized void removeDelegate(final JComponentContextFactoryDelegate extension) throws NamingException {
        logger.log(BasicLevel.DEBUG, "extension:" + extension);
        delegates.remove(extension);
        extension.undo(sharedCompContext);
    }

    /**
     * Create {@link Context} for component environments.
     * The returned context is a Java EE Component Context.
     * @param id the Context ID.
     * @return Naming {@link Context} for component environment
     * @throws NamingException If exception encountered when creating namespace.
     */
    public synchronized Context createComponentContext(final String id) throws NamingException {

        logger.log(BasicLevel.DEBUG, id);

        // Create a new environment
        ComponentContext ctx = new ComponentContext(id);

        // Create subContext
        ComponentContext compCtx = (ComponentContext) ctx.createSubcontext(COMP_SUBCONTEXT);

        // Add the wrapped shared java:comp context
        compCtx.addWrapped(sharedCompContext);

        return ctx;
    }

}
