0001: /*
0002: * Copyright 2005-2006 The Kuali Foundation.
0003: *
0004: *
0005: * Licensed under the Educational Community License, Version 1.0 (the "License");
0006: * you may not use this file except in compliance with the License.
0007: * You may obtain a copy of the License at
0008: *
0009: * http://www.opensource.org/licenses/ecl1.php
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017: package edu.iu.uis.eden.docsearch.xml;
0018:
0019: import java.io.BufferedReader;
0020: import java.io.StringReader;
0021: import java.util.ArrayList;
0022: import java.util.Collection;
0023: import java.util.HashMap;
0024: import java.util.Iterator;
0025: import java.util.List;
0026: import java.util.Map;
0027: import java.util.regex.Matcher;
0028: import java.util.regex.Pattern;
0029:
0030: import javax.xml.parsers.DocumentBuilderFactory;
0031: import javax.xml.xpath.XPath;
0032: import javax.xml.xpath.XPathConstants;
0033: import javax.xml.xpath.XPathExpressionException;
0034:
0035: import org.apache.commons.lang.StringUtils;
0036: import org.w3c.dom.Document;
0037: import org.w3c.dom.Element;
0038: import org.w3c.dom.NamedNodeMap;
0039: import org.w3c.dom.Node;
0040: import org.w3c.dom.NodeList;
0041: import org.xml.sax.InputSource;
0042:
0043: import edu.iu.uis.eden.KEWServiceLocator;
0044: import edu.iu.uis.eden.docsearch.DocSearchUtils;
0045: import edu.iu.uis.eden.docsearch.SearchableAttributeValue;
0046: import edu.iu.uis.eden.exception.EdenUserNotFoundException;
0047: import edu.iu.uis.eden.exception.WorkflowRuntimeException;
0048: import edu.iu.uis.eden.lookupable.Field;
0049: import edu.iu.uis.eden.lookupable.Row;
0050: import edu.iu.uis.eden.routetemplate.RuleAttribute;
0051: import edu.iu.uis.eden.routetemplate.WorkflowAttributeValidationError;
0052: import edu.iu.uis.eden.routetemplate.xmlrouting.XPathHelper;
0053: import edu.iu.uis.eden.util.KeyLabelPair;
0054: import edu.iu.uis.eden.util.Utilities;
0055: import edu.iu.uis.eden.util.XmlHelper;
0056: import edu.iu.uis.eden.web.session.UserSession;
0057: import edu.iu.uis.eden.workgroup.GroupNameId;
0058:
0059: /**
0060: * implementation of {@link GenericXMLSearchableAttribute}.
0061: *
0062: * @author jhopf
0063: * @author rkirkend
0064: */
0065: public class StandardGenericXMLSearchableAttribute implements
0066: GenericXMLSearchableAttribute {
0067: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
0068: .getLogger(StandardGenericXMLSearchableAttribute.class);
0069:
0070: private static final String FIELD_DEF_E = "fieldDef";
0071:
0072: private Map paramMap = new HashMap();
0073: private RuleAttribute ruleAttribute;
0074: private List searchRows = new ArrayList();
0075:
0076: public void setRuleAttribute(RuleAttribute ruleAttribute) {
0077: this .ruleAttribute = ruleAttribute;
0078: }
0079:
0080: public void setParamMap(Map paramMap) {
0081: this .paramMap = paramMap;
0082: }
0083:
0084: public Map getParamMap() {
0085: return paramMap;
0086: }
0087:
0088: public String getSearchContent() {
0089: XPath xpath = XPathHelper.newXPath();
0090: String findDocContent = "//searchingConfig/xmlSearchContent";
0091: try {
0092: Node xmlDocumentContent = (Node) xpath
0093: .evaluate(findDocContent, getConfigXML(),
0094: XPathConstants.NODE);
0095: if (xmlDocumentContent != null
0096: && xmlDocumentContent.hasChildNodes()) {
0097: // Custom doc content in the searchingConfig xml.
0098: String docContent = "";
0099: NodeList customNodes = xmlDocumentContent
0100: .getChildNodes();
0101: for (int i = 0; i < customNodes.getLength(); i++) {
0102: Node childNode = customNodes.item(i);
0103: docContent += XmlHelper.writeNode(childNode);
0104: }
0105: String findField = "//searchingConfig/" + FIELD_DEF_E;
0106: NodeList nodes = (NodeList) xpath.evaluate(findField,
0107: getConfigXML(), XPathConstants.NODESET);
0108: if (nodes == null || nodes.getLength() == 0) {
0109: return "";
0110: }
0111: for (int i = 0; i < nodes.getLength(); i++) {
0112: Node field = nodes.item(i);
0113: NamedNodeMap fieldAttributes = field
0114: .getAttributes();
0115: if (getParamMap() != null
0116: && !Utilities
0117: .isEmpty((String) getParamMap()
0118: .get(
0119: fieldAttributes
0120: .getNamedItem(
0121: "name")
0122: .getNodeValue()))) {
0123: docContent = docContent
0124: .replaceAll(
0125: "%"
0126: + fieldAttributes
0127: .getNamedItem(
0128: "name")
0129: .getNodeValue()
0130: + "%",
0131: (String) getParamMap()
0132: .get(
0133: fieldAttributes
0134: .getNamedItem(
0135: "name")
0136: .getNodeValue()));
0137: }
0138: }
0139: return docContent;
0140: } else {
0141: // Standard doc content if no doc content is found in the searchingConfig xml.
0142: StringBuffer documentContent = new StringBuffer(
0143: "<xmlRouting>");
0144: String findField = "//searchingConfig/" + FIELD_DEF_E;
0145: NodeList nodes = (NodeList) xpath.evaluate(findField,
0146: getConfigXML(), XPathConstants.NODESET);
0147: if (nodes == null || nodes.getLength() == 0) {
0148: return "";
0149: }
0150: for (int i = 0; i < nodes.getLength(); i++) {
0151: Node field = nodes.item(i);
0152: NamedNodeMap fieldAttributes = field
0153: .getAttributes();
0154: if (getParamMap() != null
0155: && !Utilities
0156: .isEmpty((String) getParamMap()
0157: .get(
0158: fieldAttributes
0159: .getNamedItem(
0160: "name")
0161: .getNodeValue()))) {
0162: documentContent.append("<field name=\"");
0163: documentContent.append(fieldAttributes
0164: .getNamedItem("name").getNodeValue());
0165: documentContent.append("\"><value>");
0166: documentContent
0167: .append((String) getParamMap().get(
0168: fieldAttributes.getNamedItem(
0169: "name").getNodeValue()));
0170: documentContent.append("</value></field>");
0171: }
0172: }
0173: documentContent.append("</xmlRouting>");
0174: return documentContent.toString();
0175: }
0176: } catch (XPathExpressionException e) {
0177: LOG.error("error in getSearchContent ", e);
0178: throw new RuntimeException(
0179: "Error trying to find xml content with xpath expression",
0180: e);
0181: } catch (Exception e) {
0182: LOG
0183: .error(
0184: "error in getSearchContent attempting to find xml search content",
0185: e);
0186: throw new RuntimeException(
0187: "Error trying to get xml search content.", e);
0188: }
0189: }
0190:
0191: public List getSearchStorageValues(String docContent) {
0192: List searchStorageValues = new ArrayList();
0193: Document document;
0194: if (StringUtils.isBlank(docContent)) {
0195: LOG.warn("Empty Document Content found '" + docContent
0196: + "'");
0197: return searchStorageValues;
0198: }
0199: try {
0200: document = DocumentBuilderFactory.newInstance()
0201: .newDocumentBuilder().parse(
0202: new InputSource(new BufferedReader(
0203: new StringReader(docContent))));
0204: } catch (Exception e) {
0205: LOG.error("error parsing docContent: " + docContent, e);
0206: throw new RuntimeException(
0207: "Error trying to parse docContent: " + docContent,
0208: e);
0209: }
0210: XPath xpath = XPathHelper.newXPath(document);
0211: String findField = "//searchingConfig/" + FIELD_DEF_E;
0212: try {
0213: NodeList nodes = (NodeList) xpath.evaluate(findField,
0214: getConfigXML(), XPathConstants.NODESET);
0215: if (nodes == null) {
0216: LOG
0217: .error("Could not find searching configuration (<searchingConfig>) for this XMLSearchAttribute");
0218: } else {
0219:
0220: for (int i = 0; i < nodes.getLength(); i++) {
0221: Node field = nodes.item(i);
0222: NamedNodeMap fieldAttributes = field
0223: .getAttributes();
0224:
0225: String findXpathExpressionPrefix = "//searchingConfig/"
0226: + FIELD_DEF_E
0227: + "[@name='"
0228: + fieldAttributes.getNamedItem("name")
0229: .getNodeValue() + "']";
0230: String findDataTypeXpathExpression = findXpathExpressionPrefix
0231: + "/searchDefinition/@dataType";
0232: String findXpathExpression = findXpathExpressionPrefix
0233: + "/fieldEvaluation/xpathexpression";
0234: String fieldDataType = null;
0235: String xpathExpression = null;
0236: try {
0237: fieldDataType = (String) xpath.evaluate(
0238: findDataTypeXpathExpression,
0239: getConfigXML(), XPathConstants.STRING);
0240: if (Utilities.isEmpty(fieldDataType)) {
0241: fieldDataType = DEFAULT_SEARCHABLE_ATTRIBUTE_TYPE_NAME;
0242: }
0243: xpathExpression = (String) xpath.evaluate(
0244: findXpathExpression, getConfigXML(),
0245: XPathConstants.STRING);
0246: if (!Utilities.isEmpty(xpathExpression)) {
0247:
0248: try {
0249: NodeList searchValues = (NodeList) xpath
0250: .evaluate(
0251: xpathExpression,
0252: document
0253: .getDocumentElement(),
0254: XPathConstants.NODESET);
0255: //being that this is the standard xml attribute we will return the key with an empty value
0256: // so we can find it from a doc search using this key
0257: if (searchValues.getLength() == 0) {
0258: SearchableAttributeValue searchableValue = this
0259: .setupSearchableAttributeValue(
0260: fieldDataType,
0261: fieldAttributes
0262: .getNamedItem(
0263: "name")
0264: .getNodeValue(),
0265: null);
0266: if (searchableValue != null) {
0267: searchStorageValues
0268: .add(searchableValue);
0269: }
0270: } else {
0271: for (int j = 0; j < searchValues
0272: .getLength(); j++) {
0273: Node searchValue = searchValues
0274: .item(j);
0275: String value = null;
0276: if (searchValue.getFirstChild() != null
0277: && (!StringUtils
0278: .isEmpty(searchValue
0279: .getFirstChild()
0280: .getNodeValue()))) {
0281: value = searchValue
0282: .getFirstChild()
0283: .getNodeValue();
0284: }
0285: SearchableAttributeValue searchableValue = this
0286: .setupSearchableAttributeValue(
0287: fieldDataType,
0288: fieldAttributes
0289: .getNamedItem(
0290: "name")
0291: .getNodeValue(),
0292: value);
0293: if (searchableValue != null) {
0294: searchStorageValues
0295: .add(searchableValue);
0296: }
0297: }
0298: }
0299: } catch (XPathExpressionException e) {
0300: //try for a string being returned from the expression. This
0301: //seems like a poor way to determine our expression return type but
0302: //it's all I can come up with at the moment.
0303: String searchValue = (String) xpath
0304: .evaluate(
0305: xpathExpression,
0306: DocumentBuilderFactory
0307: .newInstance()
0308: .newDocumentBuilder()
0309: .parse(
0310: new InputSource(
0311: new BufferedReader(
0312: new StringReader(
0313: docContent))))
0314: .getDocumentElement(),
0315: XPathConstants.STRING);
0316: String value = null;
0317: if (StringUtils.isNotBlank(searchValue)) {
0318: value = searchValue;
0319: }
0320: SearchableAttributeValue searchableValue = this
0321: .setupSearchableAttributeValue(
0322: fieldDataType,
0323: fieldAttributes
0324: .getNamedItem(
0325: "name")
0326: .getNodeValue(),
0327: value);
0328: if (searchableValue != null) {
0329: searchStorageValues
0330: .add(searchableValue);
0331: }
0332: }
0333: }
0334: } catch (XPathExpressionException e) {
0335: LOG.error("error in isMatch ", e);
0336: throw new RuntimeException(
0337: "Error trying to find xml content with xpath expressions: "
0338: + findXpathExpression + " or "
0339: + xpathExpression, e);
0340: } catch (Exception e) {
0341: LOG.error("error parsing docContent: "
0342: + docContent, e);
0343: throw new RuntimeException(
0344: "Error trying to parse docContent: "
0345: + docContent, e);
0346: }
0347: }
0348: }
0349: } catch (XPathExpressionException e) {
0350: LOG.error("error in getSearchStorageValues ", e);
0351: throw new RuntimeException(
0352: "Error trying to find xml content with xpath expression: "
0353: + findField, e);
0354: }
0355: return searchStorageValues;
0356: }
0357:
0358: private SearchableAttributeValue setupSearchableAttributeValue(
0359: String dataType, String key, String value) {
0360: SearchableAttributeValue attValue = DocSearchUtils
0361: .getSearchableAttributeValueByDataTypeString(dataType);
0362: if (attValue == null) {
0363: String errorMsg = "Cannot find a SearchableAttributeValue associated with the data type '"
0364: + dataType + "'";
0365: LOG.error("setupSearchableAttributeValue() " + errorMsg);
0366: throw new RuntimeException(errorMsg);
0367: }
0368: // TODO delyea - should we be saving null values??
0369: value = (value != null) ? value.trim() : null;
0370: // TODO delyea - should we use differing validation for UI vs Data Saving here?
0371: if ((StringUtils.isNotBlank(value))
0372: && (!attValue.isPassesDefaultValidation(value))) {
0373: String errorMsg = "SearchableAttributeValue with the data type '"
0374: + dataType
0375: + "', key '"
0376: + key
0377: + "', and value '"
0378: + value
0379: + "' does not pass default validation and cannot be saved to the database";
0380: LOG.error("setupSearchableAttributeValue() " + errorMsg);
0381: throw new RuntimeException(errorMsg);
0382: }
0383: attValue.setSearchableAttributeKey(key);
0384: attValue.setupAttributeValue(value);
0385: return attValue;
0386: }
0387:
0388: public List getSearchingRows() {
0389: if (searchRows.isEmpty()) {
0390: List searchableAttributeValues = DocSearchUtils
0391: .getSearchableAttributeValueObjectTypes();
0392: List rows = new ArrayList();
0393: NodeList fieldNodeList = getConfigXML()
0394: .getElementsByTagName(FIELD_DEF_E);
0395: for (int i = 0; i < fieldNodeList.getLength(); i++) {
0396: Node field = fieldNodeList.item(i);
0397: NamedNodeMap fieldAttributes = field.getAttributes();
0398:
0399: List fields = new ArrayList();
0400: boolean isColumnVisible = true;
0401: boolean hasXPathExpression = false;
0402: Field myField = new Field(fieldAttributes.getNamedItem(
0403: "title").getNodeValue(), "", "", false,
0404: fieldAttributes.getNamedItem("name")
0405: .getNodeValue(), "", null, "");
0406: String quickfinderService = null;
0407: // range search details
0408: Field rangeLowerBoundField = null;
0409: Field rangeUpperBoundField = null;
0410: for (int j = 0; j < field.getChildNodes().getLength(); j++) {
0411: Node childNode = field.getChildNodes().item(j);
0412: if ("value".equals(childNode.getNodeName())) {
0413: myField.setPropertyValue(childNode
0414: .getFirstChild().getNodeValue());
0415: } else if ("display"
0416: .equals(childNode.getNodeName())) {
0417: List options = new ArrayList();
0418: List selectedOptions = new ArrayList();
0419: for (int k = 0; k < childNode.getChildNodes()
0420: .getLength(); k++) {
0421: Node displayChildNode = childNode
0422: .getChildNodes().item(k);
0423: if ("type".equals(displayChildNode
0424: .getNodeName())) {
0425: String typeValue = displayChildNode
0426: .getFirstChild().getNodeValue();
0427: myField
0428: .setFieldType(convertTypeToFieldType(typeValue));
0429: if ("date".equals(typeValue)) {
0430: myField
0431: .setHasDatePicker(Boolean.TRUE);
0432: myField
0433: .setFieldDataType(DATA_TYPE_DATE);
0434: }
0435: } else if ("meta".equals(displayChildNode
0436: .getNodeName())) {
0437:
0438: } else if ("values".equals(displayChildNode
0439: .getNodeName())) {
0440: NamedNodeMap valuesAttributes = displayChildNode
0441: .getAttributes();
0442: // this is to allow an empty drop down choice and can probably implemented in a better way
0443: if (displayChildNode.getFirstChild() != null) {
0444: options.add(new KeyLabelPair(
0445: displayChildNode
0446: .getFirstChild()
0447: .getNodeValue(),
0448: valuesAttributes
0449: .getNamedItem(
0450: "title")
0451: .getNodeValue()));
0452: if (valuesAttributes
0453: .getNamedItem("selected") != null) {
0454: selectedOptions
0455: .add(displayChildNode
0456: .getFirstChild()
0457: .getNodeValue());
0458: }
0459: } else {
0460: options.add(new KeyLabelPair("",
0461: valuesAttributes
0462: .getNamedItem(
0463: "title")
0464: .getNodeValue()));
0465: }
0466: } else if ("parameters"
0467: .equals(displayChildNode
0468: .getNodeName())) {
0469: NamedNodeMap parametersAttributes = displayChildNode
0470: .getAttributes();
0471: myField.addDisplayParameter(
0472: parametersAttributes
0473: .getNamedItem("name")
0474: .getNodeValue(),
0475: displayChildNode
0476: .getFirstChild()
0477: .getNodeValue());
0478: }
0479: }
0480: if (!options.isEmpty()) {
0481: myField.setFieldValidValues(options);
0482: if (!selectedOptions.isEmpty()) {
0483: if (Field.MULTI_VALUE_FIELD_TYPES
0484: .contains(myField
0485: .getFieldType())) {
0486: String[] newSelectedOptions = new String[selectedOptions
0487: .size()];
0488: int k = 0;
0489: for (Iterator iter = selectedOptions
0490: .iterator(); iter.hasNext();) {
0491: String option = (String) iter
0492: .next();
0493: newSelectedOptions[k] = option;
0494: k++;
0495: }
0496: myField
0497: .setPropertyValues(newSelectedOptions);
0498: } else {
0499: myField
0500: .setPropertyValue((String) selectedOptions
0501: .get(0));
0502: }
0503: }
0504: }
0505: } else if ("visibility".equals(childNode
0506: .getNodeName())) {
0507: parseVisibility(myField, (Element) childNode);
0508: } else if ("searchDefinition".equals(childNode
0509: .getNodeName())) {
0510: NamedNodeMap searchDefAttributes = childNode
0511: .getAttributes();
0512: // data type operations
0513: String dataType = (searchDefAttributes
0514: .getNamedItem("dataType") == null) ? null
0515: : searchDefAttributes.getNamedItem(
0516: "dataType").getNodeValue();
0517: if (!Utilities.isEmpty(dataType)) {
0518: myField.setFieldDataType(dataType);
0519: } else {
0520: // no data type means we default to String which disallows range search
0521: myField
0522: .setFieldDataType(DEFAULT_SEARCHABLE_ATTRIBUTE_TYPE_NAME);
0523: }
0524: if (DATA_TYPE_DATE.equalsIgnoreCase(myField
0525: .getFieldDataType())) {
0526: myField.setHasDatePicker(Boolean.TRUE);
0527: }
0528:
0529: // figure out if this is a range search
0530: myField.setMemberOfRange(isRangeSearchField(
0531: searchableAttributeValues, myField
0532: .getFieldDataType(),
0533: searchDefAttributes, childNode));
0534: if (!myField.isMemberOfRange()) {
0535: // either we don't allow a range search... or the range search doesn't exist in the xml
0536: myField.setAllowWildcards(getBooleanValue(
0537: searchDefAttributes,
0538: "allowWildcards"));
0539: myField.setCaseSensitive(getBooleanValue(
0540: searchDefAttributes,
0541: "caseSensitive"));
0542: String autoWildcardAttributeValue = (searchDefAttributes
0543: .getNamedItem("autoWildcardLocation") == null) ? null
0544: : searchDefAttributes.getNamedItem(
0545: "autoWildcardLocation")
0546: .getNodeValue();
0547: setupAutoWildcardPolicy(myField,
0548: autoWildcardAttributeValue);
0549: } else {
0550: // by now we know we have a range that uses the default values at least
0551: // these will be
0552: rangeLowerBoundField = new Field(
0553: DEFAULT_RANGE_SEARCH_LOWER_BOUND_LABEL,
0554: "", "", false, "", "", null, "");
0555: rangeLowerBoundField.setMemberOfRange(true);
0556: rangeUpperBoundField = new Field(
0557: DEFAULT_RANGE_SEARCH_UPPER_BOUND_LABEL,
0558: "", "", false, "", "", null, "");
0559: rangeUpperBoundField.setMemberOfRange(true);
0560: setupBoundFields(childNode,
0561: rangeLowerBoundField,
0562: rangeUpperBoundField);
0563: }
0564: } else if ("resultColumn".equals(childNode
0565: .getNodeName())) {
0566: NamedNodeMap columnAttributes = childNode
0567: .getAttributes();
0568: Node showNode = columnAttributes
0569: .getNamedItem("show");
0570: if (showNode != null
0571: && showNode.getNodeValue() != null) {
0572: isColumnVisible = Boolean.valueOf(
0573: showNode.getNodeValue())
0574: .booleanValue();
0575: }
0576: myField.setColumnVisible(isColumnVisible);
0577: } else if ("fieldEvaluation".equals(childNode
0578: .getNodeName())) {
0579: for (int k = 0; k < childNode.getChildNodes()
0580: .getLength(); k++) {
0581: Node displayChildNode = childNode
0582: .getChildNodes().item(k);
0583: if ("xpathexpression"
0584: .equals(displayChildNode
0585: .getNodeName())) {
0586: hasXPathExpression = true;
0587: break;
0588: }
0589: }
0590: } else if ("quickfinder".equals(childNode
0591: .getNodeName())) {
0592: NamedNodeMap quickfinderAttributes = childNode
0593: .getAttributes();
0594: String drawQuickfinder = quickfinderAttributes
0595: .getNamedItem("draw").getNodeValue();
0596: if (!Utilities.isEmpty(drawQuickfinder)
0597: && "true".equals(drawQuickfinder)) {
0598: quickfinderService = quickfinderAttributes
0599: .getNamedItem("service")
0600: .getNodeValue();
0601: }
0602: myField
0603: .setQuickFinderClassNameImpl(quickfinderAttributes
0604: .getNamedItem("service")
0605: .getNodeValue());
0606: myField.setHasLookupable(true);
0607: myField
0608: .setDefaultLookupableName(quickfinderAttributes
0609: .getNamedItem("appliesTo")
0610: .getNodeValue());
0611: }
0612: }
0613: myField.setSearchable(hasXPathExpression);
0614:
0615: if (myField.isMemberOfRange()) {
0616: // we have a ranged search... we need to add the bound fields and NOT the myField object
0617: addRangeFields(RANGE_LOWER_BOUND_PROPERTY_PREFIX,
0618: rangeLowerBoundField, myField, rows,
0619: quickfinderService);
0620: addRangeFields(RANGE_UPPER_BOUND_PROPERTY_PREFIX,
0621: rangeUpperBoundField, myField, rows,
0622: quickfinderService);
0623: } else {
0624: fields.add(myField);
0625: if (!myField.getFieldType().equals(Field.HIDDEN)) {
0626: if (!Utilities.isEmpty(quickfinderService)) {
0627: fields.add(new Field("", "",
0628: Field.QUICKFINDER, false, "", "",
0629: null, quickfinderService));
0630: }
0631: if (myField.isUsingDatePicker()) {
0632: addDatePickerField(fields, myField
0633: .getPropertyName());
0634: }
0635: }
0636: rows.add(new Row(fields));
0637: }
0638: }
0639: searchRows = rows;
0640: }
0641: return searchRows;
0642: }
0643:
0644: private boolean isRangeSearchField(List searchableAttributeValues,
0645: String dataType, NamedNodeMap searchDefAttributes,
0646: Node searchDefNode) {
0647: for (Iterator iter = searchableAttributeValues.iterator(); iter
0648: .hasNext();) {
0649: SearchableAttributeValue attValue = (SearchableAttributeValue) iter
0650: .next();
0651: if (dataType.equalsIgnoreCase(attValue
0652: .getAttributeDataType())) {
0653: return isRangeSearchField(attValue, dataType,
0654: searchDefAttributes, searchDefNode);
0655: }
0656: }
0657: String errorMsg = "Could not find searchable attribute value for data type '"
0658: + dataType + "'";
0659: LOG
0660: .error("isRangeSearchField(List, String, NamedNodeMap, Node) "
0661: + errorMsg);
0662: throw new RuntimeException(errorMsg);
0663: }
0664:
0665: private boolean isRangeSearchField(
0666: SearchableAttributeValue searchableAttributeValue,
0667: String dataType, NamedNodeMap searchDefAttributes,
0668: Node searchDefNode) {
0669: boolean allowRangedSearch = searchableAttributeValue
0670: .allowsRangeSearches();
0671: Boolean rangeSearchBoolean = getBooleanValue(
0672: searchDefAttributes, "rangeSearch");
0673: boolean rangeSearch = (rangeSearchBoolean != null) ? rangeSearchBoolean
0674: .booleanValue()
0675: : false;
0676: Node rangeDefinition = searchDefNode.getFirstChild();
0677: return ((allowRangedSearch) && ((rangeDefinition != null) || (rangeSearch)));
0678: }
0679:
0680: private void setupBoundFields(Node searchDefinitionNode,
0681: Field lowerBoundField, Field upperBoundField) {
0682: NamedNodeMap searchDefAttributes = searchDefinitionNode
0683: .getAttributes();
0684: Node rangeDefinitionNode = getPotentialChildNode(
0685: searchDefinitionNode, "rangeDefinition");
0686: NamedNodeMap rangeDefinitionAttributes = null;
0687: NamedNodeMap lowerBoundNodeAttributes = null;
0688: NamedNodeMap upperBoundNodeAttributes = null;
0689: if (rangeDefinitionNode != null) {
0690: rangeDefinitionAttributes = rangeDefinitionNode
0691: .getAttributes();
0692: lowerBoundNodeAttributes = getAttributesForPotentialChildNode(
0693: rangeDefinitionNode, "lower");
0694: upperBoundNodeAttributes = getAttributesForPotentialChildNode(
0695: rangeDefinitionNode, "upper");
0696: }
0697: // below methods allow for nullable attribute NamedNodeMaps
0698: setupRangeBoundFieldOverridableSettings(searchDefAttributes,
0699: rangeDefinitionAttributes, lowerBoundNodeAttributes,
0700: lowerBoundField);
0701: setupRangeBoundFieldOverridableSettings(searchDefAttributes,
0702: rangeDefinitionAttributes, upperBoundNodeAttributes,
0703: upperBoundField);
0704: }
0705:
0706: private void addRangeFields(String propertyPrefix,
0707: Field rangeBoundField, Field mainField, List rows,
0708: String quickfinderService) {
0709: List rangeFields = new ArrayList();
0710: rangeBoundField.populateFieldFromExistingField(mainField);
0711: rangeBoundField.setPropertyName(propertyPrefix
0712: + mainField.getPropertyName());
0713: rangeFields.add(rangeBoundField);
0714: if (!mainField.getFieldType().equals(Field.HIDDEN)) {
0715: if (!Utilities.isEmpty(quickfinderService)) {
0716: rangeFields.add(new Field("", "", Field.QUICKFINDER,
0717: false, "", "", null, quickfinderService));
0718: }
0719: if (rangeBoundField.getHasDatePicker() != null) {
0720: // variable was set on the bound field
0721: if (rangeBoundField.isUsingDatePicker()) {
0722: addDatePickerField(rangeFields, rangeBoundField
0723: .getPropertyName());
0724: }
0725: } else {
0726: if (mainField.isUsingDatePicker()) {
0727: addDatePickerField(rangeFields, rangeBoundField
0728: .getPropertyName());
0729: }
0730: }
0731: }
0732: rows.add(new Row(rangeFields, mainField.getFieldLabel(), 2));
0733: }
0734:
0735: private void addDatePickerField(List fields, String propertyName) {
0736: fields.add(new Field("", "", Field.DATEPICKER, false,
0737: propertyName + "_datepicker", "", null, ""));
0738: }
0739:
0740: private NamedNodeMap getAttributesForPotentialChildNode(Node node,
0741: String potentialChildNodeName) {
0742: Node testNode = getPotentialChildNode(node,
0743: potentialChildNodeName);
0744: return (testNode != null) ? testNode.getAttributes() : null;
0745: }
0746:
0747: private Node getPotentialChildNode(Node node, String childNodeName) {
0748: if (node != null) {
0749: for (int k = 0; k < node.getChildNodes().getLength(); k++) {
0750: Node testNode = node.getChildNodes().item(k);
0751: if (testNode.getNodeName().equals(childNodeName)) {
0752: return testNode;
0753: }
0754: }
0755: }
0756: return null;
0757: }
0758:
0759: private void setupRangeBoundFieldOverridableSettings(
0760: NamedNodeMap searchDefinitionAttributes,
0761: NamedNodeMap rangeDefinitionAttributes,
0762: NamedNodeMap rangeBoundAttributes, Field boundField) {
0763: String potentialLabel = getPotentialRangeBoundLabelFromAttributes(rangeBoundAttributes);
0764: if (StringUtils.isNotBlank(potentialLabel)) {
0765: boundField.setFieldLabel(potentialLabel);
0766: }
0767: ArrayList<NamedNodeMap> namedNodeMapsByImportance = new ArrayList<NamedNodeMap>();
0768: namedNodeMapsByImportance.add(rangeBoundAttributes);
0769: namedNodeMapsByImportance.add(rangeDefinitionAttributes);
0770: namedNodeMapsByImportance.add(searchDefinitionAttributes);
0771: boundField.setAllowWildcards(getBooleanWithPotentialOverrides(
0772: namedNodeMapsByImportance, "allowWildcards"));
0773: boundField.setCaseSensitive(getBooleanWithPotentialOverrides(
0774: namedNodeMapsByImportance, "caseSensitive"));
0775: boundField.setHasDatePicker(getBooleanWithPotentialOverrides(
0776: namedNodeMapsByImportance, "datePicker"));
0777: boundField
0778: .setRangeFieldInclusive(getBooleanWithPotentialOverrides(
0779: namedNodeMapsByImportance, "inclusive"));
0780:
0781: String autoWildcardValueToUse = null;
0782: for (int i = 0; i < namedNodeMapsByImportance.size(); i++) {
0783: NamedNodeMap nodeMap = (NamedNodeMap) namedNodeMapsByImportance
0784: .get(i);
0785: String attributeValue = getStringValue(nodeMap,
0786: "autoWildcardLocation");
0787: if (attributeValue != null) {
0788: autoWildcardValueToUse = attributeValue;
0789: break;
0790: }
0791: }
0792: setupAutoWildcardPolicy(boundField, autoWildcardValueToUse);
0793: }
0794:
0795: private String getPotentialRangeBoundLabelFromAttributes(
0796: NamedNodeMap rangeBoundAttributes) {
0797: if (rangeBoundAttributes != null) {
0798: String boundLabel = (rangeBoundAttributes
0799: .getNamedItem("label") == null) ? null
0800: : rangeBoundAttributes.getNamedItem("label")
0801: .getNodeValue();
0802: if (!Utilities.isEmpty(boundLabel)) {
0803: return boundLabel;
0804: }
0805: }
0806: return null;
0807: }
0808:
0809: private Boolean getBooleanWithPotentialOverrides(
0810: String attributeName,
0811: NamedNodeMap searchDefinitionAttributes,
0812: NamedNodeMap rangeDefinitionAttributes,
0813: NamedNodeMap rangeBoundAttributes) {
0814: ArrayList<NamedNodeMap> namedNodeMapsByImportance = new ArrayList<NamedNodeMap>();
0815: namedNodeMapsByImportance.add(rangeBoundAttributes);
0816: namedNodeMapsByImportance.add(rangeDefinitionAttributes);
0817: namedNodeMapsByImportance.add(searchDefinitionAttributes);
0818: return getBooleanWithPotentialOverrides(
0819: namedNodeMapsByImportance, attributeName);
0820: }
0821:
0822: private Boolean getBooleanWithPotentialOverrides(
0823: ArrayList<NamedNodeMap> namedNodeMapsByImportance,
0824: String attributeName) {
0825: for (int i = 0; i < namedNodeMapsByImportance.size(); i++) {
0826: NamedNodeMap nodeMap = (NamedNodeMap) namedNodeMapsByImportance
0827: .get(i);
0828: Boolean booleanValue = getBooleanValue(nodeMap,
0829: attributeName);
0830: if (booleanValue != null) {
0831: return booleanValue;
0832: }
0833: }
0834: return null;
0835: }
0836:
0837: private void setupAutoWildcardPolicy(Field field,
0838: String attributeValue) {
0839: if (attributeValue == null) {
0840: return;
0841: }
0842: if (attributeValue.trim().equalsIgnoreCase("prefixonly")) {
0843: field.setAutoWildcardBeginning(Boolean.TRUE);
0844: field.setAutoWildcardEnding(Boolean.FALSE);
0845: return;
0846: } else if (attributeValue.trim().equalsIgnoreCase("suffixonly")) {
0847: field.setAutoWildcardBeginning(Boolean.FALSE);
0848: field.setAutoWildcardEnding(Boolean.TRUE);
0849: return;
0850: } else if (attributeValue.trim().equalsIgnoreCase("bothsides")) {
0851: field.setAutoWildcardBeginning(Boolean.TRUE);
0852: field.setAutoWildcardEnding(Boolean.TRUE);
0853: return;
0854: } else if (attributeValue.trim().equalsIgnoreCase("none")) {
0855: field.setAutoWildcardBeginning(Boolean.FALSE);
0856: field.setAutoWildcardEnding(Boolean.FALSE);
0857: return;
0858: }
0859: throw new IllegalArgumentException(
0860: "Illegal auto wildcard value being used: "
0861: + attributeValue.trim());
0862: }
0863:
0864: private Boolean getBooleanValue(NamedNodeMap nodeMap,
0865: String attributeName) {
0866: String nodeValue = getStringValue(nodeMap, attributeName);
0867: if (nodeValue != null) {
0868: return Boolean.valueOf(nodeValue);
0869: }
0870: return null;
0871: }
0872:
0873: private String getStringValue(NamedNodeMap nodeMap,
0874: String attributeName) {
0875: return ((nodeMap == null)
0876: || (nodeMap.getNamedItem(attributeName) == null) || (Utilities
0877: .isEmpty(nodeMap.getNamedItem(attributeName)
0878: .getNodeValue()))) ? null : nodeMap
0879: .getNamedItem(attributeName).getNodeValue();
0880: }
0881:
0882: private void parseVisibility(Field field, Element visibilityElement) {
0883: for (int vIndex = 0; vIndex < visibilityElement.getChildNodes()
0884: .getLength(); vIndex++) {
0885: Node visibilityChildNode = visibilityElement
0886: .getChildNodes().item(vIndex);
0887: if (visibilityChildNode.getNodeType() == Node.ELEMENT_NODE) {
0888: boolean visible = true;
0889: NamedNodeMap visibilityAttributes = visibilityChildNode
0890: .getAttributes();
0891: Node visibleNode = visibilityAttributes
0892: .getNamedItem("visible");
0893: if (visibleNode != null
0894: && visibleNode.getNodeValue() != null) {
0895: visible = Boolean.valueOf(
0896: visibleNode.getNodeValue()).booleanValue();
0897: } else {
0898: NodeList visibilityDecls = visibilityChildNode
0899: .getChildNodes();
0900: for (int vdIndex = 0; vdIndex < visibilityDecls
0901: .getLength(); vdIndex++) {
0902: Node visibilityDecl = visibilityDecls
0903: .item(vdIndex);
0904: if (visibilityDecl.getNodeType() == Node.ELEMENT_NODE) {
0905: if ("isMemberOfWorkgroup"
0906: .equals(visibilityDecl
0907: .getNodeName())) {
0908: String workgroupName = visibilityDecl
0909: .getFirstChild().getNodeValue();
0910: UserSession session = UserSession
0911: .getAuthenticatedUser();
0912: if (session == null) {
0913: throw new WorkflowRuntimeException(
0914: "UserSession is null! Attempted to render the searchable attribute outside of an established session.");
0915: }
0916: GroupNameId groupId = new GroupNameId(
0917: workgroupName);
0918: try {
0919: visible = KEWServiceLocator
0920: .getWorkgroupService()
0921: .isUserMemberOfGroup(
0922: groupId,
0923: session
0924: .getWorkflowUser());
0925: } catch (EdenUserNotFoundException e) {
0926: throw new RuntimeException(
0927: "Error checking for workgroup membership permissions for workgroup '"
0928: + workgroupName
0929: + "'. Error Message: "
0930: + e.getMessage(), e);
0931: }
0932: }
0933: }
0934: }
0935: }
0936: String type = visibilityChildNode.getNodeName();
0937: if ("field".equals(type)
0938: || "fieldAndColumn".equals(type)) {
0939: // if it's not visible, coerce this field to a hidden type
0940: if (!visible) {
0941: field.setFieldType(Field.HIDDEN);
0942: }
0943: }
0944: if ("column".equals(type)
0945: || "fieldAndColumn".equals(type)) {
0946: field.setColumnVisible(visible);
0947: }
0948: }
0949:
0950: }
0951: }
0952:
0953: private String convertTypeToFieldType(String type) {
0954: if ("text".equals(type)) {
0955: return Field.TEXT;
0956: } else if ("select".equals(type)) {
0957: return Field.DROPDOWN;
0958: } else if ("radio".equals(type)) {
0959: return Field.RADIO;
0960: } else if ("quickfinder".equals(type)) {
0961: return Field.QUICKFINDER;
0962: } else if ("hidden".equals(type)) {
0963: return Field.HIDDEN;
0964: } else if ("date".equals(type)) {
0965: return Field.TEXT;
0966: } else if ("multibox".equals(type)) {
0967: return Field.MULTIBOX;
0968: } else if ("checkbox_indicator".equals(type)) {
0969: return Field.CHECKBOX_YES_NO;
0970: } else if ("checkbox_present".equals(type)) {
0971: return Field.CHECKBOX_PRESENT;
0972: }
0973: throw new IllegalArgumentException("Illegal field type found: "
0974: + type);
0975: }
0976:
0977: public List validateUserSearchInputs(Map paramMap) {
0978: this .paramMap = paramMap;
0979: List errors = new ArrayList();
0980:
0981: XPath xpath = XPathHelper.newXPath();
0982: String findField = "//searchingConfig/" + FIELD_DEF_E;
0983: try {
0984: NodeList nodes = (NodeList) xpath.evaluate(findField,
0985: getConfigXML(), XPathConstants.NODESET);
0986: if (nodes == null) {
0987: // no field definitions is de facto valid
0988: LOG
0989: .warn("Could not find any field definitions (<"
0990: + FIELD_DEF_E
0991: + ">) or possibly a searching configuration (<searchingConfig>) for this XMLSearchAttribute");
0992: } else {
0993: for (int i = 0; i < nodes.getLength(); i++) {
0994: Node field = nodes.item(i);
0995: NamedNodeMap fieldAttributes = field
0996: .getAttributes();
0997: String fieldDefName = fieldAttributes.getNamedItem(
0998: "name").getNodeValue();
0999: String fieldDefTitle = ((fieldAttributes
1000: .getNamedItem("title")) != null) ? fieldAttributes
1001: .getNamedItem("title").getNodeValue()
1002: : "";
1003: // check for range search members in the parameter map
1004: boolean rangeMemberInSearchParams = false;
1005: if (getParamMap() != null) {
1006: Object lowerObj = getParamMap().get(
1007: RANGE_LOWER_BOUND_PROPERTY_PREFIX
1008: + fieldDefName);
1009: if ((lowerObj != null)
1010: && (lowerObj instanceof String)) {
1011: rangeMemberInSearchParams |= StringUtils
1012: .isNotBlank((String) lowerObj);
1013: }
1014: Object upperObj = getParamMap().get(
1015: RANGE_UPPER_BOUND_PROPERTY_PREFIX
1016: + fieldDefName);
1017: if ((upperObj != null)
1018: && (upperObj instanceof String)) {
1019: rangeMemberInSearchParams |= StringUtils
1020: .isNotBlank((String) upperObj);
1021: }
1022: Object testObject = getParamMap().get(
1023: fieldDefName);
1024: if ((testObject != null)
1025: || rangeMemberInSearchParams) {
1026: // check to see if we need to process this field at all
1027: if (!rangeMemberInSearchParams) {
1028: if (testObject instanceof String) {
1029: String stringVariable = (String) testObject;
1030: if (StringUtils
1031: .isBlank(stringVariable)) {
1032: // field is not multi value and is empty... skip it
1033: continue;
1034: }
1035: } else if (testObject instanceof Collection) {
1036: Collection stringVariables = (Collection<String>) testObject;
1037: boolean allAreBlank = true;
1038: for (Iterator iter = stringVariables
1039: .iterator(); iter.hasNext();) {
1040: String testString = (String) iter
1041: .next();
1042: if (StringUtils
1043: .isNotBlank(testString)) {
1044: allAreBlank = false;
1045: break;
1046: }
1047: }
1048: if (allAreBlank) {
1049: // field is multivalue but all values are blank... skip it
1050: continue;
1051: }
1052: } else {
1053: String errorMessage = "Only String or String[] objects should come from entered parameters of an attribute. Current parameter is '"
1054: + testObject.getClass()
1055: + "'";
1056: LOG.error(errorMessage);
1057: throw new RuntimeException(
1058: errorMessage);
1059: }
1060: }
1061: String findXpathExpressionPrefix = "//searchingConfig/"
1062: + FIELD_DEF_E
1063: + "[@name='"
1064: + fieldDefName + "']";
1065: Node searchDefNode = (Node) xpath
1066: .evaluate(findXpathExpressionPrefix
1067: + "/searchDefinition",
1068: getConfigXML(),
1069: XPathConstants.NODE);
1070: NamedNodeMap searchDefAttributes = null;
1071: String fieldDataType = null;
1072: if (searchDefNode != null) {
1073: // get the data type from the xml
1074: searchDefAttributes = searchDefNode
1075: .getAttributes();
1076: if (searchDefAttributes
1077: .getNamedItem("dataType") != null) {
1078: fieldDataType = searchDefAttributes
1079: .getNamedItem("dataType")
1080: .getNodeValue();
1081: }
1082:
1083: }
1084: if (Utilities.isEmpty(fieldDataType)) {
1085: fieldDataType = DEFAULT_SEARCHABLE_ATTRIBUTE_TYPE_NAME;
1086: }
1087: // get the searchable attribute value by using the data type
1088: SearchableAttributeValue attributeValue = DocSearchUtils
1089: .getSearchableAttributeValueByDataTypeString(fieldDataType);
1090: if (attributeValue == null) {
1091: String errorMsg = "Cannot find SearchableAttributeValue for field data type '"
1092: + fieldDataType + "'";
1093: LOG.error("validateUserSearchInputs() "
1094: + errorMsg);
1095: throw new RuntimeException(errorMsg);
1096: }
1097:
1098: if (rangeMemberInSearchParams) {
1099: String lowerBoundFieldDefName = RANGE_LOWER_BOUND_PROPERTY_PREFIX
1100: + fieldDefName;
1101: String upperBoundFieldDefName = RANGE_UPPER_BOUND_PROPERTY_PREFIX
1102: + fieldDefName;
1103: String lowerBoundEnteredValue = null;
1104: String upperBoundEnteredValue = null;
1105: NamedNodeMap lowerBoundRangeAttributes = null;
1106: NamedNodeMap upperBoundRangeAttributes = null;
1107: Node rangeDefinitionNode = getPotentialChildNode(
1108: searchDefNode,
1109: "rangeDefinition");
1110: NamedNodeMap rangeDefinitionAttributes = (rangeDefinitionNode != null) ? rangeDefinitionNode
1111: .getAttributes()
1112: : null;
1113: lowerBoundEnteredValue = (String) getParamMap()
1114: .get(lowerBoundFieldDefName);
1115: upperBoundEnteredValue = (String) getParamMap()
1116: .get(upperBoundFieldDefName);
1117: if (!Utilities
1118: .isEmpty(lowerBoundEnteredValue)) {
1119: lowerBoundRangeAttributes = getAttributesForPotentialChildNode(
1120: rangeDefinitionNode,
1121: "lower");
1122: errors
1123: .addAll(performValidation(
1124: attributeValue,
1125: getBooleanWithPotentialOverrides(
1126: "allowWildcards",
1127: searchDefAttributes,
1128: rangeDefinitionAttributes,
1129: lowerBoundRangeAttributes),
1130: lowerBoundFieldDefName,
1131: lowerBoundEnteredValue,
1132: constructRangeFieldErrorPrefix(
1133: fieldDefTitle,
1134: lowerBoundRangeAttributes),
1135: findXpathExpressionPrefix));
1136: }
1137: if (!Utilities
1138: .isEmpty(upperBoundEnteredValue)) {
1139: upperBoundRangeAttributes = getAttributesForPotentialChildNode(
1140: rangeDefinitionNode,
1141: "upper");
1142: errors
1143: .addAll(performValidation(
1144: attributeValue,
1145: getBooleanWithPotentialOverrides(
1146: "allowWildcards",
1147: searchDefAttributes,
1148: rangeDefinitionAttributes,
1149: upperBoundRangeAttributes),
1150: upperBoundFieldDefName,
1151: upperBoundEnteredValue,
1152: constructRangeFieldErrorPrefix(
1153: fieldDefTitle,
1154: upperBoundRangeAttributes),
1155: findXpathExpressionPrefix));
1156: }
1157: if (errors.isEmpty()) {
1158: Boolean rangeValid = attributeValue
1159: .isRangeValid(
1160: lowerBoundEnteredValue,
1161: upperBoundEnteredValue);
1162: if ((rangeValid != null)
1163: && (!rangeValid)) {
1164: String lowerLabel = getPotentialRangeBoundLabelFromAttributes(lowerBoundRangeAttributes);
1165: String upperLabel = getPotentialRangeBoundLabelFromAttributes(upperBoundRangeAttributes);
1166: String errorMsg = "The "
1167: + fieldDefTitle
1168: + " range is incorrect. The "
1169: + (StringUtils
1170: .isNotBlank(lowerLabel) ? lowerLabel
1171: : DEFAULT_RANGE_SEARCH_LOWER_BOUND_LABEL)
1172: + " value entered must come before the "
1173: + (StringUtils
1174: .isNotBlank(upperLabel) ? upperLabel
1175: : DEFAULT_RANGE_SEARCH_UPPER_BOUND_LABEL)
1176: + " value";
1177: LOG
1178: .debug("validateUserSearchInputs() "
1179: + errorMsg
1180: + " :: field type '"
1181: + attributeValue
1182: .getAttributeDataType()
1183: + "'");
1184: errors
1185: .add(new WorkflowAttributeValidationError(
1186: fieldDefName,
1187: errorMsg));
1188: }
1189: }
1190:
1191: } else {
1192: Object enteredValue = getParamMap()
1193: .get(fieldDefName);
1194: if (enteredValue instanceof String) {
1195: String stringVariable = (String) enteredValue;
1196: errors
1197: .addAll(performValidation(
1198: attributeValue,
1199: getBooleanValue(
1200: searchDefAttributes,
1201: "allowWildcards"),
1202: fieldDefName,
1203: stringVariable,
1204: fieldDefTitle,
1205: findXpathExpressionPrefix));
1206: } else if (enteredValue instanceof Collection) {
1207: Collection stringVariables = (Collection<String>) enteredValue;
1208: for (Iterator iter = stringVariables
1209: .iterator(); iter.hasNext();) {
1210: String stringVariable = (String) iter
1211: .next();
1212: errors
1213: .addAll(performValidation(
1214: attributeValue,
1215: getBooleanValue(
1216: searchDefAttributes,
1217: "allowWildcards"),
1218: fieldDefName,
1219: stringVariable,
1220: "One value for "
1221: + fieldDefTitle,
1222: findXpathExpressionPrefix));
1223: }
1224:
1225: } else {
1226: String errorMessage = "Only String or String[] objects should come from entered parameters of an attribute.";
1227: LOG.error(errorMessage);
1228: throw new RuntimeException(
1229: errorMessage);
1230: }
1231: }
1232: } else {
1233: // String findValidation = "//searchingConfig/field[@name='" + fieldAttributes.getNamedItem("name").getNodeValue() + "']/validation";
1234: // Node validation = (Node) xpath.evaluate(findValidation, getConfigXML(), XPathConstants.NODE);
1235: // if (validation != null) {
1236: // NamedNodeMap validationAttributes = validation.getAttributes();
1237: // Node required = validationAttributes.getNamedItem("required");
1238: // if (required != null && "true".equalsIgnoreCase(required.getNodeValue())) {
1239: // errors.add(new WorkflowAttributeValidationError(fieldAttributes.getNamedItem("name").getNodeValue(),fieldAttributes.getNamedItem("title").getNodeValue()+" is required."));
1240: // }
1241: // }
1242: }
1243: }
1244: }
1245: }
1246: } catch (XPathExpressionException e) {
1247: LOG.error("error in validateUserSearchInputs ", e);
1248: throw new RuntimeException(
1249: "Error trying to find xml content with xpath expression: "
1250: + findField, e);
1251: }
1252: return errors;
1253: }
1254:
1255: private String constructRangeFieldErrorPrefix(String fieldDefLabel,
1256: NamedNodeMap rangeBoundAttributes) {
1257: String potentialLabel = getPotentialRangeBoundLabelFromAttributes(rangeBoundAttributes);
1258: if ((StringUtils.isNotBlank(potentialLabel))
1259: && (StringUtils.isNotBlank(fieldDefLabel))) {
1260: return fieldDefLabel + " " + potentialLabel + " Field";
1261: } else if (StringUtils.isNotBlank(fieldDefLabel)) {
1262: return fieldDefLabel + " Range Field";
1263: } else if (StringUtils.isNotBlank(potentialLabel)) {
1264: return "Range Field " + potentialLabel + " Field";
1265: }
1266: return null;
1267: }
1268:
1269: private List performValidation(
1270: SearchableAttributeValue attributeValue,
1271: Boolean allowWildcards, String fieldDefName,
1272: String enteredValue, String errorMessagePrefix,
1273: String findXpathExpressionPrefix)
1274: throws XPathExpressionException {
1275: List errors = new ArrayList();
1276: XPath xpath = XPathHelper.newXPath();
1277: if (attributeValue.allowsWildcards()
1278: && ((allowWildcards == null) || (allowWildcards
1279: .booleanValue()))) {
1280: enteredValue = enteredValue.replaceAll(
1281: SEARCH_WILDCARD_CHARACTER_REGEX_ESCAPED, "");
1282: }
1283: if (!attributeValue.isPassesDefaultValidation(enteredValue)) {
1284: errorMessagePrefix = (StringUtils
1285: .isNotBlank(errorMessagePrefix)) ? errorMessagePrefix
1286: : "Field";
1287: String errorMsg = errorMessagePrefix
1288: + " with value '"
1289: + enteredValue
1290: + "' does not conform to standard validation for field type.";
1291: LOG.debug("validateUserSearchInputs() " + errorMsg
1292: + " :: field type '"
1293: + attributeValue.getAttributeDataType() + "'");
1294: errors.add(new WorkflowAttributeValidationError(
1295: fieldDefName, errorMsg));
1296: } else {
1297: String findValidation = findXpathExpressionPrefix
1298: + "/validation/regex";
1299: String regex = (String) xpath.evaluate(findValidation,
1300: getConfigXML(), XPathConstants.STRING);
1301: if (!Utilities.isEmpty(regex)) {
1302: Pattern pattern = Pattern.compile(regex);
1303: Matcher matcher = pattern.matcher(enteredValue);
1304: if (!matcher.matches()) {
1305: String findErrorMessage = findXpathExpressionPrefix
1306: + "/validation/message";
1307: String message = (String) xpath.evaluate(
1308: findErrorMessage, getConfigXML(),
1309: XPathConstants.STRING);
1310: errors.add(new WorkflowAttributeValidationError(
1311: fieldDefName, message));
1312: }
1313: }
1314: }
1315: return errors;
1316: }
1317:
1318: public Element getConfigXML() {
1319: try {
1320: return DocumentBuilderFactory.newInstance()
1321: .newDocumentBuilder().parse(
1322: new InputSource(new BufferedReader(
1323: new StringReader(ruleAttribute
1324: .getXmlConfigData()))))
1325: .getDocumentElement();
1326: } catch (Exception e) {
1327: String ruleAttrStr = (ruleAttribute == null ? null
1328: : ruleAttribute.getName());
1329: LOG.error("error parsing xml data from search attribute: "
1330: + ruleAttrStr, e);
1331: throw new RuntimeException(
1332: "error parsing xml data from searchable attribute: "
1333: + ruleAttrStr, e);
1334: }
1335: }
1336: }
|