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 }