1 /**
2 * Copyright 2005-2013 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.kns.workflow;
17
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20 import org.junit.Ignore;
21 import org.junit.Test;
22 import org.kuali.rice.core.api.impex.xml.XmlConstants;
23 import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
24 import org.kuali.rice.core.api.reflect.ObjectDefinition;
25 import org.kuali.rice.kew.api.KewApiConstants;
26 import org.kuali.rice.kew.api.extension.ExtensionDefinition;
27 import org.kuali.rice.kew.rule.xmlrouting.XPathHelper;
28 import org.kuali.rice.krad.datadictionary.AttributeDefinition;
29 import org.kuali.rice.krad.datadictionary.BusinessObjectEntry;
30 import org.kuali.rice.krad.datadictionary.DocumentEntry;
31 import org.kuali.rice.krad.service.DataDictionaryService;
32 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
33 import org.kuali.rice.kns.workflow.attribute.KualiXmlAttribute;
34 import org.kuali.rice.kns.workflow.attribute.KualiXmlAttributeHelper;
35 import org.kuali.rice.krad.test.KRADTestCase;
36 import org.w3c.dom.NamedNodeMap;
37 import org.w3c.dom.Node;
38 import org.w3c.dom.NodeList;
39 import org.xml.sax.InputSource;
40
41 import javax.xml.transform.Result;
42 import javax.xml.transform.Source;
43 import javax.xml.transform.TransformerException;
44 import javax.xml.transform.TransformerFactory;
45 import javax.xml.transform.dom.DOMSource;
46 import javax.xml.transform.stream.StreamResult;
47 import javax.xml.xpath.XPath;
48 import javax.xml.xpath.XPathConstants;
49 import java.io.StringReader;
50 import java.io.StringWriter;
51 import java.util.HashSet;
52 import java.util.Set;
53
54 import org.junit.Assert;
55
56
57 /**
58 * KualiXMLAttributeImplTest tests the {@link KualiXmlAttributeHelper} operations of getting data from the data dictionary for workflow
59 * attributes
60 *
61 * @author Kuali Rice Team (rice.collab@kuali.org)
62 */
63 @Ignore
64 public class KualiXMLAttributeImplTest extends KRADTestCase {
65 private static Log LOG = LogFactory.getLog(KualiXMLAttributeImplTest.class);
66
67 private static final String RULE_ATTRIBUTE_CONFIG_NODE_NAME = XmlConstants.ROUTING_CONFIG;
68 private static final String SEARCH_ATTRIBUTE_CONFIG_NODE_NAME = XmlConstants.SEARCHING_CONFIG;
69
70 XPath myXPath = XPathHelper.newXPath();
71 String ruleAttributeXml = "";
72 String searchAttributeXml = "";
73 // private boolean testFailed = false;
74
75 @Override
76 public void setUp() throws Exception {
77 super.setUp();
78 // read in the file and make it a string
79
80 // InputStream is = new FileInputStream(getBaseDir() + "/src/test/resources/org/kuali/rice/kew/batch/data/RuleAttributeContent.xml");
81 // is.
82 // if ((StringUtils.isNotBlank(ruleAttributeXml)) && (StringUtils.isNotBlank(searchAttributeXml))) {
83 // return;
84 // }
85 //
86 // DataSource mySource = KEWServiceLocator.getDataSource();
87 // ruleAttributeXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<data >\n<ruleAttributes>\n";
88 // searchAttributeXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<data >\n<ruleAttributes>\n";
89 // Connection dbCon = null;
90 // try {
91 //
92 // dbCon = mySource.getConnection();
93 // Statement dbAsk = dbCon.createStatement();
94 // ResultSet dbAnswer = dbAsk.executeQuery("select * from EN_RULE_ATTRIB_T");
95 // // ResultSet dbAnswer = dbAsk.executeQuery("select * from EN_RULE_ATTRIB_T where RULE_ATTRIB_NM =
96 // // 'SystemParameterRoutingAttribute'");
97 //
98 // while (dbAnswer.next()) {
99 // String className = dbAnswer.getString("RULE_ATTRIB_CLS_NM");
100 // if (StringUtils.isNotBlank(className)) {
101 // try {
102 // if (KualiXmlAttribute.class.isAssignableFrom(Class.forName(className))) {
103 // LOG.debug("Adding attribute to test with class name " + className);
104 // String attributeType = dbAnswer.getString("RULE_ATTRIB_TYP");
105 // if (KewApiConstants.RULE_XML_ATTRIBUTE_TYPE.equals(attributeType)) {
106 // ruleAttributeXml = ruleAttributeXml + "<ruleAttribute>\n\t<name>";
107 // ruleAttributeXml = ruleAttributeXml + dbAnswer.getString("RULE_ATTRIB_NM");
108 // ruleAttributeXml = ruleAttributeXml + "</name>\n\t<className>";
109 // ruleAttributeXml = ruleAttributeXml + className;
110 // ruleAttributeXml = ruleAttributeXml + "</className>\n\t<label>";
111 // ruleAttributeXml = ruleAttributeXml + dbAnswer.getString("RULE_ATTRIB_LBL_TXT");
112 // ruleAttributeXml = ruleAttributeXml + "</label>\n\t<description>";
113 // ruleAttributeXml = ruleAttributeXml + dbAnswer.getString("RULE_ATTRIB_DESC");
114 // ruleAttributeXml = ruleAttributeXml + "</description>\n\t<type>";
115 // ruleAttributeXml = ruleAttributeXml + attributeType;
116 // ruleAttributeXml = ruleAttributeXml + "</type>\n\t" + dbAnswer.getString("RULE_ATTRIB_XML_RTE_TXT") + "\n</ruleAttribute>\n";
117 //
118 // }
119 // else if (KewApiConstants.SEARCHABLE_XML_ATTRIBUTE_TYPE.equals(attributeType)) {
120 // searchAttributeXml = searchAttributeXml + "<ruleAttribute>\n\t<name>";
121 // searchAttributeXml = searchAttributeXml + dbAnswer.getString("RULE_ATTRIB_NM");
122 // searchAttributeXml = searchAttributeXml + "</name>\n\t<className>";
123 // searchAttributeXml = searchAttributeXml + className;
124 // searchAttributeXml = searchAttributeXml + "</className>\n\t<label>";
125 // searchAttributeXml = searchAttributeXml + dbAnswer.getString("RULE_ATTRIB_LBL_TXT");
126 // searchAttributeXml = searchAttributeXml + "</label>\n\t<description>";
127 // searchAttributeXml = searchAttributeXml + dbAnswer.getString("RULE_ATTRIB_DESC");
128 // searchAttributeXml = searchAttributeXml + "</description>\n\t<type>";
129 // searchAttributeXml = searchAttributeXml + attributeType;
130 // searchAttributeXml = searchAttributeXml + "</type>\n\t" + dbAnswer.getString("RULE_ATTRIB_XML_RTE_TXT") + "\n</ruleAttribute>\n";
131 //
132 // }
133 // }
134 // else {
135 // LOG.debug("Skipping attribute with class name " + className);
136 // }
137 // }
138 // catch (ClassNotFoundException cnfe) {
139 // LOG.debug("Could not find class for name '" + className + "'");
140 // }
141 // }
142 // }
143 // ruleAttributeXml = ruleAttributeXml + "</ruleAttributes>\n</data>\n";
144 // searchAttributeXml = searchAttributeXml + "</ruleAttributes>\n</data>\n";
145 //
146 // ruleAttributeXml = ruleAttributeXml.replaceAll(" & ", " & ");
147 // searchAttributeXml = searchAttributeXml.replaceAll(" & ", " & ");
148 //
149 // loadDataDictionaryEntries();
150 // }
151 // catch (Exception e) {
152 // e.printStackTrace();
153 // }
154 // finally {
155 // try {
156 // dbCon.close();
157 // }
158 // catch (SQLException sqle2) {
159 // sqle2.printStackTrace();
160 // }
161 // }
162 }
163
164 /**
165 * goes through all of the ruleAttributes in the inputSource and tries to get a label out of the data dictionary
166 */
167 @Test public void testConfirmLabels() {
168 boolean failed = false;
169 // test rule xml attributes
170 failed |= confirmLabels(KualiXmlAttributeHelper.notFound, ruleAttributeXml, RULE_ATTRIBUTE_CONFIG_NODE_NAME);
171
172 // test search xml attributes
173 failed |= confirmLabels(KualiXmlAttributeHelper.notFound, searchAttributeXml, SEARCH_ATTRIBUTE_CONFIG_NODE_NAME);
174
175 Assert.assertFalse("At least one label was incorrect", failed);
176 }
177
178 /**
179 * accepts a Node, and if all goes well, returns the exact same Node with expected changes
180 *
181 * <p>The node should have the name and title attributes added to
182 * the fieldDef element. This exercises the getConfigXML method on the class under test.</p>
183 *
184 * @param xmlNode - an input node
185 * @return the input node with attributes added
186 * @throws TransformerException
187 */
188 private Node configureRuleAttribute(Node xmlNode, KualiXmlAttribute myAttribute) throws TransformerException {
189 ExtensionDefinition.Builder extensionDefinition = ExtensionDefinition.Builder.create("fakeName", "fakeType", "fakeResourceDescriptor");
190
191 StringWriter xmlBuffer = new StringWriter();
192 Source source = new DOMSource(xmlNode);
193 Result result = new StreamResult(xmlBuffer);
194 TransformerFactory.newInstance().newTransformer().transform(source, result);
195
196 extensionDefinition.getConfiguration().put(KewApiConstants.ATTRIBUTE_XML_CONFIG_DATA, new String(xmlBuffer.getBuffer()));
197
198 if (LOG.isDebugEnabled()) {
199 LOG.debug("This is the XML that was added to the attribute");
200 LOG.debug(new String(xmlBuffer.getBuffer()));
201 StringWriter xmlBuffer2 = new StringWriter();
202 Source source2 = new DOMSource(xmlNode);
203 Result result2 = new StreamResult(xmlBuffer2);
204 TransformerFactory.newInstance().newTransformer().transform(source2, result2);
205 LOG.debug("This is the XML that was returned from the ruleAttribute");
206 LOG.debug(new String(xmlBuffer2.getBuffer()));
207 }
208 return myAttribute.getConfigXML(extensionDefinition.build());
209 }
210
211 /**
212 * compares the label from the test to the expected, or not expected, value for all of the rule attributes in the file
213 *
214 * <p>The inputSource file should be as close to the production version as possible, as described by the class comments. It
215 * accepts the string to test against as a parameter.</p>
216 *
217 * @param testString
218 * @param attributeXml
219 * @param configNodeName
220 */
221 private boolean confirmLabels(String testString, String attributeXml, String configNodeName) {
222 boolean testFailed = false;
223 String theTitle = "";
224 String theName = "";
225 String attributeName = "";
226 try {
227 NodeList tempList = (NodeList) myXPath.evaluate("//ruleAttribute", new InputSource(new StringReader(attributeXml)), XPathConstants.NODESET);
228 for (int i = 0; i < tempList.getLength(); i++) { // loop over ruleattributes
229 Node originalNode = tempList.item(i);
230 Set ruleAttributeFieldDefNames = new HashSet();
231 Set ruleAttributeFieldDefTitles = new HashSet();
232 attributeName = (String) myXPath.evaluate(WorkflowUtils.XSTREAM_MATCH_RELATIVE_PREFIX + "name", originalNode, XPathConstants.STRING);
233 Node classNameNode = (Node) myXPath.evaluate(WorkflowUtils.XSTREAM_MATCH_RELATIVE_PREFIX + "className", originalNode, XPathConstants.NODE);
234 if ((classNameNode != null) && (classNameNode.getFirstChild() != null)) {
235 if (LOG.isInfoEnabled()) {
236 LOG.info("Checking attribute with name '" + attributeName + "'");
237 }
238 KualiXmlAttribute myAttribute = (KualiXmlAttribute) GlobalResourceLoader.getObject(new ObjectDefinition(classNameNode.getFirstChild().getNodeValue()));
239 Node xmlNode = configureRuleAttribute(originalNode, myAttribute);
240 NamedNodeMap fieldDefAttributes = null;
241 String potentialFailMessage = "";
242
243 try {
244 NodeList xmlNodeList = (NodeList) myXPath.evaluate("//fieldDef", xmlNode, XPathConstants.NODESET);
245
246 for (int j = 0; j < xmlNodeList.getLength(); j++) {
247 Node fieldDefXmlNode = xmlNodeList.item(j);
248 fieldDefAttributes = fieldDefXmlNode.getAttributes();
249
250 theTitle = fieldDefAttributes.getNamedItem("title").getNodeValue();// Making sure they are clean
251 theName = fieldDefAttributes.getNamedItem("name").getNodeValue();
252 if (LOG.isDebugEnabled()) {
253 LOG.debug(attributeName);
254 LOG.debug("name=" + theName + " title=" + theTitle);
255 }
256 if (ruleAttributeFieldDefNames.contains(theName)) {
257 // names of fieldDefs inside a single attribute must be unique
258 potentialFailMessage = "Each fieldDef name on a single attribute must be unique and the fieldDef name '" + theName + "' already exists on the attribute '" + attributeName + "'";
259 Assert.fail(potentialFailMessage);
260 }
261 else {
262 ruleAttributeFieldDefNames.add(theName);
263 }
264 if (testString.equals(KualiXmlAttributeHelper.notFound)) {
265 potentialFailMessage = "Each fieldDef title should be a valid value and currently the title for attribute '" + attributeName + "' is '" + theTitle + "'";
266 Assert.assertFalse(potentialFailMessage, theTitle.equals(testString));
267 if (ruleAttributeFieldDefTitles.contains(theTitle)) {
268 /*
269 * Titles of fieldDefs inside a single attribute should be unique in the normal case. Having two
270 * fields with the same label would certainly confuse the user. However, due to the way the
271 * confirmSource test works, all the titles/labels must be the same. So only run this check when
272 * not in the confirmSource test.
273 */
274 potentialFailMessage = "Each fieldDef title on a single attribute must be unique and the fieldDef title '" + theTitle + "' already exists on the attribute '" + attributeName + "'";
275 Assert.fail(potentialFailMessage);
276 }
277 else {
278 ruleAttributeFieldDefTitles.add(theTitle);
279 }
280 }
281 else {
282 potentialFailMessage = "For attribute '" + attributeName + "' the title should have been '" + testString + "' but was actually '" + theTitle + "'";
283 Assert.assertEquals(potentialFailMessage, testString, theTitle);
284 }
285 }
286 }
287 catch (AssertionError afe) {
288 LOG.warn("Assertion Failed for attribute '" + attributeName + "' with error " + potentialFailMessage, afe);
289 testFailed = true;
290 }
291 finally {
292 attributeName = "";
293 }
294 }
295 else {
296 throw new RuntimeException("Could not find class for attribute named '" + attributeName + "'");
297 }
298 }
299 }
300 catch (Exception e) {
301 LOG.error("General Exception thrown for attribute '" + attributeName + "'", e);
302 testFailed = true;
303 }
304 return testFailed;
305 }
306
307 /**
308 * confirms that the labels are coming from the data dictionary
309 *
310 * <p>This is done by modifying all the dictionary values
311 * programatically to a nonsense value. It then rebuilds the Hash Table and runs confirmLabels() to make sure the labels have
312 * changed.</p>
313 */
314 @Test public void testLabelSource() {
315 DataDictionaryService myDDService = KRADServiceLocatorWeb.getDataDictionaryService();
316 XPath xpath = XPathHelper.newXPath();
317 String nonsenseString = "BananaRama";
318 for (Object tempEntity : myDDService.getDataDictionary().getBusinessObjectEntries().values()) {
319
320 for ( AttributeDefinition attribute : ((BusinessObjectEntry) tempEntity).getAttributes() ) {
321 attribute.setLabel(nonsenseString);
322 attribute.setShortLabel(nonsenseString);
323 }
324
325 }
326 for (Object tempEntity : myDDService.getDataDictionary().getDocumentEntries().values()) {
327
328 for ( AttributeDefinition attribute : ((DocumentEntry) tempEntity).getAttributes() ) {
329 attribute.setLabel(nonsenseString);
330 attribute.setShortLabel(nonsenseString);
331 }
332
333 }
334 // KualiXmlAttributeHelper.buildDictionaryHash();
335
336 boolean failed = false;
337 Assert.assertFalse("At least one label was incorrect", failed);
338 // test rule xml attributes
339 failed |= confirmLabels(nonsenseString, ruleAttributeXml, RULE_ATTRIBUTE_CONFIG_NODE_NAME);
340
341 // test search xml attributes
342 failed |= confirmLabels(nonsenseString, searchAttributeXml, SEARCH_ATTRIBUTE_CONFIG_NODE_NAME);
343
344 Assert.assertFalse("At least one label was incorrect", failed);
345 }
346
347 /*
348 unused method
349
350 private void loadDataDictionaryEntries() throws Exception {
351 KualiXmlRuleAttributeImpl myAttribute = new KualiXmlRuleAttributeImpl();
352 NamedNodeMap fieldDefAttributes = null;
353 NodeList tempList = (NodeList) myXPath.evaluate("//ruleAttribute", new InputSource(new StringReader(ruleAttributeXml)), XPathConstants.NODESET);
354 for (int i = 0; i < tempList.getLength(); i++) {
355 Node xmlNode = configureRuleAttribute(tempList.item(i), myAttribute);
356 }
357 KualiXmlSearchableAttributeImpl mySearchAttribute = new KualiXmlSearchableAttributeImpl();
358 fieldDefAttributes = null;
359 tempList = (NodeList) myXPath.evaluate("//ruleAttribute", new InputSource(new StringReader(searchAttributeXml)), XPathConstants.NODESET);
360 for (int i = 0; i < tempList.getLength(); i++) {
361 Node xmlNode = configureRuleAttribute(tempList.item(i), mySearchAttribute);
362 }
363 }*/
364 }