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.krad.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.bo.RuleAttribute;
28  import org.kuali.rice.kew.rule.xmlrouting.XPathHelper;
29  import org.kuali.rice.krad.datadictionary.AttributeDefinition;
30  import org.kuali.rice.krad.datadictionary.BusinessObjectEntry;
31  import org.kuali.rice.krad.datadictionary.DocumentEntry;
32  import org.kuali.rice.krad.service.DataDictionaryService;
33  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
34  import org.kuali.rice.krad.workflow.attribute.KualiXmlAttribute;
35  import org.kuali.rice.krad.workflow.attribute.KualiXmlAttributeHelper;
36  import org.kuali.rice.krad.workflow.attribute.KualiXmlRuleAttributeImpl;
37  import org.kuali.rice.krad.workflow.attribute.KualiXmlSearchableAttributeImpl;
38  import org.kuali.test.KRADTestCase;
39  import org.w3c.dom.NamedNodeMap;
40  import org.w3c.dom.Node;
41  import org.w3c.dom.NodeList;
42  import org.xml.sax.InputSource;
43  
44  import javax.xml.transform.Result;
45  import javax.xml.transform.Source;
46  import javax.xml.transform.TransformerException;
47  import javax.xml.transform.TransformerFactory;
48  import javax.xml.transform.dom.DOMSource;
49  import javax.xml.transform.stream.StreamResult;
50  import javax.xml.xpath.XPath;
51  import javax.xml.xpath.XPathConstants;
52  import java.io.StringReader;
53  import java.io.StringWriter;
54  import java.util.HashSet;
55  import java.util.Set;
56  
57  import static org.junit.Assert.*;
58  
59  
60  /**
61   * This class tests the {@link KualiXmlAttributeHelper} operations of getting data from the data dictionary for workflow
62   * attributes
63   * 
64   * @author Kuali Rice Team (rice.collab@kuali.org)
65   */
66  @Ignore
67  public class KualiXMLAttributeImplTest extends KRADTestCase {
68      private static Log LOG = LogFactory.getLog(KualiXMLAttributeImplTest.class);
69  
70      private static final String RULE_ATTRIBUTE_CONFIG_NODE_NAME = XmlConstants.ROUTING_CONFIG;
71      private static final String SEARCH_ATTRIBUTE_CONFIG_NODE_NAME = XmlConstants.SEARCHING_CONFIG;
72  
73      XPath myXPath = XPathHelper.newXPath();
74      String ruleAttributeXml = "";
75      String searchAttributeXml = "";
76  //    private boolean testFailed = false;
77  
78      @Override
79      public void setUp() throws Exception {
80          super.setUp();
81          // read in the file and make it a string
82  
83  //        InputStream is = new FileInputStream(getBaseDir() + "/src/test/resources/org/kuali/rice/kew/batch/data/RuleAttributeContent.xml");
84  //        is.
85  //        if ((StringUtils.isNotBlank(ruleAttributeXml)) && (StringUtils.isNotBlank(searchAttributeXml))) {
86  //            return;
87  //        }
88  //
89  //        DataSource mySource = KEWServiceLocator.getDataSource();
90  //        ruleAttributeXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<data >\n<ruleAttributes>\n";
91  //        searchAttributeXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<data >\n<ruleAttributes>\n";
92  //        Connection dbCon = null;
93  //        try {
94  //
95  //            dbCon = mySource.getConnection();
96  //            Statement dbAsk = dbCon.createStatement();
97  //            ResultSet dbAnswer = dbAsk.executeQuery("select * from EN_RULE_ATTRIB_T");
98  //            // ResultSet dbAnswer = dbAsk.executeQuery("select * from EN_RULE_ATTRIB_T where RULE_ATTRIB_NM =
99  //            // '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(" & ", " &amp; ");
150 //            searchAttributeXml = searchAttributeXml.replaceAll(" & ", " &amp; ");
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 }