1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package edu.sampleu.bookstore.document.attribs;
17
18 import java.io.BufferedReader;
19 import java.io.IOException;
20 import java.io.StringReader;
21 import java.math.BigDecimal;
22 import java.math.BigInteger;
23 import java.text.DateFormat;
24 import java.text.ParseException;
25 import java.text.SimpleDateFormat;
26 import java.util.ArrayList;
27 import java.util.Date;
28 import java.util.List;
29
30 import javax.jws.WebParam;
31 import javax.xml.parsers.DocumentBuilderFactory;
32 import javax.xml.parsers.ParserConfigurationException;
33 import javax.xml.xpath.XPath;
34 import javax.xml.xpath.XPathConstants;
35 import javax.xml.xpath.XPathExpressionException;
36
37 import org.apache.commons.lang.StringUtils;
38 import org.apache.log4j.Logger;
39 import org.kuali.rice.core.api.CoreApiServiceLocator;
40 import org.kuali.rice.core.api.uif.RemotableAttributeError;
41 import org.kuali.rice.core.api.uif.RemotableAttributeField;
42 import org.kuali.rice.core.api.uif.RemotableDatepicker;
43 import org.kuali.rice.kew.api.KewApiConstants;
44 import org.kuali.rice.kew.api.document.DocumentWithContent;
45 import org.kuali.rice.kew.api.document.attribute.DocumentAttribute;
46 import org.kuali.rice.kew.api.document.attribute.DocumentAttributeFactory;
47 import org.kuali.rice.kew.api.document.attribute.WorkflowAttributeDefinition;
48 import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
49 import org.kuali.rice.kew.api.extension.ExtensionDefinition;
50 import org.kuali.rice.kew.docsearch.DocumentSearchInternalUtils;
51 import org.kuali.rice.kew.docsearch.SearchableAttributeValue;
52 import org.kuali.rice.kew.framework.document.attribute.SearchableAttribute;
53 import org.kuali.rice.kew.rule.xmlrouting.XPathHelper;
54 import org.w3c.dom.Element;
55 import org.xml.sax.InputSource;
56 import org.xml.sax.SAXException;
57
58
59
60
61
62
63
64 public abstract class XPathSearchableAttribute implements SearchableAttribute {
65 protected final Logger log;
66 protected final String key;
67 protected final String title;
68 protected final String xpathExpression;
69 protected final String dataType;
70
71 protected XPathSearchableAttribute(String key, String dataType, String xpathExpression) {
72 this(key, dataType, xpathExpression, null);
73 }
74
75 protected XPathSearchableAttribute(String key, String dataType, String xpathExpression, String title) {
76 this.key = key;
77 this.dataType = dataType;
78 this.xpathExpression = xpathExpression;
79 this.log = Logger.getLogger(getClass().getName() + ":" + key);
80 this.title = title == null ? log.getName(): title;
81 }
82
83 @Override
84 public String generateSearchContent(@WebParam(name = "extensionDefinition") ExtensionDefinition extensionDefinition,
85 @WebParam(name = "documentTypeName") String documentTypeName,
86 @WebParam(name = "attributeDefinition") WorkflowAttributeDefinition attributeDefinition) {
87
88 return null;
89 }
90
91 @Override
92 public List<DocumentAttribute> extractDocumentAttributes(@WebParam(name = "extensionDefinition") ExtensionDefinition extensionDefinition,
93 @WebParam(name = "documentWithContent") DocumentWithContent documentWithContent) {
94 List<DocumentAttribute> attribs = new ArrayList<DocumentAttribute>(1);
95 String appContent = documentWithContent.getDocumentContent().getApplicationContent();
96 XPath xpath = XPathHelper.newXPath();
97 try {
98
99 Element source = DocumentBuilderFactory
100 .newInstance().newDocumentBuilder().parse(new InputSource(new BufferedReader(new StringReader(appContent)))).getDocumentElement();
101 String result = (String) xpath.evaluate(xpathExpression, source, XPathConstants.STRING);
102
103 if (StringUtils.isNotEmpty(result)) {
104 try {
105 attribs.add(createAttribute(this.key, result, this.dataType));
106 } catch (ParseException pe) {
107 log.error("Error converting value '" + result + "' to type '" + this.dataType + "'");
108 }
109 }
110 } catch (XPathExpressionException xep) {
111 log.error("Error evaluating searchable attribute expression: '" + this.xpathExpression + "'", xep);
112 } catch (SAXException se) {
113 log.error("Error parsing application content: '" + appContent + "'", se);
114 } catch (ParserConfigurationException pce) {
115 log.error("Error parsing application content: '" + appContent + "'", pce);
116 } catch (IOException ioe) {
117 log.error("Error parsing application content: '" + appContent + "'", ioe);
118 }
119 return attribs;
120 }
121
122
123
124
125 protected static DocumentAttribute createAttribute(String name, String value, String dataTypeValue) throws ParseException {
126 if (StringUtils.isBlank(dataTypeValue)) {
127 return DocumentAttributeFactory.createStringAttribute(name, value);
128 } else if (KewApiConstants.SearchableAttributeConstants.DATA_TYPE_STRING.equals(dataTypeValue)) {
129 return DocumentAttributeFactory.createStringAttribute(name, value);
130 } else if (KewApiConstants.SearchableAttributeConstants.DATA_TYPE_DATE.equals(dataTypeValue)) {
131 try {
132 return DocumentAttributeFactory.createDateTimeAttribute(name, CoreApiServiceLocator.getDateTimeService().convertToDate(value));
133 } catch (ParseException pe) {
134
135 DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
136 dateFormat.setLenient(false);
137 Date date = dateFormat.parse(value);
138 return DocumentAttributeFactory.createDateTimeAttribute(name, date);
139 }
140 } else if (KewApiConstants.SearchableAttributeConstants.DATA_TYPE_LONG.equals(dataTypeValue)) {
141 return DocumentAttributeFactory.createIntegerAttribute(name, new BigInteger(value));
142 } else if (KewApiConstants.SearchableAttributeConstants.DATA_TYPE_FLOAT.equals(dataTypeValue)) {
143 return DocumentAttributeFactory.createDecimalAttribute(name, new BigDecimal(value));
144 }
145 throw new IllegalArgumentException("Invalid dataTypeValue was given: " + dataTypeValue);
146 }
147
148 @Override
149 public List<RemotableAttributeField> getSearchFields(@WebParam(name = "extensionDefinition") ExtensionDefinition extensionDefinition,
150 @WebParam(name = "documentTypeName") String documentTypeName) {
151 List<RemotableAttributeField> fields = new ArrayList<RemotableAttributeField>();
152 RemotableAttributeField.Builder builder = RemotableAttributeField.Builder.create(key);
153 builder.setLongLabel(this.title);
154 builder.setDataType(DocumentSearchInternalUtils.convertValueToDataType(this.dataType));
155 if (KewApiConstants.SearchableAttributeConstants.DATA_TYPE_DATE.equals(this.dataType)) {
156 builder.getWidgets().add(RemotableDatepicker.Builder.create());
157 }
158 builder = decorateRemotableAttributeField(builder);
159 fields.add(builder.build());
160 return fields;
161 }
162
163
164
165
166
167 protected RemotableAttributeField.Builder decorateRemotableAttributeField(RemotableAttributeField.Builder raf) {
168 return raf;
169 }
170
171 @Override
172 public List<RemotableAttributeError> validateDocumentAttributeCriteria(@WebParam(name = "extensionDefinition") ExtensionDefinition extensionDefinition,
173 @WebParam(name = "documentSearchCriteria") DocumentSearchCriteria documentSearchCriteria) {
174 SearchableAttributeValue valueType = DocumentSearchInternalUtils.getSearchableAttributeValueByDataTypeString(this.dataType);
175 return DocumentSearchInternalUtils.validateSearchFieldValues(this.key, valueType, documentSearchCriteria.getDocumentAttributeValues().get(key), log.getName(), null, null);
176 }
177
178 }