Package org.junitext.runners.parameters.factory

Source Code of org.junitext.runners.parameters.factory.DigesterParameterFactory

/*******************************************************************************
* Copyright (C) 2006-2007 Jochen Hiller and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License - v 1.0
* which accompanies this distribution, and is available at
* http://junitext.sourceforge.net/licenses/junitext-license.html
*
* Contributors:
*     Jochen Hiller - initial API and implementation
*     Jim Hurne - initial XMLParameterizedRunner API and implementation
******************************************************************************/
package org.junitext.runners.parameters.factory;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import org.apache.commons.digester.Digester;
import org.apache.commons.digester.Rule;

/**
* Creates sets of test parameters by parsing input XML using the Jakarta
* commons-digester.
*
* @author Jim Hurne
*/
public class DigesterParameterFactory implements ParameterFactory {

  /**
   * @see org.junitext.runners.parameters.factory.ParameterFactory#createParameters(java.lang.Class,
   *      java.io.File)
   */
  public List<ParameterList> createParameters(Class<?> testClass, File xmlFile)
      throws Exception {

    InputStream xmlInput = new FileInputStream(xmlFile);
    return createParameters(xmlInput);
  }

  /**
   * Creates sets of test parameters by parsing input XML using the Jakarta
   * commons-digester.
   *
   * @param xmlInput
   *            an <code>InputStream</code> containing the XML to parse
   * @return the sets of test parameters
   * @throws Exception
   */
  @SuppressWarnings("unchecked")
  public List<ParameterList> createParameters(InputStream xmlInput)
      throws Exception {
    // Step 1 - Create the digester
    Digester digester = new Digester();
    digester.setValidating(false);

    // Step 2 - Register rules

    registerBaseRules(digester);
    registerValueObjectRules(digester);
    registerCollectionRules(digester);

    // Step 3 - Run the digester against the given input file
    List<ParameterList> generatedParamSets = (List<ParameterList>) digester
        .parse(xmlInput);

    return generatedParamSets;
  }

  private void registerBaseRules(Digester digester) {
    // Add a list for the top level <tests> element
    digester.addObjectCreate("tests", ArrayList.class);

    // Add a list for each <test> element
    digester.addObjectCreate("tests/test", ParameterList.class);

    // Sets the name of the ParameterList based on the id attribute
    digester.addSetProperties("tests/test", "id", "name");

    // Add the <test> list to the top level <tests> list
    digester.addSetNext("tests/test", "add");

    // -- Basic Bean Rules

    // Create an object for any "beans" that are encountered
    // We use the wildcard so that any bean tag at any nesting level is
    // handled
    digester.addObjectCreate("*/bean", "java.lang.Object", "class");

    // Set the properties on the beans based on the
    // <property name="" value="" > tag
    digester.addSetProperty("*/bean/property", "name", "value");

    // Add an object set previously with the CallParamRule to the bean
    // property. This rule is used by the collections as well as properties
    // that expect beans
    Rule setPropertyWithObject = new SetPropertyWithParameterRule("name");
    digester.addRule("*/bean/property", setPropertyWithObject);

    // Add the bean to the parameter set (or to a <list>)
    digester.addSetNext("*/bean", "add");

    // --Rules for bean-based properties

    // Create beans that are associated with properties
    // We have to do this becuase the more-specific pattern overrides
    // the less specific "*/bean" pattern.
    digester.addObjectCreate("*/bean/property/bean", "java.lang.Object",
        "class");

    // Add nested beans as a parameter so that they can be
    // added to the properties of a parent bean
    digester.addCallParam("*/bean/property/bean", 0, true);
  }

  private void registerValueObjectRules(Digester digester) {
    Rule createValueObject = new CreateValueObjectRule("type");
    digester.addRule("tests/test/value", createValueObject);
    digester.addSetNext("tests/test/value", "add", Object.class.getName());

    // Handle nulls for all value elements
    Rule flagNull = new FlagValueObjectIsNullRule();
    digester.addRule("*/value/null", flagNull);

    // Also allow setting bean properties using value elements
    // This is exactly like the Spring "long" property syntax
    // We do it this way so that we have full support of the "type"
    // attribute on the value object.
    digester.addRule("*/bean/property/value", createValueObject);

    // Since our createValueObject rule runs processing at the very end,
    // and since the default CallParamRule processes at the beginning
    // tag, we need to use a custom "CallParamAtEnd" rule.
    Rule callParamAtEnd = new CallParamAtEndRule(0, true);
    digester.addRule("*/bean/property/value", callParamAtEnd);
  }

  private void registerCollectionRules(Digester digester) {
    registerListRules(digester);
    registerSetRules(digester);
    registerMapRules(digester);
  }

  private void registerListRules(Digester digester) {
    // NOTE: Most of the rules for lists are already defined under
    // registerBaseRules. This is because the <tests> element is also
    // a list, so the general rules there also get applied for lists as
    // bean properties.

    // -- Rules for List Processing
    // Create an ArrayList for each <list> element
    digester.addObjectCreate("*/list", ArrayList.class);

    // Add the newly created ArrayLists as a parameter so that it can be
    // added to the properties of the parent bean (or added to another
    // collection)
    digester.addCallParam("*/list", 0, true);

    // -- Rules for basic values nested under lists
    Rule createValueObject = new CreateValueObjectRule("type");
    digester.addRule("*/list/value", createValueObject);
    digester.addSetNext("*/list/value", "add", Object.class.getName());

    // -- Rules for lists nested under lists
    // Create an ArrayList for each nested <list> element
    digester.addObjectCreate("*/list/list", ArrayList.class);
    // If the list is nested within another list, add it to the parent list
    digester.addSetNext("*/list/list", "add");

    // -- Rules for sets nested under lists
    // Create an HashSet for each nested <set> element
    digester.addObjectCreate("*/list/set", HashSet.class);
    // If the set is nested within a list, add it to the parent list
    digester.addSetNext("*/list/set", "add");

    // -- Rules for maps nested under lists
    // Create an HashSet for each nested <map> element
    digester.addObjectCreate("*/list/map", HashMap.class);
    // If the map is nested within a list, add it to the parent list
    digester.addSetNext("*/list/map", "add");
  }

  private void registerSetRules(Digester digester) {
    // NOTE: Most of the rules for sets are already defined under
    // registerBaseRules. This is because the <tests> element is also
    // a list, and list and sets have similar method names,
    // so the general rules there also get applied for sets as
    // bean properties.

    // -- Rules for Set Processing
    // Create a HashSet for each <set> element
    digester.addObjectCreate("*/set", HashSet.class);

    // Add the newly created Set as a parameter so that it can be
    // added to the properties of the parent bean (or added to another
    // collection)
    digester.addCallParam("*/set", 0, true);

    // -- Rules for basic values nested under sets
    Rule createValueObject = new CreateValueObjectRule("type");
    digester.addRule("*/set/value", createValueObject);
    digester.addSetNext("*/set/value", "add", Object.class.getName());

    // -- Rules for sets nested under sets
    // Create a HashSet for each nested <set> element
    digester.addObjectCreate("*/set/set", HashSet.class);
    // If the set is nested within another set, add it to the parent set
    digester.addSetNext("*/set/set", "add");

    // -- Rules for lists nested under sets
    // Create an ArrayList for each nested <list> element
    digester.addObjectCreate("*/set/list", ArrayList.class);
    // If the set is nested within a set, add it to the parent set
    digester.addSetNext("*/set/list", "add");

    // -- Rules for maps nested under sets
    // Create an HashMap for each nested <map> element
    digester.addObjectCreate("*/set/map", HashMap.class);
    // If the map is nested within a set, add it to the parent set
    digester.addSetNext("*/set/map", "add");

  }

  private void registerMapRules(Digester digester) {
    // -- Base Map Rules
    digester.addObjectCreate("*/map", HashMap.class);

    // Add the newly created Map as a parameter so that it can be
    // added to the properties of the parent bean (or added to another
    // collection)
    digester.addCallParam("*/map", 0, true);

    // -- Entry rules
    digester.addCallMethod("*/map/entry", "put", 2);

    // -- Key rules
    // Handle cases where the key is specified as an attribute on the entry
    digester.addCallParam("*/map/entry", 0, "key");

    // Handle casses where the key is specified as a child value element on
    // the entry
    Rule createValueObject = new CreateValueObjectRule("type");
    digester.addRule("*/map/entry/key/value", createValueObject);
    // Since our createValueObject rule runs processing at the very end,
    // and since the default CallParamRule processes at the beginning
    // tag, we need to use a custom "CallParamAtEnd" rule.
    Rule callParamAtEnd = new CallParamAtEndRule(0, true);
    digester.addRule("*/map/entry/key/value", callParamAtEnd);

    // Override some of the bean rules, as we want to do something different
    // here
    digester.addObjectCreate("*/map/entry/key/bean", "java.lang.Object",
        "class");

    // Add the bean to be used as the key for the current map entry
    digester.addCallParam("*/map/entry/key/bean", 0, true);

    // -- Value rules
    // Handle cases where the value is specified as an attribute on the
    // entry
    digester.addCallParam("*/map/entry", 1, "value");
    // Handle cases where the value is a value object and is specified as an
    // element
    digester.addRule("*/map/entry/value", createValueObject);
    // Since our createValueObject rule runs processing at the very end,
    // and since the default CallParamRule processes at the beginning
    // tag, we need to use a custom "CallParamAtEnd" rule.
    callParamAtEnd = new CallParamAtEndRule(1, true);
    digester.addRule("*/map/entry/value", callParamAtEnd);

    // Override some of the bean rules, as we want to do something different
    // here
    digester.addObjectCreate("*/map/entry/bean", "java.lang.Object",
        "class");

    // Add beans as parameters for value objects
    digester.addCallParam("*/map/entry/bean", 1, true);

    // -- Maps nested in Entry rules
    // Create a HashMap for each nested <map> element
    digester.addObjectCreate("*/map/entry/map", HashMap.class);
    // If the map is nested within an entry of a map, treat it as the
    // value of the entry
    digester.addCallParam("*/map/entry/map", 1, true);

    // -- Lists nested in Entry rules
    // Create an ArrayList for each nested <list> element
    digester.addObjectCreate("*/map/entry/list", ArrayList.class);
    // If the list is nested within an entry of a map, treat it as the
    // value of the entry
    digester.addCallParam("*/map/entry/list", 1, true);

    // -- Sets nested in Entry rules
    // Create an ArrayList for each nested <list> element
    digester.addObjectCreate("*/map/entry/set", HashSet.class);
    // If the set is nested within an entry of a map, treat it as the
    // value of the entry
    digester.addCallParam("*/map/entry/set", 1, true);
  }
}
TOP

Related Classes of org.junitext.runners.parameters.factory.DigesterParameterFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.