1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kns.workflow.attribute;
17
18 import java.io.StringWriter;
19 import java.util.ArrayList;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24
25 import javax.xml.transform.Result;
26 import javax.xml.transform.Source;
27 import javax.xml.transform.TransformerFactory;
28 import javax.xml.transform.dom.DOMSource;
29 import javax.xml.transform.stream.StreamResult;
30 import javax.xml.xpath.XPath;
31 import javax.xml.xpath.XPathConstants;
32 import javax.xml.xpath.XPathExpressionException;
33
34 import org.apache.commons.lang.StringUtils;
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.kuali.rice.core.util.KeyLabelPair;
38 import org.kuali.rice.kew.rule.xmlrouting.XPathHelper;
39 import org.kuali.rice.kew.util.XmlHelper;
40 import org.kuali.rice.kns.lookup.keyvalues.KeyValuesFinder;
41 import org.kuali.rice.kns.service.DataDictionaryService;
42 import org.kuali.rice.kns.service.KNSServiceLocator;
43 import org.w3c.dom.Element;
44 import org.w3c.dom.NamedNodeMap;
45 import org.w3c.dom.Node;
46 import org.w3c.dom.NodeList;
47
48
49 public class KualiXmlAttributeHelper {
50 private static Log LOG = LogFactory.getLog(KualiXmlRuleAttributeImpl.class);
51 private static XPath xpath = XPathHelper.newXPath();
52 private static final String testVal = "\'/[^\']*\'";
53 private static final String testVal2 = "/[^/]+/" + "*";
54 private static final String cleanVal = "[^/\']+";
55 private static final String ruledataVal = "ruledata[^\']*\'([^\']*)";
56
57
58
59 private static final Pattern xPathPattern = Pattern.compile(testVal);
60 private static final Pattern termPattern = Pattern.compile(testVal2);
61 private static final Pattern cleanPattern = Pattern.compile(cleanVal);
62 private static final Pattern targetPattern = Pattern.compile(ruledataVal);
63
64 public static final String ATTRIBUTE_LABEL_BO_REFERENCE_PREFIX = "kuali_dd_label(";
65 public static final String ATTRIBUTE_LABEL_BO_REFERENCE_SUFFIX = ")";
66 public static final String ATTRIBUTE_SHORT_LABEL_BO_REFERENCE_PREFIX = "kuali_dd_short_label(";
67 public static final String ATTRIBUTE_SHORT_LABEL_BO_REFERENCE_SUFFIX = ")";
68 private static final String KUALI_VALUES_FINDER_REFERENCE_PREFIX = "kuali_values_finder_class(";
69 private static final String KUALI_VALUES_FINDER_REFERENCE_SUFFIX = ")";
70 public static final String notFound = "Label Not Found";
71
72 private String lastXPath = "";
73
74
75
76
77
78
79
80
81 public Element processConfigXML(Element root) {
82 return this.processConfigXML(root, null);
83 }
84
85
86
87
88
89
90
91
92 public Element processConfigXML(Element root, String[] xpathExpressionElements) {
93
94 NodeList fields = root.getElementsByTagName("fieldDef");
95 Element theTag = null;
96 String docContent = "";
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112 org.w3c.dom.Document xmlDoc = null;
113 if (!xmlDocumentContentExists(root)) {
114 fields = root.getElementsByTagName("fieldDef");
115 xmlDoc = root.getOwnerDocument();
116 }
117 for (int i = 0; i < fields.getLength(); i++) {
118 String name = null;
119 if (!xmlDocumentContentExists(root)) {
120 theTag = (Element) fields.item(i);
121
122
123
124
125
126
127
128 List<String> xPathTerms = getXPathTerms(theTag);
129 if (xPathTerms.size() != 0) {
130 Node iterNode = xmlDoc.createElement("xmlDocumentContent");
131
132
133 xmlDoc.normalize();
134
135 iterNode.normalize();
136
137
138
139
140
141 for (int j = 0; j < xPathTerms.size(); j++) {
142
143 iterNode.appendChild(xmlDoc.createElement(xPathTerms.get(j)));
144 xmlDoc.normalize();
145
146 iterNode = iterNode.getFirstChild();
147 iterNode.normalize();
148
149 }
150 iterNode.setTextContent("%" + xPathTerms.get(xPathTerms.size() - 1) + "%");
151 root.appendChild(iterNode);
152 }
153 }
154 theTag = (Element) fields.item(i);
155
156 NodeList displayTagElements = theTag.getElementsByTagName("display");
157 if (displayTagElements.getLength() == 1) {
158 Element displayTag = (Element) displayTagElements.item(0);
159 List valuesElementsToAdd = new ArrayList();
160 for (int w = 0; w < displayTag.getChildNodes().getLength(); w++) {
161 Node displayTagChildNode = (Node) displayTag.getChildNodes().item(w);
162 if ((displayTagChildNode != null) && ("values".equals(displayTagChildNode.getNodeName()))) {
163 if (displayTagChildNode.getChildNodes().getLength() > 0) {
164 String valuesNodeText = displayTagChildNode.getFirstChild().getNodeValue();
165 String potentialClassName = getPotentialKualiClassName(valuesNodeText, KUALI_VALUES_FINDER_REFERENCE_PREFIX, KUALI_VALUES_FINDER_REFERENCE_SUFFIX);
166 if (StringUtils.isNotBlank(potentialClassName)) {
167 try {
168 Class finderClass = Class.forName((String) potentialClassName);
169 KeyValuesFinder finder = (KeyValuesFinder) finderClass.newInstance();
170 NamedNodeMap valuesNodeAttributes = displayTagChildNode.getAttributes();
171 Node potentialSelectedAttribute = (valuesNodeAttributes != null) ? valuesNodeAttributes.getNamedItem("selected") : null;
172 for (Iterator iter = finder.getKeyValues().iterator(); iter.hasNext();) {
173 KeyLabelPair keyLabelPair = (KeyLabelPair) iter.next();
174 Element newValuesElement = root.getOwnerDocument().createElement("values");
175 newValuesElement.appendChild(root.getOwnerDocument().createTextNode(keyLabelPair.getKey().toString()));
176
177 newValuesElement.setAttribute("title", keyLabelPair.getLabel());
178 if (potentialSelectedAttribute != null) {
179 newValuesElement.setAttribute("selected", potentialSelectedAttribute.getNodeValue());
180 }
181 valuesElementsToAdd.add(newValuesElement);
182 }
183 }
184 catch (ClassNotFoundException cnfe) {
185 String errorMessage = "Caught an exception trying to find class '" + potentialClassName + "'";
186 LOG.error(errorMessage, cnfe);
187 throw new RuntimeException(errorMessage, cnfe);
188 }
189 catch (InstantiationException ie) {
190 String errorMessage = "Caught an exception trying to instantiate class '" + potentialClassName + "'";
191 LOG.error(errorMessage, ie);
192 throw new RuntimeException(errorMessage, ie);
193 }
194 catch (IllegalAccessException iae) {
195 String errorMessage = "Caught an access exception trying to instantiate class '" + potentialClassName + "'";
196 LOG.error(errorMessage, iae);
197 throw new RuntimeException(errorMessage, iae);
198 }
199 }
200 else {
201 valuesElementsToAdd.add(displayTagChildNode.cloneNode(true));
202 }
203 displayTag.removeChild(displayTagChildNode);
204 }
205 }
206 }
207 for (Iterator iter = valuesElementsToAdd.iterator(); iter.hasNext();) {
208 Element valuesElementToAdd = (Element) iter.next();
209 displayTag.appendChild(valuesElementToAdd);
210 }
211 }
212 if ((xpathExpressionElements != null) && (xpathExpressionElements.length > 0)) {
213 NodeList fieldEvaluationElements = theTag.getElementsByTagName("fieldEvaluation");
214 if (fieldEvaluationElements.getLength() == 1) {
215 Element fieldEvaluationTag = (Element) fieldEvaluationElements.item(0);
216 List tagsToAdd = new ArrayList();
217 for (int w = 0; w < fieldEvaluationTag.getChildNodes().getLength(); w++) {
218 Node fieldEvaluationChildNode = (Node) fieldEvaluationTag.getChildNodes().item(w);
219 Element newTagToAdd = null;
220 if ((fieldEvaluationChildNode != null) && ("xpathexpression".equals(fieldEvaluationChildNode.getNodeName()))) {
221 newTagToAdd = root.getOwnerDocument().createElement("xpathexpression");
222 newTagToAdd.appendChild(root.getOwnerDocument().createTextNode(generateNewXpathExpression(fieldEvaluationChildNode.getFirstChild().getNodeValue(), xpathExpressionElements)));
223 tagsToAdd.add(newTagToAdd);
224 fieldEvaluationTag.removeChild(fieldEvaluationChildNode);
225 }
226 }
227 for (Iterator iter = tagsToAdd.iterator(); iter.hasNext();) {
228 Element elementToAdd = (Element) iter.next();
229 fieldEvaluationTag.appendChild(elementToAdd);
230 }
231 }
232 }
233 theTag.setAttribute("title", getBusinessObjectTitle(theTag));
234
235 }
236 if (LOG.isDebugEnabled()) {
237 LOG.debug(XmlHelper.jotNode(root));
238 StringWriter xmlBuffer = new StringWriter();
239 try {
240
241 root.normalize();
242 Source source = new DOMSource(root);
243 Result result = new StreamResult(xmlBuffer);
244 TransformerFactory.newInstance().newTransformer().transform(source, result);
245 }
246 catch (Exception e) {
247 LOG.debug(" Exception when printing debug XML output " + e);
248 }
249 LOG.debug(xmlBuffer.getBuffer());
250 }
251
252 return root;
253 }
254
255 private String generateNewXpathExpression(String currentXpathExpression, String[] newXpathExpressionElements) {
256 StringBuffer returnableString = new StringBuffer();
257 for (int i = 0; i < newXpathExpressionElements.length; i++) {
258 String newXpathElement = newXpathExpressionElements[i];
259 returnableString.append(newXpathElement);
260
261
262
263
264
265
266 if (((i + 1) != newXpathExpressionElements.length) || (newXpathExpressionElements.length == 1)) {
267 returnableString.append(currentXpathExpression);
268 }
269 }
270 return returnableString.toString();
271 }
272
273
274
275
276
277
278
279 private String getXPathText(Element root) {
280 try {
281 String textContent = null;
282 Node node = (Node) xpath.evaluate(".//xpathexpression", root, XPathConstants.NODE);
283 if (node != null) {
284 textContent = node.getTextContent();
285 }
286 return textContent;
287 }
288 catch (XPathExpressionException e) {
289 LOG.error("No XPath expression text found in element xpathexpression of configXML for document. " + e);
290 return null;
291
292 }
293 }
294
295
296
297
298
299
300
301 private boolean xmlDocumentContentExists(Element root) {
302 try {
303 if (((NodeList) xpath.evaluate("//xmlDocumentContent", root, XPathConstants.NODESET)).getLength() == 0) {
304 return false;
305 }
306 }
307 catch (XPathExpressionException e) {
308 LOG.error("Error parsing xmlDocumentConfig. " + e);
309 return false;
310 }
311 return true;
312 }
313
314 public static String getPotentialKualiClassName(String testString, String prefixIndicator, String suffixIndicator) {
315 if ((StringUtils.isNotBlank(testString)) && (testString.startsWith(prefixIndicator)) && (testString.endsWith(suffixIndicator))) {
316 return testString.substring(prefixIndicator.length(), testString.lastIndexOf(suffixIndicator));
317 }
318 return null;
319 }
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341 private String getBusinessObjectTitle(Element root) {
342 String businessObjectName = null;
343 String businessObjectText = root.getAttribute("title");
344 String potentialClassNameLongLabel = getPotentialKualiClassName(businessObjectText, ATTRIBUTE_LABEL_BO_REFERENCE_PREFIX, ATTRIBUTE_LABEL_BO_REFERENCE_SUFFIX);
345 String potentialClassNameShortLabel = getPotentialKualiClassName(businessObjectText, ATTRIBUTE_SHORT_LABEL_BO_REFERENCE_PREFIX, ATTRIBUTE_SHORT_LABEL_BO_REFERENCE_SUFFIX);
346
347 boolean requestedShortLabel = false;
348
349 if (StringUtils.isNotBlank(potentialClassNameLongLabel)) {
350 businessObjectName = potentialClassNameLongLabel;
351 }
352 else if (StringUtils.isNotBlank(potentialClassNameShortLabel)) {
353 businessObjectName = potentialClassNameShortLabel;
354 requestedShortLabel = true;
355 }
356 if (StringUtils.isNotBlank(businessObjectName)) {
357 DataDictionaryService DDService = KNSServiceLocator.getDataDictionaryService();
358
359 String title = null;
360 String targetVal = lastXPath;
361
362 if (LOG.isErrorEnabled()) {
363 LOG.debug("Finding title in BO=" + businessObjectName + " ObjectName=" + targetVal);
364 }
365
366 if (StringUtils.isNotBlank(targetVal)) {
367
368 if (requestedShortLabel) {
369 title = DDService.getAttributeShortLabel(businessObjectName, targetVal);
370 }
371 else {
372 title = DDService.getAttributeLabel(businessObjectName, targetVal);
373 }
374 if (StringUtils.isNotBlank(title)) {
375 return title;
376 }
377 }
378
379 targetVal = getRuleData(root);
380 if (LOG.isErrorEnabled()) {
381 LOG.debug("Finding title in BO=" + businessObjectName + " ObjectName=" + targetVal);
382 }
383 if (StringUtils.isNotBlank(targetVal)) {
384 title = DDService.getAttributeLabel(businessObjectName, targetVal);
385 if (StringUtils.isNotBlank(title)) {
386 return title;
387 }
388 }
389
390
391 targetVal = root.getAttribute("name");
392 if (LOG.isErrorEnabled()) {
393 LOG.debug("Finding title in BO=" + businessObjectName + " ObjectName=" + targetVal);
394 }
395 title = DDService.getAttributeLabel(businessObjectName, targetVal);
396
397 if (StringUtils.isNotBlank(title)) {
398 return title;
399 }
400 }
401
402 else if ( (StringUtils.isNotBlank(businessObjectText)) && (StringUtils.isBlank(businessObjectName)) ) {
403 return businessObjectText;
404 }
405 return notFound;
406
407 }
408
409
410
411
412
413
414
415 private String getRuleData(Element root) {
416 String xPathRuleTarget = getXPathText(root);
417
418
419 if (StringUtils.isNotBlank(xPathRuleTarget)) {
420 Matcher ruleTarget = targetPattern.matcher(xPathRuleTarget);
421 if (ruleTarget.find()) {
422 xPathRuleTarget = ruleTarget.group(1);
423 }
424 }
425 return xPathRuleTarget;
426 }
427
428 private List<String> getXPathTerms(Element myTag) {
429
430 Matcher xPathTarget;
431 String firstMatch;
432 List<String> xPathTerms = new ArrayList();
433 String allText = getXPathText(myTag);
434 if (StringUtils.isNotBlank(allText)) {
435 xPathTarget = xPathPattern.matcher(allText);
436 Matcher termTarget;
437 Matcher cleanTarget;
438 int theEnd = 0;
439
440 xPathTarget.find(theEnd);
441 theEnd = xPathTarget.end() - 1;
442 firstMatch = xPathTarget.group();
443
444
445 termTarget = termPattern.matcher(firstMatch);
446 int theEnd2 = 0;
447 while (termTarget.find(theEnd2)) {
448 theEnd2 = termTarget.end() - 1;
449 cleanTarget = cleanPattern.matcher(termTarget.group());
450 cleanTarget.find();
451 lastXPath = cleanTarget.group();
452 xPathTerms.add(lastXPath);
453
454 }
455 }
456 return xPathTerms;
457 }
458
459 private String getLastXPath(Element root) {
460 List<String> tempList = getXPathTerms(root);
461 return tempList.get(tempList.size());
462 }
463 }