//----------------------------BEGIN LICENSE----------------------------
/* 
 * Willow : the Open Source WorkFlow Project
 * Distributable under GNU LGPL license by gun.org
 *
 * Copyright (C) 2004-2010 huihoo.org 
 * Copyright (C) 2004-2010  ZosaTapo <dertyang@hotmail.com> 
 * 
 * ====================================================================
 * Project Homepage : http://www.huihoo.org/willow
 * Source Forge     : http://sourceforge.net/projects/huihoo
 * Mailing list     : willow@lists.sourceforge.net 
 */
//----------------------------END  LICENSE-----------------------------
package org.huihoo.workflow.xpdl.parser;

/**
 *
 * This code is designed to implement the JAXP 1.1 spec pluggability
 * feature and is designed to run on JDK version 1.1 and later including
 * JVMs that perform early linking like the Microsoft JVM in IE 5.  Note
 * however that it must be compiled on a JDK version 1.2 or later system
 * since it calls Thread#getContextClassLoader().  The code also runs both
 * as part of an unbundled jar file and when bundled as part of the JDK.
 */
class FactoryFinder
{
	/**
	 * Figure out which ClassLoader to use.  For JDK 1.2 and later use the
	 * context ClassLoader if possible.  Note: we defer linking the class
	 * that calls an API only in JDK 1.2 until runtime so that we can catch
	 * LinkageError so that this code will run in older non-Sun JVMs such
	 * as the Microsoft JVM in IE.
	 */
	private static ClassLoader findClassLoader() throws ConfigurationError
	{
		ClassLoader classLoader;
		try
		{
			// Construct the name of the concrete class to instantiate
			Class clazz = Class.forName(FactoryFinder.class.getName() + "$ClassLoaderFinderConcrete");
			ClassLoaderFinder clf = (ClassLoaderFinder) clazz.newInstance();
			classLoader = clf.getContextClassLoader();
		}
		catch (LinkageError le)
		{
			classLoader = FactoryFinder.class.getClassLoader();
		}
		catch (ClassNotFoundException x)
		{
			classLoader = FactoryFinder.class.getClassLoader();
		}
		catch (Exception x)
		{
			throw new ConfigurationError(x.toString(), x);
		}
		return classLoader;
	}

	/**
	 * Create an instance of a class using the specified ClassLoader
	 */
	private static Object newInstance(String className, ClassLoader classLoader)
		throws ConfigurationError
	{
		try
		{
			Class spiClass;
			if (classLoader == null)
			{
				spiClass = Class.forName(className);
			}
			else
			{
				spiClass = classLoader.loadClass(className);
			}
			return spiClass.newInstance();
		}
		catch (ClassNotFoundException x)
		{
			throw new ConfigurationError("Provider " + className + " not found", x);
		}
		catch (Exception x)
		{
			throw new ConfigurationError("Provider " + className + " could not be instantiated: " + x, x);
		}
	}

	static Object find(String factoryClassName, String fallbackClassName) throws ConfigurationError
	{
		ClassLoader classLoader = findClassLoader();
		if (factoryClassName != null && !"".equals(factoryClassName))
		{
			return newInstance(factoryClassName, classLoader);
		}

		if (fallbackClassName == null)
		{
			throw new ConfigurationError("Provider for " + factoryClassName + " cannot be found", null);
		}

		return newInstance(fallbackClassName, classLoader);
	}

	static class ConfigurationError extends Error
	{
		private Exception exception;

		/**
		 * Construct a new instance with the specified detail string and
		 * exception.
		 */
		ConfigurationError(String msg, Exception x)
		{
			super(msg);
			this.exception = x;
		}

		Exception getException()
		{
			return exception;
		}
	}

	private static abstract class ClassLoaderFinder
	{
		abstract ClassLoader getContextClassLoader();
	}

	static class ClassLoaderFinderConcrete extends ClassLoaderFinder
	{
		ClassLoader getContextClassLoader()
		{
			return Thread.currentThread().getContextClassLoader();
		}
	}
}
