Coverage Report - org.apache.commons.pipeline.config.PipelineRuleSet
 
Classes in this File Line Coverage Branch Coverage Complexity
PipelineRuleSet
94%
45/48
N/A
0
PipelineRuleSet$1
N/A
N/A
0
PipelineRuleSet$PipelineAddStageRule
100%
12/12
N/A
0
PipelineRuleSet$PipelineDriverFactoriesRule
100%
7/7
N/A
0
PipelineRuleSet$PipelineFactory
36%
4/11
17%
1/6
0
PipelineRuleSet$PipelineFeedObjectRule
20%
1/5
N/A
0
PipelineRuleSet$PipelineFeedValueRule
100%
5/5
N/A
0
PipelineRuleSet$SetNestedPropertyObjectRule
100%
7/7
N/A
0
PipelineRuleSet$StageDriverFactoryFactory
90%
9/10
50%
1/2
0
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  * 
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  * 
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.    
 18  
  */ 
 19  
 
 20  
 package org.apache.commons.pipeline.config;
 21  
 
 22  
 import java.util.HashMap;
 23  
 import java.util.List;
 24  
 import java.util.Map;
 25  
 
 26  
 import org.apache.commons.beanutils.BeanUtils;
 27  
 import org.apache.commons.digester.AbstractObjectCreationFactory;
 28  
 import org.apache.commons.digester.CallMethodRule;
 29  
 import org.apache.commons.digester.Digester;
 30  
 import org.apache.commons.digester.ObjectCreationFactory;
 31  
 import org.apache.commons.digester.Rule;
 32  
 import org.apache.commons.digester.RuleSet;
 33  
 import org.apache.commons.digester.RuleSetBase;
 34  
 import org.apache.commons.pipeline.Pipeline;
 35  
 import org.apache.commons.pipeline.Stage;
 36  
 import org.apache.commons.pipeline.StageDriver;
 37  
 import org.apache.commons.pipeline.StageDriverFactory;
 38  
 import org.xml.sax.Attributes;
 39  
 
 40  
 /**
 41  
  * This is a Digester RuleSet that provides rules for parsing a pipeline
 42  
  * XML file.
 43  
  *
 44  
  * The rules defined by this object are used for parsing the following tags:
 45  
  * <ul>
 46  
  *     <li>
 47  
  *         <B><code>&lt;pipeline&gt;&lt;/pipeline&gt;</code></B><br/>
 48  
  *         The root element of the XML configuration file for a pipeline. This tag
 49  
  *         supports two optional attributes that are for use only when configuring
 50  
  *         branch pipelines, <code>key</code> and <code>configURI</code>. These
 51  
  *         attributes are described more fully below in the <code>&lt;branch&gt;</code>
 52  
  *         documentation.
 53  
  *     </li>
 54  
  *     <li>
 55  
  *         <B><code>&lt;driverFactory className="<em>MyDriverFactory</em>" id="<em>my_id</em>" ... /&gt;</code></B><br/>
 56  
  *         This tag is used to create and configure a {@link StageDriverFactory} that
 57  
  *         will be used to create {@link StageDriver} instances for stages
 58  
  *         in the parent pipeline. Each {@link StageDriverFactory} is identified by a unique
 59  
  *         string identifier that is used by the <code>&lt;stage&gt;</code> tag
 60  
  *         to identify the factory used to create the driver for the stage.
 61  
  *         The class of the factory (which must supply a no-argument constructor)
 62  
  *         is specified by the <code>className</code> attribute, and all other
 63  
  *         additional attributes are used by Digester to configure the associated properties
 64  
  *         (using standard Java bean naming conventions) of the driver instance created.
 65  
  *     </li>
 66  
  *     <li>
 67  
  *         <B><code>&lt;stage className="<em>MyStageClass</em>" driverFactoryId="<i>name</i>" ... &gt;&lt;/stage&gt;</code></B><br/>
 68  
  *         A single stage is created, configured, and added to the parent pipeline using
 69  
  *         this tag. Stages created in this manner are added to the pipeline in the order
 70  
  *         that they occur in the configuration file. The class of the stage (which must
 71  
  *         provide a no-argument constructor) is specified by the <em>className</em> attribute.
 72  
  *         Each stage should be associated with a previously declared driver factory
 73  
  *         by use of the <code>driverFactoryId</code> attribute. All other attributes are
 74  
  *         used by Digester to set bean properties on the newly created Stage object.
 75  
  *     </li>
 76  
  *     <li>
 77  
  *         <B><code>&lt;feed/&gt;</code></B><br/>
 78  
  *         Enqueue an object onto the first stage in the pipeline. Note that this
 79  
  *         must come <em>after</em> the first stage declaration in the configuration file,
 80  
  *         otherwise the queue for the first stage does not exist yet and the fed
 81  
  *         values will be discarded.
 82  
  *         <p/>
 83  
  *         There are two types of usage available, provided by the following subtags:
 84  
  *         <ul>
 85  
  *             <li>
 86  
  *                 <B><code>&lt;value&gt;my_value&lt;/value&gt;</code></B><br/>
 87  
  *                 Feed the string value of the body of this tag to the first stage in the
 88  
  *                 pipeline.
 89  
  *             </li>
 90  
  *             <li>
 91  
  *                 <B><code>&lt;object className="MyClass" ... /&gt;</code></B><br/>
 92  
  *                 This tag uses the standard Digester ObjectCreateRule to create an
 93  
  *                 arbitrary object of the specified class (which must provide a
 94  
  *                 no-argument constructor) to the first stage in the pipeline.
 95  
  *                 All attributes other than <code>className</codee> are used by
 96  
  *                 Digester to set bean properties on the newly created object.
 97  
  *             </li>
 98  
  *         </ul>
 99  
  *     </li>
 100  
  *     <li>
 101  
  *         <B><code>&lt;branch/&gt;</code></B><br/>
 102  
  *         Add a branch to a pipeline. The contents of this tag should
 103  
  *         be one or more <code>&lt;pipeline/&gt;</code> declarations. Branch
 104  
  *         pipelines added in this fashion must be configured with an attribute
 105  
  *         named <code>key</code> that holds the name by which the branch pipeline
 106  
  *         will be referred to.
 107  
  *         <p/>
 108  
  *         Branch pipelines may be configured either inline in the main 
 109  
  *         configuration file or in a separate file referred to by the
 110  
  *         <code>configURI</code> pipeline attribute.
 111  
  *     </li>
 112  
  * </ul>
 113  
  */
 114  0
 public class PipelineRuleSet extends RuleSetBase {
 115  1
     private static Class[] addBranchTypes = { String.class, Pipeline.class };
 116  1
     private static Class[] setEnvTypes = { String.class, Object.class };
 117  
     private List<RuleSet> nestedRuleSets;
 118  
     
 119  
     /**
 120  
      * Creates a new instance of the rule set used by Digester to configure a pipeline.
 121  
      */
 122  0
     public PipelineRuleSet() {
 123  0
     }
 124  
     
 125  
     /**
 126  
      * Creates a new pipeline rule set with the specified collection of additional
 127  
      * rule sets that may be used for recursive creation of branch pipelines.
 128  
      * @param nestedRuleSets A list of other RuleSet instances that are being used in conjunction with the
 129  
      * PipelineRuleSet. In the case that branch pipelines are referred to by URI, these
 130  
      * rule sets will be added to a new Digester instance (along with a PipelineRuleSet
 131  
      * instance) that is used to parse the branch configuration file.
 132  
      */
 133  1
     public PipelineRuleSet(List<RuleSet> nestedRuleSets) {
 134  1
         this.nestedRuleSets = nestedRuleSets;
 135  1
     }
 136  
     
 137  
     /**
 138  
      * Adds the rule instances for pipeline, stage, and enqueue
 139  
      * tasks to the Digester instance supplied.
 140  
      * @param digester The Digester instance to which the rules should be added.
 141  
      */
 142  
     public void addRuleInstances(Digester digester) {
 143  1
         ObjectCreationFactory pipelineFactory = new PipelineFactory();
 144  1
         ObjectCreationFactory driverFactoryFactory = new StageDriverFactoryFactory();
 145  
         
 146  
         //rules to create pipeline
 147  1
         digester.addFactoryCreate("pipeline", pipelineFactory);
 148  1
         digester.addSetProperties("pipeline");
 149  1
         digester.addRule("pipeline", new PipelineDriverFactoriesRule());
 150  
         
 151  
         //these rules are used to add branches to the main pipeline
 152  1
         digester.addFactoryCreate("*/branch/pipeline", pipelineFactory);
 153  1
         digester.addRule("*/branch/pipeline", new CallMethodRule(1, "addBranch", 2, addBranchTypes));
 154  1
         digester.addCallParam("*/branch/pipeline", 0, "key");
 155  1
         digester.addCallParam("*/branch/pipeline", 1, 0);
 156  1
         digester.addRule("*/branch/pipeline", new PipelineDriverFactoriesRule());
 157  
         
 158  
         //rules for adding values to the global pipeline environment
 159  1
         digester.addObjectCreate("*/pipeline/env/object", "java.lang.Object", "className");
 160  1
         digester.addSetProperties("*/pipeline/env/object");
 161  1
         digester.addRule("*/pipeline/env/object", new CallMethodRule(1, "setEnv", 2, setEnvTypes));
 162  1
         digester.addCallParam("*/pipeline/env/object", 0, "key");
 163  1
         digester.addCallParam("*/pipeline/env/object", 1, 0);
 164  
         
 165  1
         digester.addRule("*/pipeline/env/value", new CallMethodRule(0, "setEnv", 2, setEnvTypes));
 166  1
         digester.addCallParam("*/pipeline/env/value", 0, "key");
 167  1
         digester.addCallParam("*/pipeline/env/value", 1);
 168  
         
 169  
         //this rule is intended to be used to add a StageEventListener to the pipeline.
 170  1
         digester.addObjectCreate("*/pipeline/listener", "org.apache.commons.pipeline.StageEventListener", "className");
 171  1
         digester.addSetProperties("*/pipeline/listener");
 172  1
         digester.addSetNext("*/pipeline/listener", "registerListener", "org.apache.commons.pipeline.StageEventListener");
 173  
         
 174  
         //this rule is intended to be used to add a StageDriverFactory to the pipeline.
 175  1
         digester.addFactoryCreate("*/pipeline/driverFactory", driverFactoryFactory);
 176  1
         digester.addSetProperties("*/pipeline/driverFactory");
 177  
         
 178  1
         digester.addObjectCreate("*/driverFactory", "org.apache.commons.pipeline.StageDriverFactory", "className");
 179  1
         digester.addSetProperties("*/driverFactory");
 180  1
         digester.addSetNext("*/driverFactory", "setWrappedSDF", "org.apache.commons.pipeline.StageDriverFactory");
 181  
         
 182  
         //rules for adding lifecycle jobs
 183  1
         digester.addObjectCreate("*/pipeline/lifecycleJob", "org.apache.commons.pipeline.PipelineLifecycleJob", "className");
 184  1
         digester.addSetProperties("*/pipeline/lifecycleJob");
 185  1
         digester.addSetNext("*/pipeline/lifecycleJob", "addLifecycleJob", "org.apache.commons.pipeline.PipelineLifecycleJob");
 186  
         
 187  
         //rules for setting an object property on the next-to-top object on the stack
 188  
         //similar to setNestedPropertiesRule
 189  1
         digester.addObjectCreate("*/property", "java.lang.Object", "className");
 190  1
         digester.addSetProperties("*/property");
 191  1
         digester.addRule("*/property", new SetNestedPropertyObjectRule());
 192  
         
 193  
         //this rule is intended to be used to add a stage to a pipeline
 194  1
         digester.addObjectCreate("*/pipeline/stage", "org.apache.commons.pipeline.BaseStage", "className");
 195  1
         digester.addSetProperties("*/pipeline/stage");
 196  1
         digester.addRule("*/pipeline/stage", new PipelineAddStageRule());
 197  
         
 198  
         //rule for feeding a string value to the source feeder
 199  1
         digester.addRule("*/pipeline/feed/value", new PipelineFeedValueRule());
 200  
         
 201  
         //rules for enqueueing an object
 202  1
         digester.addObjectCreate("*/pipeline/feed/object", "java.lang.Object", "className");
 203  1
         digester.addSetProperties("*/pipeline/feed/object");
 204  1
         digester.addRule("*/pipeline/feed/object", new PipelineFeedObjectRule());
 205  1
     }
 206  
     
 207  
     /**
 208  
      * This factory is used to create a pipeline. If the "configURI" parameter
 209  
      * is specified, the pipeline is created based upon the configuration file
 210  
      * located at that URI.
 211  
      */
 212  2
     private class PipelineFactory extends AbstractObjectCreationFactory {
 213  
         public Object createObject(Attributes attributes) throws java.lang.Exception {
 214  1
             String configURI = attributes.getValue("configURI");
 215  1
             if (configURI == null) {
 216  1
                 return new Pipeline();
 217  
             } else {
 218  0
                 Digester subDigester = new Digester();
 219  0
                 if (nestedRuleSets != null) {
 220  0
                     for (RuleSet ruleset : nestedRuleSets) {
 221  0
                         subDigester.addRuleSet(ruleset);
 222  
                     }
 223  
                     
 224  0
                     Pipeline pipeline = (Pipeline) subDigester.parse(configURI);
 225  0
                     return pipeline;
 226  
                 } else {
 227  0
                     throw new IllegalStateException("Unable to parse branch configuration file: No parsing rules provided to PipelineRuleSet constructor.");
 228  
                 }
 229  
             }
 230  
         }
 231  
     }
 232  
     
 233  
     /**
 234  
      * Configure the storage for the map of driver factories for the pipeline.
 235  
      */
 236  4
     private class PipelineDriverFactoriesRule extends Rule {
 237  
         public void begin(String namespace, String name, Attributes attributes) throws Exception {
 238  1
             digester.push("org.apache.commons.pipeline.config.DriverFactories", new HashMap<String, StageDriverFactory>());
 239  1
             super.begin(namespace, name, attributes);
 240  1
         }
 241  
         
 242  
         public void end(String namespace, String name) throws Exception {
 243  1
             super.end(namespace, name);
 244  1
             digester.pop("org.apache.commons.pipeline.config.DriverFactories");
 245  1
         }
 246  
     }
 247  
     
 248  
     /**
 249  
      * Configure the storage for the map of driver factories for the pipeline.
 250  
      */
 251  2
     private class SetNestedPropertyObjectRule extends Rule {
 252  
         String propName;
 253  
         
 254  
         public void begin(String namespace, String name, Attributes attributes) throws Exception {
 255  4
             propName = attributes.getValue("propName");
 256  4
             super.begin(namespace, name, attributes);
 257  4
         }
 258  
         
 259  
         public void end(String namespace, String name) throws Exception {
 260  4
             super.end(namespace, name);
 261  4
             BeanUtils.setProperty(digester.peek(1), propName, digester.peek());
 262  4
         }
 263  
     }
 264  
     
 265  
     /**
 266  
      * This ObjectCreationFactory creates a stage driver factory and stores
 267  
      * it in the scope of the rule set so that it can be retrieved by the stage
 268  
      * creation rule.
 269  
      */
 270  2
     private class StageDriverFactoryFactory extends AbstractObjectCreationFactory {
 271  
         public Object createObject(Attributes attributes) throws Exception {
 272  1
             Map<String, StageDriverFactory> driverFactories =
 273  
                     (Map<String,StageDriverFactory>) digester.peek("org.apache.commons.pipeline.config.DriverFactories");
 274  
             
 275  1
             String className = attributes.getValue("className");
 276  1
             String id = attributes.getValue("id");
 277  1
             Class clazz = Class.forName(className);
 278  1
             if (!StageDriverFactory.class.isAssignableFrom(clazz)) {
 279  0
                 throw new IllegalArgumentException("Class " + clazz + " does not implement StageDriverFactory.");
 280  
             } else {
 281  1
                 StageDriverFactory factory = (StageDriverFactory) clazz.newInstance();
 282  1
                 driverFactories.put(id, factory);
 283  1
                 return factory;
 284  
             }
 285  
         }
 286  
     }
 287  
     
 288  
     /**
 289  
      * This Rule adds a stage to the pipeline using the factory specified
 290  
      * by the driverFactoryId attribute.
 291  
      */
 292  2
     private class PipelineAddStageRule extends Rule {
 293  
         public void begin(String namespace, String name, Attributes attributes) throws Exception {
 294  6
             digester.push("org.apache.commons.pipeline.config.DriverFactoryIds", attributes.getValue("driverFactoryId"));
 295  6
             super.begin(namespace, name, attributes);
 296  6
         }
 297  
         
 298  
         public void end(String namespace, String name) throws Exception {
 299  6
             super.end(namespace, name);
 300  6
             String factoryId = (String) digester.pop("org.apache.commons.pipeline.config.DriverFactoryIds");
 301  6
             Map<String, StageDriverFactory> driverFactories =
 302  
                     (Map<String,StageDriverFactory>) digester.peek("org.apache.commons.pipeline.config.DriverFactories");
 303  6
             StageDriverFactory factory = driverFactories.get(factoryId);
 304  6
             Stage stage = (Stage) digester.peek();
 305  6
             Pipeline pipeline = (Pipeline) digester.peek(1);
 306  6
             pipeline.addStage(stage, factory);
 307  6
         }
 308  
     }
 309  
     
 310  
     /**
 311  
      * This Rule allows an object to be fed to the pipeline.
 312  
      */
 313  2
     private class PipelineFeedValueRule extends Rule {
 314  
         public void body(String namespace, String name, String text) throws Exception {
 315  2
             Pipeline pipeline = (Pipeline) digester.peek();
 316  2
             pipeline.getSourceFeeder().feed(text);
 317  2
             super.body(namespace, name, text);
 318  2
         }
 319  
     }
 320  
     
 321  
     /**
 322  
      * This Rule allows an object to be fed to the pipeline.
 323  
      */
 324  2
     private class PipelineFeedObjectRule extends Rule {
 325  
         public void end(String namespace, String name) throws Exception {
 326  0
             super.end(namespace, name);
 327  0
             Pipeline pipeline = (Pipeline) digester.peek(1);
 328  0
             pipeline.getSourceFeeder().feed(digester.peek());
 329  0
         }
 330  
     }
 331  
 }