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