//----------------------------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.xmlrules;

import java.lang.reflect.Constructor;

import org.apache.commons.digester.Digester;
import org.apache.commons.digester.Rule;
import org.apache.commons.digester.RuleSetBase;
import org.huihoo.willow.Container;
import org.huihoo.willow.Loader;
import org.xml.sax.Attributes;

public class ContextRuleSet extends RuleSetBase
{

	// ----------------------------------------------------- Instance Variables

	/**
	 * The matching pattern prefix to use for recognizing our elements.
	 */
	protected String prefix = null;

	// ------------------------------------------------------------ Constructor

	/**
	 * Construct an instance of this <code>RuleSet</code> with the default
	 * matching pattern prefix.
	 */
	public ContextRuleSet()
	{

		this("");

	}

	/**
	 * Construct an instance of this <code>RuleSet</code> with the specified
	 * matching pattern prefix.
	 *
	 * @param prefix Prefix for matching pattern rules (including the
	 *  trailing slash character)
	 */
	public ContextRuleSet(String prefix)
	{

		super();
		this.namespaceURI = null;
		this.prefix = prefix;

	}

	// --------------------------------------------------------- Public Methods

	/**
	 * <p>Add the set of Rule instances defined in this RuleSet to the
	 * specified <code>Digester</code> instance, associating them with
	 * our namespace URI (if any).  This method should only be called
	 * by a Digester instance.</p>
	 *
	 * @param digester Digester instance to which the new Rule instances
	 *  should be added.
	 */
	public void addRuleInstances(Digester digester)
	{
		if (isDefaultContext())
		{
			digester.addObjectCreate(prefix + "Context", "org.huihoo.willow.core.StandardDefaultContext", "className");
		}
		else
		{
			digester.addObjectCreate(prefix + "Context", "org.huihoo.willow.core.StandardContext", "className");
		}

		digester.addRule(prefix + "Context", new setAllProperitesExcludingClassNameRule());

		if (isDefaultContext())
		{
			digester.addSetNext(prefix + "Context", "addDefaultContext", "org.huihoo.willow.DefaultContext");
		}
		else
		{
			digester.addRule(prefix + "Context", new CopyParentClassLoaderRule(digester));
			digester.addRule(
				prefix + "Context",
				new LifecycleListenerRule(digester, "org.huihoo.willow.startup.ContextConfig", "configClass"));
			digester.addRule(prefix + "Context", new SetDocBaseRule(digester));

			digester.addSetNext(prefix + "Context", "addChild", "org.huihoo.willow.Context");
		}

		digester.addObjectCreate(prefix + "Context/Listener", null, // MUST be specified in the element
		"className");
		digester.addRule(prefix + "Context/Listener", new setAllProperitesExcludingClassNameRule());

		digester.addSetNext(prefix + "Context/Listener", "addLifecycleListener", "org.huihoo.willow.LifecycleListener");

		digester.addRule(
			prefix + "Context/Loader",
			new CreateLoaderRule(digester, "org.huihoo.willow.loader.WorkflowLoader", "className"));
		digester.addRule(prefix + "Context/Loader", new setAllProperitesExcludingClassNameRule());
		digester.addSetNext(prefix + "Context/Loader", "setLoader", "org.huihoo.willow.Loader");

		digester.addObjectCreate(prefix + "Context/Logger", null, // MUST be specified in the element
		"className");
		digester.addRule(prefix + "Context/Logger", new setAllProperitesExcludingClassNameRule());
		digester.addSetNext(prefix + "Context/Logger", "setLogger", "org.huihoo.willow.Logger");

		digester.addObjectCreate(prefix + "Context/Parameter", "org.huihoo.willow.deploy.ApplicationParameter");
		digester.addSetProperties(prefix + "Context/Parameter");
		digester.addSetNext(
			prefix + "Context/Parameter",
			"addApplicationParameter",
			"org.huihoo.willow.deploy.ApplicationParameter");
	}
	// ------------------------------------------------------ Protected Methods

	/**
		* Are we processing a DefaultContext element?
		*/
	protected boolean isDefaultContext()
	{

		return (prefix.endsWith("/Default"));

	}

}

// ----------------------------------------------------------- Private Classes

/**
 * Rule that creates a new <code>Loader</code> instance, with the parent
 * class loader associated with the top object on the stack (which must be
 * a <code>Container</code>), and pushes it on to the stack.
 */

final class CreateLoaderRule extends Rule
{

	public CreateLoaderRule(Digester digester, String loaderClass, String attributeName)
	{

		super(digester);
		this.loaderClass = loaderClass;
		this.attributeName = attributeName;

	}

	private String attributeName;

	private String loaderClass;

	public void begin(Attributes attributes) throws Exception
	{

		// Look up the required parent class loader
		ClassLoader parentClassLoader = null;
		Object ojb = digester.peek();
		if (ojb instanceof Container)
		{
			parentClassLoader = ((Container) ojb).getParentClassLoader();
		}

		// Instantiate a new Loader implementation object
		String className = loaderClass;
		if (attributeName != null)
		{
			String value = attributes.getValue(attributeName);
			if (value != null)
				className = value;
		}
		Class clazz = Class.forName(className);
		Class types[] = { ClassLoader.class };
		Object args[] = { parentClassLoader };
		Constructor constructor = clazz.getDeclaredConstructor(types);
		Loader loader = (Loader) constructor.newInstance(args);

		// Push the new loader onto the stack
		digester.push(loader);
		if (digester.getDebug() >= 1)
			digester.log("new " + loader.getClass().getName());

	}

	public void end() throws Exception
	{

		Loader loader = (Loader) digester.pop();
		if (digester.getDebug() >= 1)
			digester.log("pop " + loader.getClass().getName());

	}

}