/**
 * OW2 Specifications
 * Copyright (C) 2008 Bull S.A.S.
 * Contact: easybeans@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: StandardProviderResolver.java 5417 2010-03-24 09:04:14Z benoitf $
 * --------------------------------------------------------------------------
 */

package javax.xml.ws.spi;

import javax.xml.ws.WebServiceException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Enumeration;
import java.util.Properties;

/**
 * Created by IntelliJ IDEA.
 * User: Guillaume
 * Date: 11 déc. 2008
 * Time: 21:20:54
 * To change this template use File | Settings | File Templates.
 */
class StandardProviderResolver {

    public static <T> T find(Class<T> type) {

        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        if (loader == null) {
            loader = ClassLoader.getSystemClassLoader();
        }

        // Find META-INF/services/T resources
        String name = "META-INF/services/" + type.getName();
        Enumeration<URL> resources = null;
        try {
            resources = loader.getResources(name);
        } catch (IOException e) {
            // Ignored, continue
        }
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            InputStream stream = null;
            try {
                stream = resource.openStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));

                String providerClassname = reader.readLine();

                if (providerClassname != null && !"".equals(providerClassname)) {
                    return newInstance(providerClassname, loader, type);
                }
            } catch (Exception e) {
                // Ignored
            } finally {
                if (stream != null) {
                    try {
                        stream.close();
                    } catch (IOException e) {
                        // Ignored
                    }
                }
            }
        }

        // Find ${java.home}/lib/jaxws.properties
        String javaHome = System.getProperty("java.home");
        File jaxwsFile = new File(new File(javaHome, "lib"), "jaxws.properties");
        if (jaxwsFile.isFile()) {
            InputStream stream = null;
            try {
                stream = new FileInputStream(jaxwsFile);
                Properties props = new Properties();
                props.load(stream);

                String providerClassname = props.getProperty(type.getName());
                if (providerClassname != null && !"".equals(providerClassname)) {
                    return newInstance(providerClassname, loader, type);
                }
            } catch (Exception e) {
                // Ignored
            } finally {
                if (stream != null) {
                    try {
                        stream.close();
                    } catch (IOException e) {
                        // Ignored
                    }
                }
            }
        }

        // Find ${T}
        String providerClassname = System.getProperty(type.getName());
        if (providerClassname != null && !"".equals(providerClassname)) {
            return newInstance(providerClassname, loader, type);
        }

        // No default provider instance
        return null;
    }

    private static <T> T newInstance(String className, ClassLoader loader, Class<T> type) {
        try {
            Class<? extends T> spiClass;
            if (loader == null) {
                spiClass = Class.forName(className).asSubclass(type);
            } else {
                spiClass = loader.loadClass(className).asSubclass(type);
            }
            return spiClass.newInstance();
        } catch (ClassNotFoundException cnfe) {
            throw new WebServiceException("Provider " + className + " not found", cnfe);
        } catch (ClassCastException cce) {
            // TODO this is a classloader problem, provide an helpful message to diagnose
            throw new WebServiceException();
        } catch (Exception e) {
            throw new WebServiceException("Provider " + className + " could not be instantiated: ",
                    e);
        }
    }
}
