001 /** 002 * Copyright 2005-2011 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.rice.krad.workflow; 017 018 import org.apache.commons.logging.Log; 019 import org.apache.commons.logging.LogFactory; 020 import org.junit.Ignore; 021 import org.junit.Test; 022 import org.kuali.rice.core.api.impex.xml.XmlConstants; 023 import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; 024 import org.kuali.rice.core.api.reflect.ObjectDefinition; 025 import org.kuali.rice.kew.api.KewApiConstants; 026 import org.kuali.rice.kew.api.extension.ExtensionDefinition; 027 import org.kuali.rice.kew.rule.bo.RuleAttribute; 028 import org.kuali.rice.kew.rule.xmlrouting.XPathHelper; 029 import org.kuali.rice.krad.datadictionary.AttributeDefinition; 030 import org.kuali.rice.krad.datadictionary.BusinessObjectEntry; 031 import org.kuali.rice.krad.datadictionary.DocumentEntry; 032 import org.kuali.rice.krad.service.DataDictionaryService; 033 import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 034 import org.kuali.rice.krad.workflow.attribute.KualiXmlAttribute; 035 import org.kuali.rice.krad.workflow.attribute.KualiXmlAttributeHelper; 036 import org.kuali.rice.krad.workflow.attribute.KualiXmlRuleAttributeImpl; 037 import org.kuali.rice.krad.workflow.attribute.KualiXmlSearchableAttributeImpl; 038 import org.kuali.test.KRADTestCase; 039 import org.w3c.dom.NamedNodeMap; 040 import org.w3c.dom.Node; 041 import org.w3c.dom.NodeList; 042 import org.xml.sax.InputSource; 043 044 import javax.xml.transform.Result; 045 import javax.xml.transform.Source; 046 import javax.xml.transform.TransformerException; 047 import javax.xml.transform.TransformerFactory; 048 import javax.xml.transform.dom.DOMSource; 049 import javax.xml.transform.stream.StreamResult; 050 import javax.xml.xpath.XPath; 051 import javax.xml.xpath.XPathConstants; 052 import java.io.StringReader; 053 import java.io.StringWriter; 054 import java.util.HashSet; 055 import java.util.Set; 056 057 import static org.junit.Assert.*; 058 059 060 /** 061 * This class tests the {@link KualiXmlAttributeHelper} operations of getting data from the data dictionary for workflow 062 * attributes 063 * 064 * @author Kuali Rice Team (rice.collab@kuali.org) 065 */ 066 @Ignore 067 public class KualiXMLAttributeImplTest extends KRADTestCase { 068 private static Log LOG = LogFactory.getLog(KualiXMLAttributeImplTest.class); 069 070 private static final String RULE_ATTRIBUTE_CONFIG_NODE_NAME = XmlConstants.ROUTING_CONFIG; 071 private static final String SEARCH_ATTRIBUTE_CONFIG_NODE_NAME = XmlConstants.SEARCHING_CONFIG; 072 073 XPath myXPath = XPathHelper.newXPath(); 074 String ruleAttributeXml = ""; 075 String searchAttributeXml = ""; 076 // private boolean testFailed = false; 077 078 @Override 079 public void setUp() throws Exception { 080 super.setUp(); 081 // read in the file and make it a string 082 083 // InputStream is = new FileInputStream(getBaseDir() + "/src/test/resources/org/kuali/rice/kew/batch/data/RuleAttributeContent.xml"); 084 // is. 085 // if ((StringUtils.isNotBlank(ruleAttributeXml)) && (StringUtils.isNotBlank(searchAttributeXml))) { 086 // return; 087 // } 088 // 089 // DataSource mySource = KEWServiceLocator.getDataSource(); 090 // ruleAttributeXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<data >\n<ruleAttributes>\n"; 091 // searchAttributeXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<data >\n<ruleAttributes>\n"; 092 // Connection dbCon = null; 093 // try { 094 // 095 // dbCon = mySource.getConnection(); 096 // Statement dbAsk = dbCon.createStatement(); 097 // ResultSet dbAnswer = dbAsk.executeQuery("select * from EN_RULE_ATTRIB_T"); 098 // // ResultSet dbAnswer = dbAsk.executeQuery("select * from EN_RULE_ATTRIB_T where RULE_ATTRIB_NM = 099 // // 'SystemParameterRoutingAttribute'"); 100 // 101 // while (dbAnswer.next()) { 102 // String className = dbAnswer.getString("RULE_ATTRIB_CLS_NM"); 103 // if (StringUtils.isNotBlank(className)) { 104 // try { 105 // if (KualiXmlAttribute.class.isAssignableFrom(Class.forName(className))) { 106 // LOG.debug("Adding attribute to test with class name " + className); 107 // String attributeType = dbAnswer.getString("RULE_ATTRIB_TYP"); 108 // if (KewApiConstants.RULE_XML_ATTRIBUTE_TYPE.equals(attributeType)) { 109 // ruleAttributeXml = ruleAttributeXml + "<ruleAttribute>\n\t<name>"; 110 // ruleAttributeXml = ruleAttributeXml + dbAnswer.getString("RULE_ATTRIB_NM"); 111 // ruleAttributeXml = ruleAttributeXml + "</name>\n\t<className>"; 112 // ruleAttributeXml = ruleAttributeXml + className; 113 // ruleAttributeXml = ruleAttributeXml + "</className>\n\t<label>"; 114 // ruleAttributeXml = ruleAttributeXml + dbAnswer.getString("RULE_ATTRIB_LBL_TXT"); 115 // ruleAttributeXml = ruleAttributeXml + "</label>\n\t<description>"; 116 // ruleAttributeXml = ruleAttributeXml + dbAnswer.getString("RULE_ATTRIB_DESC"); 117 // ruleAttributeXml = ruleAttributeXml + "</description>\n\t<type>"; 118 // ruleAttributeXml = ruleAttributeXml + attributeType; 119 // ruleAttributeXml = ruleAttributeXml + "</type>\n\t" + dbAnswer.getString("RULE_ATTRIB_XML_RTE_TXT") + "\n</ruleAttribute>\n"; 120 // 121 // } 122 // else if (KewApiConstants.SEARCHABLE_XML_ATTRIBUTE_TYPE.equals(attributeType)) { 123 // searchAttributeXml = searchAttributeXml + "<ruleAttribute>\n\t<name>"; 124 // searchAttributeXml = searchAttributeXml + dbAnswer.getString("RULE_ATTRIB_NM"); 125 // searchAttributeXml = searchAttributeXml + "</name>\n\t<className>"; 126 // searchAttributeXml = searchAttributeXml + className; 127 // searchAttributeXml = searchAttributeXml + "</className>\n\t<label>"; 128 // searchAttributeXml = searchAttributeXml + dbAnswer.getString("RULE_ATTRIB_LBL_TXT"); 129 // searchAttributeXml = searchAttributeXml + "</label>\n\t<description>"; 130 // searchAttributeXml = searchAttributeXml + dbAnswer.getString("RULE_ATTRIB_DESC"); 131 // searchAttributeXml = searchAttributeXml + "</description>\n\t<type>"; 132 // searchAttributeXml = searchAttributeXml + attributeType; 133 // searchAttributeXml = searchAttributeXml + "</type>\n\t" + dbAnswer.getString("RULE_ATTRIB_XML_RTE_TXT") + "\n</ruleAttribute>\n"; 134 // 135 // } 136 // } 137 // else { 138 // LOG.debug("Skipping attribute with class name " + className); 139 // } 140 // } 141 // catch (ClassNotFoundException cnfe) { 142 // LOG.debug("Could not find class for name '" + className + "'"); 143 // } 144 // } 145 // } 146 // ruleAttributeXml = ruleAttributeXml + "</ruleAttributes>\n</data>\n"; 147 // searchAttributeXml = searchAttributeXml + "</ruleAttributes>\n</data>\n"; 148 // 149 // ruleAttributeXml = ruleAttributeXml.replaceAll(" & ", " & "); 150 // searchAttributeXml = searchAttributeXml.replaceAll(" & ", " & "); 151 // 152 // loadDataDictionaryEntries(); 153 // } 154 // catch (Exception e) { 155 // e.printStackTrace(); 156 // } 157 // finally { 158 // try { 159 // dbCon.close(); 160 // } 161 // catch (SQLException sqle2) { 162 // sqle2.printStackTrace(); 163 // } 164 // } 165 } 166 167 /** 168 * This method goes through all of the ruleAttributes in the inputSource and tries to get a label out of the data dictionary. 169 */ 170 @Test public void testConfirmLabels() { 171 boolean failed = false; 172 // test rule xml attributes 173 failed |= confirmLabels(KualiXmlAttributeHelper.notFound, ruleAttributeXml, RULE_ATTRIBUTE_CONFIG_NODE_NAME); 174 175 // test search xml attributes 176 failed |= confirmLabels(KualiXmlAttributeHelper.notFound, searchAttributeXml, SEARCH_ATTRIBUTE_CONFIG_NODE_NAME); 177 178 assertFalse("At least one label was incorrect", failed); 179 } 180 181 /** 182 * This method accepts a Node, and if all goes well, returns the exact same Node, with the name and title attributes added to 183 * the fieldDef element. This exercises the getConfigXML method on the class under test. 184 * 185 * @param xmlNode 186 * @return 187 * @throws TransformerException 188 */ 189 private Node configureRuleAttribute(Node xmlNode, KualiXmlAttribute myAttribute) throws TransformerException { 190 ExtensionDefinition.Builder extensionDefinition = ExtensionDefinition.Builder.create("fakeName", "fakeType", "fakeResourceDescriptor"); 191 192 StringWriter xmlBuffer = new StringWriter(); 193 Source source = new DOMSource(xmlNode); 194 Result result = new StreamResult(xmlBuffer); 195 TransformerFactory.newInstance().newTransformer().transform(source, result); 196 197 extensionDefinition.getConfiguration().put(KewApiConstants.ATTRIBUTE_XML_CONFIG_DATA, new String(xmlBuffer.getBuffer())); 198 199 if (LOG.isDebugEnabled()) { 200 LOG.debug("This is the XML that was added to the attribute"); 201 LOG.debug(new String(xmlBuffer.getBuffer())); 202 StringWriter xmlBuffer2 = new StringWriter(); 203 Source source2 = new DOMSource(xmlNode); 204 Result result2 = new StreamResult(xmlBuffer2); 205 TransformerFactory.newInstance().newTransformer().transform(source2, result2); 206 LOG.debug("This is the XML that was returned from the ruleAttribute"); 207 LOG.debug(new String(xmlBuffer2.getBuffer())); 208 } 209 return myAttribute.getConfigXML(extensionDefinition.build()); 210 } 211 212 /** 213 * This method compares the label from the test to the expected, or not expected, value for all of the rule attributes in the 214 * file. 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. 216 * 217 * @param testString 218 */ 219 private boolean confirmLabels(String testString, String attributeXml, String configNodeName) { 220 boolean testFailed = false; 221 String theTitle = ""; 222 String theName = ""; 223 String attributeName = ""; 224 try { 225 NodeList tempList = (NodeList) myXPath.evaluate("//ruleAttribute", new InputSource(new StringReader(attributeXml)), XPathConstants.NODESET); 226 for (int i = 0; i < tempList.getLength(); i++) { // loop over ruleattributes 227 Node originalNode = tempList.item(i); 228 Set ruleAttributeFieldDefNames = new HashSet(); 229 Set ruleAttributeFieldDefTitles = new HashSet(); 230 attributeName = (String) myXPath.evaluate(WorkflowUtils.XSTREAM_MATCH_RELATIVE_PREFIX + "name", originalNode, XPathConstants.STRING); 231 Node classNameNode = (Node) myXPath.evaluate(WorkflowUtils.XSTREAM_MATCH_RELATIVE_PREFIX + "className", originalNode, XPathConstants.NODE); 232 if ((classNameNode != null) && (classNameNode.getFirstChild() != null)) { 233 if (LOG.isInfoEnabled()) { 234 LOG.info("Checking attribute with name '" + attributeName + "'"); 235 } 236 KualiXmlAttribute myAttribute = (KualiXmlAttribute) GlobalResourceLoader.getObject(new ObjectDefinition(classNameNode.getFirstChild().getNodeValue())); 237 Node xmlNode = configureRuleAttribute(originalNode, myAttribute); 238 NamedNodeMap fieldDefAttributes = null; 239 String potentialFailMessage = ""; 240 241 try { 242 NodeList xmlNodeList = (NodeList) myXPath.evaluate("//fieldDef", xmlNode, XPathConstants.NODESET); 243 244 for (int j = 0; j < xmlNodeList.getLength(); j++) { 245 Node fieldDefXmlNode = xmlNodeList.item(j); 246 fieldDefAttributes = fieldDefXmlNode.getAttributes(); 247 248 theTitle = fieldDefAttributes.getNamedItem("title").getNodeValue();// Making sure they are clean 249 theName = fieldDefAttributes.getNamedItem("name").getNodeValue(); 250 if (LOG.isDebugEnabled()) { 251 LOG.debug(attributeName); 252 LOG.debug("name=" + theName + " title=" + theTitle); 253 } 254 if (ruleAttributeFieldDefNames.contains(theName)) { 255 // names of fieldDefs inside a single attribute must be unique 256 potentialFailMessage = "Each fieldDef name on a single attribute must be unique and the fieldDef name '" + theName + "' already exists on the attribute '" + attributeName + "'"; 257 fail(potentialFailMessage); 258 } 259 else { 260 ruleAttributeFieldDefNames.add(theName); 261 } 262 if (testString.equals(KualiXmlAttributeHelper.notFound)) { 263 potentialFailMessage = "Each fieldDef title should be a valid value and currently the title for attribute '" + attributeName + "' is '" + theTitle + "'"; 264 assertFalse(potentialFailMessage, theTitle.equals(testString)); 265 if (ruleAttributeFieldDefTitles.contains(theTitle)) { 266 /* 267 * Titles of fieldDefs inside a single attribute should be unique in the normal case. Having two 268 * fields with the same label would certainly confuse the user. However, due to the way the 269 * confirmSource test works, all the titles/labels must be the same. So only run this check when 270 * not in the confirmSource test. 271 */ 272 potentialFailMessage = "Each fieldDef title on a single attribute must be unique and the fieldDef title '" + theTitle + "' already exists on the attribute '" + attributeName + "'"; 273 fail(potentialFailMessage); 274 } 275 else { 276 ruleAttributeFieldDefTitles.add(theTitle); 277 } 278 } 279 else { 280 potentialFailMessage = "For attribute '" + attributeName + "' the title should have been '" + testString + "' but was actually '" + theTitle + "'"; 281 assertEquals(potentialFailMessage, testString, theTitle); 282 } 283 } 284 } 285 catch (AssertionError afe) { 286 LOG.warn("Assertion Failed for attribute '" + attributeName + "' with error " + potentialFailMessage, afe); 287 testFailed = true; 288 } 289 finally { 290 attributeName = ""; 291 } 292 } 293 else { 294 throw new RuntimeException("Could not find class for attribute named '" + attributeName + "'"); 295 } 296 } 297 } 298 catch (Exception e) { 299 LOG.error("General Exception thrown for attribute '" + attributeName + "'", e); 300 testFailed = true; 301 } 302 return testFailed; 303 } 304 305 /** 306 * This method confirms that the labels are coming from the data dictionary by modifing all the dictionary values 307 * programatically to a nonsense value. It then rebuilds the Hash Table and runs confirmLabels() to make sure the labels have 308 * changed. 309 */ 310 @Test public void testLabelSource() { 311 DataDictionaryService myDDService = KRADServiceLocatorWeb.getDataDictionaryService(); 312 XPath xpath = XPathHelper.newXPath(); 313 String nonsenseString = "BananaRama"; 314 for (Object tempEntity : myDDService.getDataDictionary().getBusinessObjectEntries().values()) { 315 316 for ( AttributeDefinition attribute : ((BusinessObjectEntry) tempEntity).getAttributes() ) { 317 attribute.setLabel(nonsenseString); 318 attribute.setShortLabel(nonsenseString); 319 } 320 321 } 322 for (Object tempEntity : myDDService.getDataDictionary().getDocumentEntries().values()) { 323 324 for ( AttributeDefinition attribute : ((DocumentEntry) tempEntity).getAttributes() ) { 325 attribute.setLabel(nonsenseString); 326 attribute.setShortLabel(nonsenseString); 327 } 328 329 } 330 // KualiXmlAttributeHelper.buildDictionaryHash(); 331 332 boolean failed = false; 333 assertFalse("At least one label was incorrect", failed); 334 // test rule xml attributes 335 failed |= confirmLabels(nonsenseString, ruleAttributeXml, RULE_ATTRIBUTE_CONFIG_NODE_NAME); 336 337 // test search xml attributes 338 failed |= confirmLabels(nonsenseString, searchAttributeXml, SEARCH_ATTRIBUTE_CONFIG_NODE_NAME); 339 340 assertFalse("At least one label was incorrect", failed); 341 } 342 343 private void loadDataDictionaryEntries() throws Exception { 344 KualiXmlRuleAttributeImpl myAttribute = new KualiXmlRuleAttributeImpl(); 345 NamedNodeMap fieldDefAttributes = null; 346 NodeList tempList = (NodeList) myXPath.evaluate("//ruleAttribute", new InputSource(new StringReader(ruleAttributeXml)), XPathConstants.NODESET); 347 for (int i = 0; i < tempList.getLength(); i++) { 348 Node xmlNode = configureRuleAttribute(tempList.item(i), myAttribute); 349 } 350 KualiXmlSearchableAttributeImpl mySearchAttribute = new KualiXmlSearchableAttributeImpl(); 351 fieldDefAttributes = null; 352 tempList = (NodeList) myXPath.evaluate("//ruleAttribute", new InputSource(new StringReader(searchAttributeXml)), XPathConstants.NODESET); 353 for (int i = 0; i < tempList.getLength(); i++) { 354 Node xmlNode = configureRuleAttribute(tempList.item(i), mySearchAttribute); 355 } 356 } 357 }