/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2009 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 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$
 * --------------------------------------------------------------------------
*/

package org.ow2.jonas.ws.publish.internal.manager;

import org.ow2.jonas.lib.bootstrap.JProp;
import org.ow2.jonas.lib.util.I18n;
import org.ow2.jonas.ws.publish.WSDLPublisher;
import org.ow2.jonas.ws.publish.WSDLPublisherException;
import org.ow2.util.log.Log;
import org.ow2.util.log.LogFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.Properties;


/**
 * WSDLHandlerFactory is used to dynamically instantiate a WSDLHandler
 * from a Property file.<br/>
 * Minimum properties in file : <br/>
 * - <code>jonas.service.wsdl.class</code> : Fully qualified classname to be instanciated
 *
 * @author Guillaume Sauthier
 */
public class WSDLPublisherFactory {

    /** Classname property. */
    public static final String CLASSNAME = "jonas.service.wsdl.class";

    /**
     * Logger.
     */
    private static Log logger = LogFactory.getLog(WSDLPublisherFactory.class);

    /**
     * I18n.
     */
    private static I18n i18n = I18n.getInstance(WSDLPublisherFactory.class);

    /**
     * Construct a new WSDLPublisherFactory.
     */
    private WSDLPublisherFactory() { }

    /**
     * @return Returns a new WSDLPublisherFactory instance.
     */
    public static WSDLPublisherFactory newInstance() {
        return new WSDLPublisherFactory();
    }

    /**
     * Create a new WSDLPublisher.
     *
     * @param filename properties filename to be loaded
     *
     * @return a WSDLPublisher init from properties
     *
     * @throws WSDLPublisherException when filename is null or cannot be
     *         loaded (as ClassLoader Resource or as System file)
     */
    public WSDLPublisher newPublisher(String filename)
        throws WSDLPublisherException {

        Properties props = loadProperties(filename + ".properties");

        String classname = props.getProperty(CLASSNAME);

        if (classname == null) {
            // i18n WSDLPublisherFactory.newHandler.noClassname
            String err = i18n.getMessage("WSDLHandlerFactory.newHandler.noClassname",
                                         filename + ".properties");
            logger.error("WSDLHandlerFactory.newHandler.noClassname", filename + ".properties");
            throw new WSDLPublisherException(err);
        }

        Object[] pvalues = new Object[] {props};
        Class[] types = new Class[] {Properties.class};

        // Instanciation
        WSDLPublisher publisher = null;
        try {
            // Can only load WSDLPublishers class accessible from imported package
            Class<? extends WSDLPublisher> handlerClazz = Class.forName(classname).asSubclass(WSDLPublisher.class);
            Constructor<? extends WSDLPublisher> handlerConstr = handlerClazz.getConstructor(types);
            publisher = handlerConstr.newInstance(pvalues);
        } catch (Exception e) {
            // i18n WSDLPublisherFactory.newHandler.instantiationFailure
            String err = i18n.getMessage("WSDLHandlerFactory.newHandler.instantiationFailure",
                                         filename,
                                         classname);
            logger.error("WSDLHandlerFactory.newHandler.instantiationFailure", filename, classname);
            throw new WSDLPublisherException(err, e);
        }

        return publisher;
    }

    /**
     * Load Properties from a properties file.
     * Try to load the file first as a ClassLoader resource and
     * as a File if not found in ClassLoader.
     *
     * @param filename filename to be loaded
     *
     * @return the Properties object loaded from filename
     *
     * @throws WSDLPublisherException if properties cannot be loaded.
     */
    private Properties loadProperties(String filename)
        throws WSDLPublisherException {

        Properties props = new Properties();

        InputStream is = getFromClassLoader(filename);

        if (is == null) {
            // load from ${jonas.base}/conf
            is = getFromFile(JProp.getJonasBase() + File.separator + "conf" + File.separator  + filename);
        }

        if (is != null) {
            try {
                props.load(is);
            } catch (IOException ioe) {
            // !!! i18n WSDLPublisherFactory.loadProperties.ioe
            String err = i18n.getMessage("WSDLHandlerFactory.loadProperties.ioe",
                                         filename);
            logger.error("WSDLHandlerFactory.loadProperties.ioe", filename);
            throw new WSDLPublisherException(err);
            }
        } else {
            // !!! i18n WSDLPublisherFactory.loadProperties.notFound
            String err = i18n.getMessage("WSDLHandlerFactory.loadProperties.notFound",
                                         filename);
            logger.error("WSDLHandlerFactory.loadProperties.notFound", filename);
            throw new WSDLPublisherException(err);
        }

        return props;
    }

    /**
     * Get the file as ClassLoader Resource (can be null if not found).
     *
     * @param filename the filename searched in the ClassLoader
     *
     * @return an InputStream from the ClassLoader
     */
    private InputStream getFromClassLoader(String filename) {

        String clProps = filename;

        // if filename do not start with a "/" prepend it.
        // otherwise, getResourceAsStream will attemps to load it
        // from directory of the current package.
        if (!clProps.startsWith("/")) {
            clProps = "/" + clProps;
        }

        return getClass().getResourceAsStream(clProps);
    }

    /**
     * Get the file as File (can be null if not found).
     *
     * @param filename the filename searched in the System files.
     *
     * @return an InputStream from the File
     */
    private InputStream getFromFile(String filename) {

        InputStream is = null;

        // Create a file
        File file = new File(filename);
        try {
            is = new FileInputStream(file);
        } catch (IOException ioe) {
            logger.warn("Cannot load {0} from file system.", filename);
            is = null;
        }

        return is;
    }

}
