//----------------------------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.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.huihoo.workflow.resources.XMLConstants;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;


public class DigesterFactory
{
	/**
	 * 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);
		}

		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);
			}
		}
		
		

		schemaResolver = new SchemaResolver(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)
		{
		}
		catch (SAXNotRecognizedException e)
		{
		}
		catch (SAXNotSupportedException 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(XMLConstants.W3cSchemaResourcePath_20,XMLConstants.W3cSchemaPublicId_20);

		//workflow.xml    
		register(XMLConstants.WorkflowSchemaResourcePath_20, XMLConstants.WorkflowSchemaPublicId_20);
		//register(XMLConstants.WorkflowDtdResourcePath_20, XMLConstants.WorkflowDtdPublicId_20);
		
		//for *.xpdl
		register(XMLConstants.XPDLSchemaResourcePath_20, XMLConstants.XPDLSchemaPublicId_20);
		//register(XMLConstants.XPDLDtdResourcePath_20, XMLConstants.XPDLDtdPublicId_20);
		
		//store.xml
		register(XMLConstants.PluginSchemaResourcePath_20, XMLConstants.PluginSchemaPublicId_20);
		//register(XMLConstants.StoreDtdResourcePath_20, XMLConstants.StoreDtdPublicId_20);
	}

	/**
	 * 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(XMLConstants.WorkflowSchemaResourcePath_20);
		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)
		{
		}
		catch (SAXNotRecognizedException e)
		{
		}
		catch (SAXNotSupportedException e)
		{
		}
	}
}