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(" & ", " &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    }