/**
 * 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 : Sauthier Guillaume
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
*/

package org.objectweb.jonas.ws.handler;

import java.util.Properties;

import java.lang.reflect.Constructor;

import java.io.InputStream;
import java.io.IOException;
import java.io.File;
import java.io.FileInputStream;

import org.objectweb.jonas.ws.WSServiceException;

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

import org.objectweb.jonas.common.JProp;
import org.objectweb.jonas.common.Log;
import org.objectweb.jonas_lib.I18n;

/**
 * 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 WSDLHandlerFactory {

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

    /**
     * Logger
     */
    private static Logger logger = Log.getLogger(Log.JONAS_WS_PREFIX);

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

    /**
     * Construct a new WSDLHandlerFactory
     */
    private WSDLHandlerFactory() { }

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

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

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

        String classname = props.getProperty(CLASSNAME);

        if (classname == null) {
            // i18n WSDLHandlerFactory.newHandler.noClassname
            String err = i18n.getMessage("WSDLHandlerFactory.newHandler.noClassname",
                                         filename + ".properties");
            logger.log(BasicLevel.ERROR, err);
            throw new WSServiceException(err);
        }

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

        // Instanciation
        WSDLHandler handler = null;
        try {
            Class handlerClazz = Class.forName(classname);
            Constructor handlerConstr = handlerClazz.getConstructor(types);
            handler = (WSDLHandler) handlerConstr.newInstance(pvalues);
        } catch (Exception e) {
            // i18n WSDLHandlerFactory.newHandler.instantiationFailure
            String err = i18n.getMessage("WSDLHandlerFactory.newHandler.instantiationFailure",
                                         filename,
                                         classname);
            logger.log(BasicLevel.ERROR, err);
            throw new WSServiceException(err, e);
        }

        return handler;
    }

    /**
     * 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 WSServiceException if properties cannot be loaded.
     */
    private Properties loadProperties(String filename)
        throws WSServiceException {

        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 WSDLHandlerFactory.loadProperties.ioe
            String err = i18n.getMessage("WSDLHandlerFactory.loadProperties.ioe",
                                         filename);
            logger.log(BasicLevel.ERROR, err);
            throw new WSServiceException(err);
            }
        } else {
            // !!! i18n WSDLHandlerFactory.loadProperties.notFound
            String err = i18n.getMessage("WSDLHandlerFactory.loadProperties.notFound",
                                         filename);
            logger.log(BasicLevel.ERROR, err);
            throw new WSServiceException(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.log(BasicLevel.WARN, "Cannot load " + filename + " from file system.");
            is = null;
        }

        return is;
    }

}
