/*
 * Created on 2004-6-11
 *
 * To change the template for this generated file go to
 * Window - Preferences - Java - Code Generation - Code and Comments
 */
package org.huihoo.willow.startup;

import java.net.URL;

import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.digester.Digester;
import org.apache.commons.digester.RuleSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.huihoo.willow.util.SchemaResolver;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;

/**
 * @author reic
 *
 * To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Generation - Code and Comments
 */
public class DigesterFactory
{
	private static Log log = LogFactory.getLog(DigesterFactory.class);

	/**
	 * The XML entiry resolver used by the Digester.
	 */
	private static SchemaResolver schemaResolver;

	/**
	 * Create a <code>Digester</code> parser with no <code>Rule</code>
	 * associated and XML validation turned off.
	 */
	public static Digester newDigester()
	{
		return newDigester(false, false, null);
	}

	/**
	 * Create a <code>Digester</code> parser with XML validation turned off.
	ī?* @param rule an instance of <code>Rule</codeā?used for parsing the xml.
	 */
	public static Digester newDigester(RuleSet rule)
	{
		return newDigester(false, false, rule);
	}

	/**
	 * Create a <code>Digester</code> parser.
	 * @param xmlValidation turn on/off xml validation
	 * @param xmlNamespaceAware turn on/off namespace validation
	 * @param rule an instance of <code>Rule</codeā?used for parsing the xml.
	 */
	public static Digester newDigester(
		boolean xmlValidation,
		boolean xmlNamespaceAware,
		RuleSet rule)
	{
		Digester digester = new Digester();
		digester.setNamespaceAware(xmlNamespaceAware);
		digester.setValidating(xmlValidation);

		String parserName = digester.getFactory().getClass().getName();
		if (parserName.indexOf("xerces") != -1)
		{
			digester = patchXerces(digester);
		}

		schemaResolver = new SchemaResolver(digester);
		if (xmlValidation)
		{
			// Xerces 2.3 and up has a special way to turn on validation
			// for both DTD and Schema
			if (parserName.indexOf("xerces") != -1)
			{
				turnOnXercesValidation(digester);
			}
			else
			{
				turnOnValidation(digester);
			}
		}
		registerLocalSchema();

		digester.setEntityResolver(schemaResolver);
		if (rule != null)
			digester.addRuleSet(rule);

		return (digester);
	}

	/**
	 * Patch Xerces for backward compatibility.
	 */
	private static Digester patchXerces(Digester digester)
	{
		// This feature is needed for backward compatibility with old DDs
		// which used Java encoding names such as ISO8859_1 etc.
		// with Crimson (bug 4701993). By default, Xerces does not
		// support ISO8859_1.
		try
		{
			digester.setFeature("http://apache.org/xml/features/allow-java-encodings", true);
		}
		catch (ParserConfigurationException e)
		{
			if (log.isTraceEnabled())
			{
				log.trace("contextConfig.registerLocalSchema", e);
			}
		}
		catch (SAXNotRecognizedException e)
		{
			if (log.isTraceEnabled())
			{
				log.trace("contextConfig.registerLocalSchema", e);
			}
		}
		catch (SAXNotSupportedException e)
		{
			if (log.isTraceEnabled())
			{
				log.trace("contextConfig.registerLocalSchema", e);
			}
		}
		return digester;
	}

	/**
	 * Utilities used to force the parser to use local schema, when available,
	 * instead of the <code>schemaLocation</code> XML element.
	 * @param The instance on which properties are set.
	 * @return an instance ready to parse XML schema.
	 */
	protected static void registerLocalSchema()
	{
		// W3C
		register(Constants.W3cSchemaResourcePath_10, Constants.W3cSchemaPublicId_10);

		// workflow.xml    
		register(Constants.WorkflowDtdResourcePath_10, Constants.WorkflowDtdPublicId_10);
		register(Constants.WorkflowSchemaResourcePath_10, Constants.WorkflowSchemaPublicId_10);
	}

	/**
	 * Load the resource and add it to the 
	 */
	protected static void register(String resourceURL, String resourcePublicId)
	{

		URL url = DigesterFactory.class.getResource(resourceURL);
		schemaResolver.register(resourcePublicId, url.toString());

	}

	/**
	 * Turn on DTD and/or validation (based on the parser implementation)
	 */
	protected static void turnOnValidation(Digester digester)
	{
		URL url = DigesterFactory.class.getResource(Constants.WorkflowSchemaResourcePath_10);
		digester.setSchema(url.toString());
	}

	/** 
	 * Turn on schema AND DTD validation on Xerces parser.
	 */
	protected static void turnOnXercesValidation(Digester digester)
	{
		try
		{
			digester.setFeature("http://apache.org/xml/features/validation/dynamic", true);
			digester.setFeature("http://apache.org/xml/features/validation/schema", true);
		}
		catch (ParserConfigurationException e)
		{
			if (log.isTraceEnabled())
			{
				log.trace("contextConfig.registerLocalSchema", e);
			}
		}
		catch (SAXNotRecognizedException e)
		{
			if (log.isTraceEnabled())
			{
				log.trace("contextConfig.registerLocalSchema", e);
			}
		}
		catch (SAXNotSupportedException e)
		{
			if (log.isTraceEnabled())
			{
				log.trace("contextConfig.registerLocalSchema", e);
			}
		}
	}
}