Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
PipelineRuleSet |
|
| 0.0;0 | ||||
PipelineRuleSet$1 |
|
| 0.0;0 | ||||
PipelineRuleSet$PipelineAddStageRule |
|
| 0.0;0 | ||||
PipelineRuleSet$PipelineDriverFactoriesRule |
|
| 0.0;0 | ||||
PipelineRuleSet$PipelineFactory |
|
| 0.0;0 | ||||
PipelineRuleSet$PipelineFeedObjectRule |
|
| 0.0;0 | ||||
PipelineRuleSet$PipelineFeedValueRule |
|
| 0.0;0 | ||||
PipelineRuleSet$SetNestedPropertyObjectRule |
|
| 0.0;0 | ||||
PipelineRuleSet$StageDriverFactoryFactory |
|
| 0.0;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><pipeline></pipeline></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><branch></code> | |
52 | * documentation. | |
53 | * </li> | |
54 | * <li> | |
55 | * <B><code><driverFactory className="<em>MyDriverFactory</em>" id="<em>my_id</em>" ... /></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><stage></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><stage className="<em>MyStageClass</em>" driverFactoryId="<i>name</i>" ... ></stage></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><feed/></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><value>my_value</value></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><object className="MyClass" ... /></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><branch/></code></B><br/> | |
102 | * Add a branch to a pipeline. The contents of this tag should | |
103 | * be one or more <code><pipeline/></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 | } |