/**
 * OW2 Specifications
 * Copyright (C) 2007 Bull S.A.S.
 * Contact: easybeans@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
 *
 * --------------------------------------------------------------------------
 * $Id: DeploymentFactoryManager.java 4359 2008-12-10 10:24:40Z sauthieg $
 * --------------------------------------------------------------------------
 */

package javax.enterprise.deploy.shared.factories;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.enterprise.deploy.spi.DeploymentManager;
import javax.enterprise.deploy.spi.exceptions.DeploymentManagerCreationException;
import javax.enterprise.deploy.spi.factories.DeploymentFactory;

/**
 * The DeploymentFactoryManager class is a central registry for J2EE DeploymentFactory
 * objects. The DeploymentFactoryManager retains references to DeploymentFactory
 * objects loaded by a tool. A DeploymentFactory object provides a reference to a
 * DeploymentManager.<br/>
 *
 * The DeploymentFactoryManager has been implemented as a singleton. A tool gets a
 * reference to the DeploymentFactoryManager via the getInstance method.<br/>
 *
 * The DeploymentFactoryManager can return two types of DeploymentManagers, a
 * connected DeploymentManager and a disconnected DeploymentManager. The connected
 * DeploymentManager provides access to any product resources that may be required
 * for configurations and deployment. The method to retrieve a connected
 * DeploymentManager is getDeploymentManager. This method provides parameters for
 * user name and password that the product may require for user authentication.
 * A disconnected DeploymentManager does not provide access to a running J2EE product.
 * The method to retrieve a disconnected DeploymentManager is getDisconnectedDeploymentManager.
 * A disconnected DeploymentManager does not need user authentication information.
 * @author Guillaume Sauthier
 */
public final class DeploymentFactoryManager {

    /**
     * Singleton instance.
     */
    private static DeploymentFactoryManager instance = new DeploymentFactoryManager();

    private List deploymentFactories = new ArrayList();

    /**
     * Private Constructor for singleton pattern.
     */
    private DeploymentFactoryManager() {}

    /**
     * Retrieve the Singleton DeploymentFactoryManager
     * @return DeploymentFactoryManager instance
     */
    public static DeploymentFactoryManager getInstance() {
        return instance;
    }

    /**
     * Retrieve the lists of currently registered DeploymentFactories.
     * @return the list of DeploymentFactory objects or an empty array
     *         if there are none.
     */
    public DeploymentFactory[] getDeploymentFactories() {
        return (DeploymentFactory[]) deploymentFactories.toArray(new DeploymentFactory[deploymentFactories.size()]);
    }

    /**
     * Retrieves a DeploymentManager instance to use for deployment. The caller
     * provides a URI and optional username and password, and all registered
     * DeploymentFactories will be checked. The first one to understand the
     * URI provided will attempt to initiate a server connection and return
     * a ready DeploymentManager instance.
     * @param uri The uri to check
     * @param username An optional username (may be null if no authentication
     *        is required for this platform).
     * @param password An optional password (may be null if no authentication
     *        is required for this platform).
     * @return A ready DeploymentManager instance.
     * @throws DeploymentManagerCreationException Occurs when the factory appropriate
     *         to the specified URI was unable to initialize a DeploymentManager
     *         instance (server down, unable to authenticate, etc.).
     */
    public DeploymentManager getDeploymentManager(String uri,
                                                  String username,
                                                  String password)
                             throws DeploymentManagerCreationException {
        if(uri == null) {
            throw new IllegalArgumentException("URI for DeploymentManager should not be null");
        }
        DeploymentManager manager = null;
        for(Iterator i = deploymentFactories.iterator(); i.hasNext();) {
            DeploymentFactory factory = (DeploymentFactory)i.next();
            if(factory.handlesURI(uri)) {
                manager = factory.getDeploymentManager(uri, username, password);
                if(manager != null) {
                    return manager;
                }
            }
        }
        throw new DeploymentManagerCreationException("No registered DeploymentFactory can handles this URI");
    }

    /**
     * Registers a DeploymentFactory so it will be able to handle requests.
     * @param factory DeploymentFactory instance to register
     */
    public void registerDeploymentFactory(DeploymentFactory factory) {
        if(factory == null) {
            throw new IllegalArgumentException("DeploymentFactory to register should not be null");
        }
        if(!deploymentFactories.contains(factory)) {
            deploymentFactories.add(factory);
        }
    }

    /**
     * Return a disconnected DeploymentManager instance.
     * @param uri identifier of the disconnected DeploymentManager to return.
     * @return A DeploymentManager instance.
     * @throws DeploymentManagerCreationException occurs if the DeploymentManager
     *         could not be created.
     */
    public DeploymentManager getDisconnectedDeploymentManager(String uri)
                             throws DeploymentManagerCreationException {
        if(uri == null) {
            throw new IllegalArgumentException("URI for DeploymentManager should not be null");
        }
        DeploymentManager manager = null;
        for(Iterator i = deploymentFactories.iterator(); i.hasNext();) {
            DeploymentFactory factory = (DeploymentFactory)i.next();
            if(factory.handlesURI(uri)) {
                manager = factory.getDisconnectedDeploymentManager(uri);
                if(manager != null) {
                    return manager;
                }
            }
        }
        throw new DeploymentManagerCreationException("No registered DeploymentFactory can handles this URI");

    }
}
