View Javadoc

1   /**
2    * Copyright 2005-2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.rule.xmlrouting;
17  
18  import org.junit.Test;
19  import org.kuali.rice.core.api.uif.RemotableAttributeError;
20  import org.kuali.rice.kew.api.WorkflowDocument;
21  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
22  import org.kuali.rice.kew.api.document.attribute.WorkflowAttributeDefinition;
23  import org.kuali.rice.kew.api.rule.RuleExtension;
24  import org.kuali.rice.kew.docsearch.xml.StandardGenericXMLSearchableAttribute;
25  import org.kuali.rice.kew.api.exception.WorkflowException;
26  import org.kuali.rice.kew.engine.RouteContext;
27  import org.kuali.rice.kew.engine.node.RouteNode;
28  import org.kuali.rice.kew.engine.node.RouteNodeInstance;
29  import org.kuali.rice.kew.exception.WorkflowServiceError;
30  import org.kuali.rice.kew.routeheader.DocumentContent;
31  import org.kuali.rice.kew.routeheader.StandardDocumentContent;
32  import org.kuali.rice.kew.rule.RuleExtensionBo;
33  import org.kuali.rice.kew.rule.RuleExtensionValue;
34  import org.kuali.rice.kew.rule.bo.RuleAttribute;
35  import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo;
36  import org.kuali.rice.kew.test.KEWTestCase;
37  import org.kuali.rice.kns.web.ui.Field;
38  import org.kuali.rice.kns.web.ui.Row;
39  import org.w3c.dom.Element;
40  import org.xml.sax.InputSource;
41  
42  import javax.xml.parsers.DocumentBuilderFactory;
43  import javax.xml.xpath.XPath;
44  import javax.xml.xpath.XPathConstants;
45  import javax.xml.xpath.XPathFactory;
46  import java.io.BufferedReader;
47  import java.io.StringReader;
48  import java.util.ArrayList;
49  import java.util.HashMap;
50  import java.util.Iterator;
51  import java.util.List;
52  import java.util.Map;
53  
54  import static org.junit.Assert.assertFalse;
55  import static org.junit.Assert.assertTrue;
56  
57  public class StandardGenericXMLRuleAttributeTest extends KEWTestCase {
58  
59  	private DocumentContent docContent;
60  	private StandardGenericXMLRuleAttribute attribute;
61  	private List<RuleExtension> extensions;
62  
63  	public void setUp() throws Exception {
64          super.setUp();
65  		attribute = new StandardGenericXMLRuleAttribute();
66  		String documentcontent =
67  			"<documentContent>" +
68  				"<attributeContent>"+
69  					"<xmlContent>"+
70  						"<fieldDef name=\"givenname\">"+
71  							"<value>Dave</value>"+
72  		                                "</fieldDef>"+
73  						"<fieldDef name=\"gender\">"+
74  							"<value>female</value>"+
75  						"</fieldDef>"+
76  						"<fieldDef name=\"color\">"+
77  							"<value>green</value>"+
78  						"</fieldDef>"+
79  						"<fieldDef name=\"totalDollar\">"+
80  							"<value>500</value>"+
81  						"</fieldDef>"+
82  					"</xmlContent>"+
83  					"<xmlContent>"+
84  						"<fieldDef name=\"givenname\">"+
85  							"<value>Jane</value>"+
86  		                                "</fieldDef>"+
87  						"<fieldDef name=\"gender\">"+
88  							"<value>female</value>"+
89  						"</fieldDef>"+
90  						"<fieldDef name=\"color\">"+
91  							"<value>blue</value>"+
92  						"</fieldDef>"+
93  						"<fieldDef name=\"totalDollar\">"+
94  							"<value>400</value>"+
95  						"</fieldDef>"+
96  					"</xmlContent>"+
97  				"</attributeContent>"+
98                              "</documentContent>";
99  
100 		String routingConfig =
101 			"<routingConfig>"+
102 				"<globalEvaluations>" +
103 					"<xpathexpression>//fieldDef/value != 'Nothing'</xpathexpression>" +
104 				"</globalEvaluations>"+
105 
106 				"<fieldDef name=\"givenname\" title=\"First name\" workflowType=\"ALL\">"+
107 					"<value>Joe</value>"+
108 					"<display>"+
109 						"<type>text</type>"+
110 						"<meta><name>size</name><value>20</value></meta>"+
111 					"</display>" +
112 					"<validation required=\"true\">"+
113 						"<regex>^[a-zA-Z ]+$</regex>"+
114 						"<message>Invalid first name</message>"+
115         			"</validation>"+
116 					"<fieldEvaluation><xpathexpression>//xmlContent/fieldDef[@name='givenname']/value = wf:ruledata('givenname')</xpathexpression></fieldEvaluation>"+
117 				"</fieldDef>"+
118 				"<fieldDef name=\"gender\" title=\"Gender\" workflowType=\"ALL\">"+
119 					"<value>male</value>"+
120 					"<display>"+
121 						"<type>radio</type>"+
122 						"<values title=\"Male\">male</values>"+
123 						"<values title=\"Female\">female</values>"+
124 					"</display>"+
125 			        "<validation required=\"true\">" +
126 		        		"<regex>(male|female)</regex>"+
127 		        		"<message>Invalid gender</message>"+
128 		        	"</validation>"+
129 					"<fieldEvaluation><xpathexpression>//xmlContent/fieldDef[@name='gender']/value = wf:ruledata('gender')</xpathexpression></fieldEvaluation>"+
130 				"</fieldDef>"+
131 				"<fieldDef name=\"color\" title=\"Color\" workflowType=\"ALL\">" +
132 					"<value>blue</value>" +
133 					"<display>" +
134 						"<type>select</type>" +
135 						"<values title=\"Red\">red</values>" +
136 						"<values title=\"Green\">green</values>" +
137 						"<values title=\"Blue\" selected=\"true\">blue</values>" +
138 					"</display>" +
139 					"<validation required=\"true\">"+
140 			        	"<regex>(red|green|blue|)</regex>"+
141 			        	"<message>Invalid color</message>"+
142 			        "</validation>"+
143 					"<fieldEvaluation><xpathexpression>//xmlContent/fieldDef[@name='color']/value = wf:ruledata('color')</xpathexpression></fieldEvaluation>"+
144 				"</fieldDef>"+
145 				"<fieldDef name=\"maxDollar\" title=\"Max dollar\" workflowType=\"RULE\">" +
146 					"<display>" +
147 						"<type>text</type>" +
148 					"</display>" +
149 					"<fieldEvaluation><xpathexpression>//xmlContent/fieldDef[@name='totalDollar']/value &lt;= wf:ruledata('maxDollar')</xpathexpression></fieldEvaluation>"+
150 				"</fieldDef>"+
151 				"<fieldDef name=\"minDollar\" title=\"Min dollar\" workflowType=\"RULE\">" +
152 					"<display>" +
153 						"<type>text</type>" +
154 					"</display>" +
155 					"<fieldEvaluation><xpathexpression>//xmlContent/fieldDef[@name='totalDollar']/value &gt;= wf:ruledata('minDollar')</xpathexpression></fieldEvaluation>"+
156 			    "</fieldDef>"+
157 				"<fieldDef name=\"totalDollar\" title=\"Total dollar\" workflowType=\"REPORT\">" +
158 					"<display>" +
159 						"<type>text</type>" +
160 					"</display>" +
161 		        "</fieldDef>" +
162             "</routingConfig>";
163 
164         // stub the RouteContext - it is needed for xpath caching optimization
165         RouteContext ctx = new RouteContext();
166         RouteNodeInstance fakeRouteNodeInstance = new RouteNodeInstance();
167         RouteNode fakeRouteNode = new RouteNode();
168         fakeRouteNode.setRouteNodeName("fakeRouteNode");
169         fakeRouteNodeInstance.setRouteNode(fakeRouteNode);
170         fakeRouteNodeInstance.setRouteNodeInstanceId("fakeRouteNodeInstance");
171         ctx.setNodeInstance(fakeRouteNodeInstance);
172 
173 		docContent = new StandardDocumentContent(documentcontent, ctx);
174 
175 		RuleAttribute ruleAttribute = new RuleAttribute();
176 		ruleAttribute.setXmlConfigData(routingConfig);
177 		ruleAttribute.setName("MyUniqueRuleAttribute1");
178         ruleAttribute.setType("SearchableXmlAttribute");
179         ruleAttribute.setResourceDescriptor(StandardGenericXMLSearchableAttribute.class.getName());
180 		attribute.setExtensionDefinition(RuleAttribute.to(ruleAttribute));
181 	}
182 
183 	@Test public void testValidateRoutingData(){
184         Map<String, String> paramMap = new HashMap<String, String>();
185 		paramMap.put("givenname", "Dave");
186 		paramMap.put("gender", "female");
187 		paramMap.put("color", "green");
188 		paramMap.put("totalDollar", "500");
189 
190 		assertTrue("Errors found", attribute.validateRoutingData(paramMap).isEmpty());
191 	}
192 
193 	@Test public void testValidateRuleData(){
194         Map<String, String> paramMap = new HashMap<String, String>();
195 		paramMap.put("givenname", "Dave");
196 		paramMap.put("gender", "female");
197 		paramMap.put("color", "green");
198 		paramMap.put("totalDollar", "500");
199 
200 		assertTrue("Errors found", attribute.validateRuleData(paramMap).isEmpty());
201 
202 		paramMap = new HashMap<String, String>();
203 		paramMap.put("givenname", "4444");
204 		paramMap.put("gender", "crap");
205 		paramMap.put("color", "green");
206 		paramMap.put("totalDollar", "500");
207 
208         assertFalse("Error list should contain at least one error.", attribute.validateRuleData(paramMap).isEmpty());
209 
210 		paramMap = new HashMap<String, String>();
211 		paramMap.put("givenname", "");
212 		paramMap.put("gender", "female");
213 		paramMap.put("color", "green");
214 		paramMap.put("totalDollar", "500");
215 
216 		assertFalse("givenname should be required.", attribute.validateRuleData(paramMap).isEmpty());
217 	}
218 
219     @Test public void testRuleDataAttributeErrorTypesAreConformant() {
220         Map<String, String> paramMap = new HashMap<String, String>();
221 		paramMap.put("givenname", "4444");
222 		paramMap.put("gender", "crap");
223 		paramMap.put("color", "green");
224 		paramMap.put("totalDollar", "500");
225 
226 		List<RemotableAttributeError> errors = attribute.validateRuleData(paramMap);
227         assertFalse("Error list should contain at least one error.", errors.isEmpty());
228         for (Object e: errors) {
229             assertTrue(RemotableAttributeError.class.isAssignableFrom(e.getClass()));
230         }
231     }
232 
233     @Test public void testRoutingDataAttributeErrorTypesAreConformant(){
234         Map<String, String> paramMap = new HashMap<String, String>();
235         paramMap.put("givenname", "4444");
236         paramMap.put("gender", "crap");
237         paramMap.put("color", "green");
238         paramMap.put("totalDollar", "500");
239 
240         List<RemotableAttributeError> errors = attribute.validateRoutingData(paramMap);
241         assertFalse("Error list should contain at least one error.", errors.isEmpty());
242         for (Object e: errors) {
243             assertTrue(RemotableAttributeError.class.isAssignableFrom(e.getClass()));
244         }
245     }
246 
247     /**
248      * Tests SGXA attribute matching behavior with extension value keys that do not necessarily match
249      * a field defined in the attribute
250      */
251     @Test public void testNonMatchingExtensionKey() throws WorkflowException {
252         loadXmlFile("TestExtensionValueMatching.xml");
253         WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("arh14"), "TestDocument");
254 
255         WorkflowAttributeDefinition.Builder attr = WorkflowAttributeDefinition.Builder.create(StandardGenericXMLRuleAttribute.class.getName());
256         attr.setAttributeName("Attr1");
257         // expected to match RuleTemplate with extension value: value='1' with xpath expression /xmlRouting/field[@name=attr1] = wf:ruledata('value')
258         attr.addPropertyDefinition("attr1", "2");
259         doc.addAttributeDefinition(attr.build());
260 
261         doc.route("");
262 
263         String id = doc.getDocumentId();
264 
265         doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user1"), id);
266         assertTrue("Request should have been generated to user1", doc.isApprovalRequested());
267 
268         doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user2"), id);
269         assertTrue("Expected approval request to user2", doc.isApprovalRequested());
270     }
271 
272 	/*
273 	 * Test method for 'org.kuali.rice.kew.rule.xmlrouting.StandardGenericXMLRuleAttribute.isMatch(DocumentContent, List)'
274 	 */
275 	@Test public void testIsMatch() {
276 		RuleExtensionBo extension = new RuleExtensionBo();
277 
278 		List<RuleExtensionValue> values = new ArrayList<RuleExtensionValue>();
279 		RuleExtensionValue value = new RuleExtensionValue();
280 		value.setKey("givenname");
281 		value.setValue("Dave");
282 		values.add(value);
283 
284 		RuleExtensionValue value2 = new RuleExtensionValue();
285 		value2.setKey("gender");
286 		value2.setValue("female");
287 		values.add(value2);
288 
289 		RuleExtensionValue value3 = new RuleExtensionValue();
290 		value3.setKey("color");
291 		value3.setValue("green");
292 		values.add(value3);
293 
294 		extension.setExtensionValues(values);
295 		RuleTemplateAttributeBo ruleTemplateAttribute = new RuleTemplateAttributeBo();
296 
297 		RuleAttribute ruleAttribute = new RuleAttribute();
298 		ruleAttribute.setName("MyUniqueRuleAttribute1");
299         ruleAttribute.setType("RuleAttribute");
300         ruleAttribute.setResourceDescriptor("noClass");
301 
302 		ruleTemplateAttribute.setRuleAttribute(ruleAttribute);
303         ruleTemplateAttribute.setRuleTemplateId("ruleTemplateId1");
304         ruleTemplateAttribute.setDisplayOrder(new Integer(1));
305 		extension.setRuleTemplateAttribute(ruleTemplateAttribute);
306 		RuleExtensionBo extension2 = new RuleExtensionBo();
307 
308 		List values2 = new ArrayList();
309 		RuleExtensionValue valueNew = new RuleExtensionValue();
310 		valueNew.setKey("givenname");
311 		valueNew.setValue("Jack");
312 
313 		RuleExtensionValue minDollar = new RuleExtensionValue();
314 		minDollar.setKey("minDollar");
315 		minDollar.setValue("300");
316         RuleExtensionValue maxDollar = new RuleExtensionValue();
317         maxDollar.setKey("maxDollar");
318         maxDollar.setValue("600");
319 
320 
321 		values2.add(valueNew);
322 		values2.add(minDollar);
323 		values2.add(maxDollar);
324 		extension2.setExtensionValues(values2);
325 		RuleTemplateAttributeBo ruleTemplateAttribute2 = new RuleTemplateAttributeBo();
326 
327 		RuleAttribute ruleAttribute2 = new RuleAttribute();
328 		ruleAttribute2.setName("MyUniqueRuleAttribute2");
329         ruleAttribute2.setType("RuleAttribute");
330         ruleAttribute2.setResourceDescriptor("noClass");
331 
332 		ruleTemplateAttribute2.setRuleAttribute(ruleAttribute2);
333         ruleTemplateAttribute2.setRuleTemplateId("ruleTemplateId2");
334         ruleTemplateAttribute2.setDisplayOrder(new Integer(2));
335 		extension2.setRuleTemplateAttribute(ruleTemplateAttribute2);
336 
337 		extensions = new ArrayList();
338 		extensions.add(RuleExtensionBo.to(extension));
339 		extensions.add(RuleExtensionBo.to(extension2));
340 
341 		assertTrue("Givenname did not match Dave, gender did not match female, or color did not match green", attribute.isMatch(docContent, extensions));
342 
343 		extension = new RuleExtensionBo();
344 		values = new ArrayList();
345 		RuleExtensionValue value4 = new RuleExtensionValue();
346 		value4.setKey("givenname");
347 		value4.setValue("Dave");
348 		values.add(value4);
349 
350 		RuleExtensionValue value5 = new RuleExtensionValue();
351 		value5.setKey("gender");
352 		value5.setValue("male");
353 		values.add(value5);
354 
355 		RuleExtensionValue value6 = new RuleExtensionValue();
356 		value6.setKey("color");
357 		value6.setValue("green");
358 		values.add(value6);
359 
360 		extension.setExtensionValues(values);
361 		ruleTemplateAttribute = new RuleTemplateAttributeBo();
362 
363 		ruleAttribute = new RuleAttribute();
364 		ruleAttribute.setName("MyUniqueRuleAttribute1");
365         ruleAttribute.setType("RuleAttribute");
366         ruleAttribute.setResourceDescriptor("noClass");
367 
368 
369 		ruleTemplateAttribute.setRuleAttribute(ruleAttribute);
370         ruleTemplateAttribute.setRuleTemplateId("ruleTemplateId");
371         ruleTemplateAttribute.setDisplayOrder(new Integer(1));
372 		extension.setRuleTemplateAttribute(ruleTemplateAttribute);
373 
374 
375 		values2 = new ArrayList();
376 		valueNew = new RuleExtensionValue();
377 		valueNew.setKey("givenname");
378 		valueNew.setValue("Jack");
379 
380 		values2.add(valueNew);
381 		extension2.setExtensionValues(values2);
382 		ruleTemplateAttribute2 = new RuleTemplateAttributeBo();
383 
384 		ruleAttribute2 = new RuleAttribute();
385 		ruleAttribute2.setName("MyUniqueRuleAttribute2");
386         ruleAttribute2.setType("RuleAttribute");
387         ruleAttribute2.setResourceDescriptor("noClass");
388 
389 
390 		ruleTemplateAttribute2.setRuleAttribute(ruleAttribute2);
391         ruleTemplateAttribute2.setRuleTemplateId("ruleTemplateId2");
392         ruleTemplateAttribute2.setDisplayOrder(new Integer(2));
393 		extension2.setRuleTemplateAttribute(ruleTemplateAttribute2);
394 
395 		extensions = new ArrayList();
396 		extensions.add(RuleExtensionBo.to(extension));
397 		extensions.add(RuleExtensionBo.to(extension2));
398 		assertFalse("Gender female != male.", attribute.isMatch(docContent, extensions));
399 
400 		///////
401 
402 		extension = new RuleExtensionBo();
403 		values = new ArrayList();
404 
405 		RuleExtensionValue value7 = new RuleExtensionValue();
406 		value7.setKey("maxDollar");
407 		value7.setValue("500");
408 
409 
410 		RuleExtensionValue value8 = new RuleExtensionValue();
411 		value8.setKey("minDollar");
412 		value8.setValue("100");
413 
414         values.add(value7);
415 		values.add(value8);
416 		extension.setExtensionValues(values);
417 		ruleTemplateAttribute = new RuleTemplateAttributeBo();
418 		ruleAttribute = new RuleAttribute();
419 		ruleAttribute.setName("MyUniqueRuleAttribute1");
420         ruleAttribute.setType("RuleAttribute");
421         ruleAttribute.setResourceDescriptor("noClass");
422 
423 		ruleTemplateAttribute.setRuleAttribute(ruleAttribute);
424         ruleTemplateAttribute.setRuleTemplateId("ruleTemplateId");
425         ruleTemplateAttribute.setDisplayOrder(new Integer(1));
426 		extension.setRuleTemplateAttribute(ruleTemplateAttribute);
427 
428 		values2 = new ArrayList();
429 
430 		valueNew = new RuleExtensionValue();
431 		valueNew.setKey("givenname");
432 		valueNew.setValue("Jack");
433 		values2.add(valueNew);
434 
435 		extension2.setExtensionValues(values2);
436 		ruleTemplateAttribute2 = new RuleTemplateAttributeBo();
437 
438 		ruleAttribute2 = new RuleAttribute();
439 		ruleAttribute2.setName("MyUniqueRuleAttribute2");
440         ruleAttribute2.setType("RuleAttribute");
441         ruleAttribute2.setResourceDescriptor("noClass");
442 
443 
444 		ruleTemplateAttribute2.setRuleAttribute(ruleAttribute2);
445         ruleTemplateAttribute2.setRuleTemplateId("ruleTemplateId2");
446         ruleTemplateAttribute2.setDisplayOrder(new Integer(2));
447 		extension2.setRuleTemplateAttribute(ruleTemplateAttribute2);
448 
449 		extensions = new ArrayList();
450 		extensions.add(RuleExtensionBo.to(extension));
451 		extensions.add(RuleExtensionBo.to(extension2));
452 		assertTrue("Total dollar is greater than the max or less than the min.", attribute.isMatch(docContent, extensions));
453 	}
454 
455 	/*
456 	 * Test method for 'org.kuali.rice.kew.rule.xmlrouting.StandardGenericXMLRuleAttribute.getRuleRows()'
457 	 */
458 	@Test public void testGetRuleRows() {
459 		assertTrue("Invalid number of rule rows", attribute.getRuleRows().size() == 5);
460 
461 		String routingConfigWithQuickfinders =
462 			"<routingConfig>"+
463 				"<globalEvaluations>" +
464 					"<xpathexpression>//field/value != 'Nothing'</xpathexpression>" +
465 				"</globalEvaluations>"+
466 
467 				"<fieldDef name=\"chart\" title=\"Chart\" workflowType=\"ALL\">"+
468 					"<value>BL</value>"+
469 					"<display>"+
470 						"<type>text</type>"+
471 						"<meta><name>size</name><value>20</value></meta>"+
472 					"</display>" +
473 					"<fieldEvaluation><xpathexpression>//xmlContent/field[@name='chart']/value = wf:ruledata('chart')</xpathexpression></fieldEvaluation>"+
474 				"</fieldDef>"+
475 				"<fieldDef name=\"org\" title=\"Org\" workflowType=\"ALL\">"+
476 					"<display>"+
477 						"<type>text</type>"+
478 					"</display>" +
479 					"<lookup businessObjectClass=\"ChartOrgLookupableImplService\">" +
480 					    "<fieldConversions>" +
481 				          "<fieldConversion lookupFieldName=\"fin_coa_cd\" localFieldName=\"chart\"/>" +
482 					      "<fieldConversion lookupFieldName=\"org_cd\" localFieldName=\"org\"/>" +
483 					    "</fieldConversions>" +
484 					"</lookup>" +
485 					"<fieldEvaluation><xpathexpression>//xmlContent/field[@name='gender']/value = wf:ruledata('gender')</xpathexpression></fieldEvaluation>"+
486 				"</fieldDef>" +
487             "</routingConfig>";
488 
489 		RuleAttribute ruleAttribute = new RuleAttribute();
490 		ruleAttribute.setXmlConfigData(routingConfigWithQuickfinders);
491 		ruleAttribute.setName("MyUniqueRuleAttribute3");
492         ruleAttribute.setType("SearchableXmlAttribute");
493         ruleAttribute.setResourceDescriptor(StandardGenericXMLSearchableAttribute.class.getName());
494 		StandardGenericXMLRuleAttribute myAttribute = new StandardGenericXMLRuleAttribute();
495 		myAttribute.setExtensionDefinition(RuleAttribute.to(ruleAttribute));
496 
497 		for (Iterator iter = myAttribute.getRuleRows().iterator(); iter.hasNext();) {
498 			Row row = (Row) iter.next();
499 			for (Iterator iterator = row.getFields().iterator(); iterator.hasNext();) {
500 				Field field = (Field) iterator.next();
501 				if(field.getFieldType().equals(Field.QUICKFINDER)){
502 					assertTrue("Did not find quickfinder.", true);
503 				}
504 			}
505 		}
506 		assertTrue("Should have 2 rows and 3 fields: chart, org, and quickfinder.", myAttribute.getRuleRows().size() == 2);
507 	}
508 
509 	@Test public void testGetRoutingDataRows() {
510 		assertTrue("Invalid number of routing data rows",attribute.getRoutingDataRows().size() == 4);
511 	}
512 
513 	@Test public void testGetDocContent() {
514 		//test the standard doc content...
515         Map<String, String> paramMap = new HashMap<String, String>();
516 		paramMap.put("givenname", "Dave");
517 		paramMap.put("gender", "female");
518 		paramMap.put("color", "green");
519 		paramMap.put("totalDollar", "500");
520 
521 		attribute.setParamMap(paramMap);
522 		try{
523 			XPath xpath = XPathFactory.newInstance().newXPath();
524 			Element element = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new BufferedReader(new StringReader(attribute.getDocContent())))).getDocumentElement();
525 
526 			String findStuff = "//xmlRouting/field[@name='givenname']/value";
527 			assertTrue("Document content does not contain field givenname with value of Dave.", "Dave".equals(xpath.evaluate(findStuff, element, XPathConstants.STRING)));
528 
529 			findStuff = "//xmlRouting/field[@name='gender']/value";
530 			assertTrue("Document content does not contain field gender with value of female.", "female".equals(xpath.evaluate(findStuff, element, XPathConstants.STRING)));
531 
532 			findStuff = "//xmlRouting/field[@name='color']/value";
533 			assertTrue("Document content does not contain field color with value of green.", "green".equals(xpath.evaluate(findStuff, element, XPathConstants.STRING)));
534 
535 			findStuff = "//xmlRouting/field[@name='totalDollar']/value";
536 			assertTrue("Document content does not contain field totalDollar with value of 500.", "500".equals(xpath.evaluate(findStuff, element, XPathConstants.STRING)));
537 		} catch (Exception e){
538 			e.printStackTrace();
539 		}
540 
541 		// Now test the custom doc content...
542 		String routingConfig =
543 			"<routingConfig>" +
544 				"<fieldDef name=\"myname\" title=\"First name\" workflowType=\"ALL\">"+
545 					"<value>Joe</value>"+
546 					"<display>"+
547 						"<type>text</type>"+
548 						"<meta><name>size</name><value>20</value></meta>"+
549 					"</display>"+
550 					"<fieldEvaluation><xpathexpression>//putWhateverWordsIwantInsideThisTag/myname/value = wf:ruledata('myname')</xpathexpression></fieldEvaluation>"+
551 				"</fieldDef>"+
552 				"<fieldDef name=\"theGender\" title=\"Gender\" workflowType=\"ALL\">"+
553 					"<value>male</value>"+
554 					"<display>"+
555 						"<type>radio</type>"+
556 						"<values title=\"Male\">male</values>"+
557 						"<values title=\"Female\">female</values>"+
558 					"</display>"+
559 					"<fieldEvaluation><xpathexpression>//putWhateverWordsIwantInsideThisTag/theGender/value = wf:ruledata('theGender')</xpathexpression></fieldEvaluation>"+
560 				"</fieldDef>"+
561 				"<fieldDef name=\"myFavoriteColor\" title=\"Color\" workflowType=\"ALL\">" +
562 					"<value>blue</value>" +
563 					"<display>" +
564 						"<type>select</type>" +
565 						"<values title=\"Red\">red</values>" +
566 						"<values title=\"Green\">green</values>" +
567 						"<values title=\"Blue\" selected=\"true\">blue</values>" +
568 					"</display>" +
569 					"<fieldEvaluation><xpathexpression>//putWhateverWordsIwantInsideThisTag/myFavoriteColor/value = wf:ruledata('myFavoriteColor')</xpathexpression></fieldEvaluation>"+
570 				"</fieldDef>"+
571 				"<fieldDef name=\"maxDollar\" title=\"Max dollar\" workflowType=\"RULE\">" +
572 					"<display>" +
573 						"<type>text</type>" +
574 					"</display>" +
575 					"<fieldEvaluation><xpathexpression>//putWhateverWordsIwantInsideThisTag/myMoney/value &lt;= wf:ruledata('maxDollar')</xpathexpression></fieldEvaluation>"+
576 				"</fieldDef>"+
577 				"<fieldDef name=\"minDollar\" title=\"Min dollar\" workflowType=\"RULE\">" +
578 					"<display>" +
579 						"<type>text</type>" +
580 					"</display>" +
581 					"<fieldEvaluation><xpathexpression>//putWhateverWordsIwantInsideThisTag/myMoney/value &gt;= wf:ruledata('minDollar')</xpathexpression></fieldEvaluation>"+
582 			    "</fieldDef>"+
583 				"<fieldDef name=\"myMoney\" title=\"Total dollar\" workflowType=\"REPORT\">" +
584 					"<display>" +
585 						"<type>text</type>" +
586 					"</display>" +
587 		        "</fieldDef>"+
588 
589 		        "<xmlDocumentContent>"+
590 		        	"<putWhateverWordsIwantInsideThisTag>"+
591 		        		"<myname>"+
592 		        			"<value>%myname%</value>"+
593 	        		    "</myname>"+
594 	        		    "<theGender>"+
595 	        		    	"<value>%theGender%</value>"+
596 	    				"</theGender>"+
597 	    				"<myFavoriteColor>"+
598 	    					"<value>%myFavoriteColor%</value>"+
599 						"</myFavoriteColor>"+
600 		        		"<myMoney>"+
601 	        				"<value>%myMoney%</value>"+
602 	        			"</myMoney>"+
603 					"</putWhateverWordsIwantInsideThisTag>"+
604 		        "</xmlDocumentContent>"+
605             "</routingConfig>";
606 		try {
607 			paramMap = new HashMap<String, String>();
608 			paramMap.put("myname", "jack");
609 			paramMap.put("theGender", "male");
610 			paramMap.put("myFavoriteColor", "blue");
611 			paramMap.put("myMoney", "10");
612 
613 			attribute.setParamMap(paramMap);
614 
615 			RuleAttribute ruleAttribute = new RuleAttribute();
616 			ruleAttribute.setXmlConfigData(routingConfig);
617 			ruleAttribute.setName("MyUniqueRuleAttribute2");
618 			attribute.setExtensionDefinition(RuleAttribute.to(ruleAttribute));
619 
620 			String docContent = attribute.getDocContent();
621 			assertTrue("DocContent was not found.", docContent != null && docContent.length() > 0);
622 
623 
624 			XPath xpath = XPathFactory.newInstance().newXPath();
625 			Element foundDocContent = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new BufferedReader(new StringReader(docContent)))).getDocumentElement();
626 
627 			String findStuff = "//putWhateverWordsIwantInsideThisTag/myMoney/value";
628 			assertTrue("Document content does not contain field myMoney with a value of 10.", "10".equals(xpath.evaluate(findStuff, foundDocContent, XPathConstants.STRING)));
629 
630 			findStuff = "//putWhateverWordsIwantInsideThisTag/myFavoriteColor/value";
631 			assertTrue("Document content does not contain field myFavoriteColor with value of blue.", "blue".equals(xpath.evaluate(findStuff, foundDocContent, XPathConstants.STRING)));
632 
633 			findStuff = "//putWhateverWordsIwantInsideThisTag/theGender/value";
634 			assertTrue("Document content does not contain field theGender with value of male.", "male".equals(xpath.evaluate(findStuff, foundDocContent, XPathConstants.STRING)));
635 
636 			findStuff = "//putWhateverWordsIwantInsideThisTag/myname/value";
637 			assertTrue("Document content does not contain field myname with value of jack.", "jack".equals(xpath.evaluate(findStuff, foundDocContent, XPathConstants.STRING)));
638 
639 		} catch(Exception e){
640 			e.printStackTrace();
641 		}
642 	}
643 }