Coverage Report - org.kuali.rice.kew.docsearch.xml.StandardGenericXMLSearchableAttribute
 
Classes in this File Line Coverage Branch Coverage Complexity
StandardGenericXMLSearchableAttribute
0%
0/516
0%
0/322
9.038
 
 1  
 /*
 2  
  * Copyright 2005-2007 The Kuali Foundation
 3  
  *
 4  
  *
 5  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 6  
  * you may not use this file except in compliance with the License.
 7  
  * You may obtain a copy of the License at
 8  
  *
 9  
  * http://www.opensource.org/licenses/ecl2.php
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.kuali.rice.kew.docsearch.xml;
 18  
 
 19  
 import org.apache.commons.lang.StringUtils;
 20  
 import org.kuali.rice.core.api.impex.xml.XmlConstants;
 21  
 import org.kuali.rice.core.util.ConcreteKeyValue;
 22  
 import org.kuali.rice.core.util.KeyValue;
 23  
 import org.kuali.rice.core.util.xml.XmlJotter;
 24  
 import org.kuali.rice.core.web.format.Formatter;
 25  
 import org.kuali.rice.kew.api.WorkflowRuntimeException;
 26  
 import org.kuali.rice.kew.attribute.XMLAttributeUtils;
 27  
 import org.kuali.rice.kew.docsearch.DocSearchUtils;
 28  
 import org.kuali.rice.kew.docsearch.DocumentSearchContext;
 29  
 import org.kuali.rice.kew.docsearch.SearchableAttributeValue;
 30  
 import org.kuali.rice.kew.rule.WorkflowAttributeValidationError;
 31  
 import org.kuali.rice.kew.rule.bo.RuleAttribute;
 32  
 import org.kuali.rice.kew.rule.xmlrouting.XPathHelper;
 33  
 import org.kuali.rice.kew.util.KEWConstants;
 34  
 import org.kuali.rice.kew.util.Utilities;
 35  
 import org.kuali.rice.kim.api.group.Group;
 36  
 import org.kuali.rice.kim.api.group.GroupService;
 37  
 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
 38  
 import org.kuali.rice.kns.web.ui.Field;
 39  
 import org.kuali.rice.kns.web.ui.Row;
 40  
 import org.kuali.rice.krad.UserSession;
 41  
 import org.kuali.rice.krad.util.GlobalVariables;
 42  
 import org.w3c.dom.Document;
 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  
 import org.xml.sax.InputSource;
 48  
 
 49  
 import javax.xml.parsers.DocumentBuilderFactory;
 50  
 import javax.xml.xpath.XPath;
 51  
 import javax.xml.xpath.XPathConstants;
 52  
 import javax.xml.xpath.XPathExpressionException;
 53  
 import java.io.BufferedReader;
 54  
 import java.io.StringReader;
 55  
 import java.util.ArrayList;
 56  
 import java.util.Collection;
 57  
 import java.util.HashMap;
 58  
 import java.util.Iterator;
 59  
 import java.util.List;
 60  
 import java.util.Map;
 61  
 import java.util.regex.Matcher;
 62  
 import java.util.regex.Pattern;
 63  
 
 64  
 
 65  
 /**
 66  
  * implementation of {@link GenericXMLSearchableAttribute}.
 67  
  *
 68  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 69  
  */
 70  0
 public class StandardGenericXMLSearchableAttribute implements GenericXMLSearchableAttribute {
 71  0
         private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(StandardGenericXMLSearchableAttribute.class);
 72  
 
 73  
     private static final String FIELD_DEF_E = "fieldDef";
 74  
 
 75  0
         private Map paramMap = new HashMap();
 76  
         private RuleAttribute ruleAttribute;
 77  0
         private List<Row> searchRows = new ArrayList<Row>();
 78  
 
 79  
         public void setRuleAttribute(RuleAttribute ruleAttribute) {
 80  0
                 this.ruleAttribute = ruleAttribute;
 81  0
         }
 82  
 
 83  
         public void setParamMap(Map paramMap) {
 84  0
                 this.paramMap = paramMap;
 85  0
         }
 86  
 
 87  
         public Map getParamMap() {
 88  0
                 return paramMap;
 89  
         }
 90  
 
 91  
         public String getSearchContent(DocumentSearchContext documentSearchContext) {
 92  0
                 XPath xpath = XPathHelper.newXPath();
 93  0
                 String findDocContent = "//searchingConfig/xmlSearchContent";
 94  
                 try {
 95  0
                         Node xmlDocumentContent = (Node) xpath.evaluate(findDocContent, getConfigXML(), XPathConstants.NODE);
 96  0
                         if (xmlDocumentContent != null && xmlDocumentContent.hasChildNodes()) {
 97  
                                 // Custom doc content in the searchingConfig xml.
 98  0
                                 String docContent = "";
 99  0
                                 NodeList customNodes = xmlDocumentContent.getChildNodes();
 100  0
                                 for (int i = 0; i < customNodes.getLength(); i++) {
 101  0
                                         Node childNode = customNodes.item(i);
 102  0
                                         docContent += XmlJotter.jotNode(childNode);
 103  
                                 }
 104  0
                                 String findField = "//searchingConfig/" + FIELD_DEF_E;
 105  0
                                 NodeList nodes = (NodeList) xpath.evaluate(findField, getConfigXML(), XPathConstants.NODESET);
 106  0
                                 if (nodes == null || nodes.getLength() == 0) {
 107  0
                                         return "";
 108  
                                 }
 109  0
                                 for (int i = 0; i < nodes.getLength(); i++) {
 110  0
                                         Node field = nodes.item(i);
 111  0
                                         NamedNodeMap fieldAttributes = field.getAttributes();
 112  0
                                         if (getParamMap() != null && !org.apache.commons.lang.StringUtils.isEmpty((String) getParamMap().get(fieldAttributes.getNamedItem("name").getNodeValue()))) {
 113  0
                                                 docContent = docContent.replaceAll("%" + fieldAttributes.getNamedItem("name").getNodeValue() + "%", (String) getParamMap().get(fieldAttributes.getNamedItem("name").getNodeValue()));
 114  
                                         }
 115  
                                 }
 116  0
                                 return docContent;
 117  
                         } else {
 118  
                                 // Standard doc content if no doc content is found in the searchingConfig xml.
 119  0
                                 StringBuffer documentContent = new StringBuffer("<xmlRouting>");
 120  0
                                 String findField = "//searchingConfig/" + FIELD_DEF_E;
 121  0
                                 NodeList nodes = (NodeList) xpath.evaluate(findField, getConfigXML(), XPathConstants.NODESET);
 122  0
                                 if (nodes == null || nodes.getLength() == 0) {
 123  0
                                         return "";
 124  
                                 }
 125  0
                                 for (int i = 0; i < nodes.getLength(); i++) {
 126  0
                                         Node field = nodes.item(i);
 127  0
                                         NamedNodeMap fieldAttributes = field.getAttributes();
 128  0
                                         if (getParamMap() != null && !org.apache.commons.lang.StringUtils.isEmpty((String) getParamMap().get(fieldAttributes.getNamedItem("name").getNodeValue()))) {
 129  0
                                                 documentContent.append("<field name=\"");
 130  0
                                                 documentContent.append(fieldAttributes.getNamedItem("name").getNodeValue());
 131  0
                                                 documentContent.append("\"><value>");
 132  0
                                                 documentContent.append((String) getParamMap().get(fieldAttributes.getNamedItem("name").getNodeValue()));
 133  0
                                                 documentContent.append("</value></field>");
 134  
                                         }
 135  
                                 }
 136  0
                                 documentContent.append("</xmlRouting>");
 137  0
                                 return documentContent.toString();
 138  
                         }
 139  0
                 } catch (XPathExpressionException e) {
 140  0
                         LOG.error("error in getSearchContent ", e);
 141  0
                         throw new RuntimeException("Error trying to find xml content with xpath expression", e);
 142  0
                 } catch (Exception e) {
 143  0
                         LOG.error("error in getSearchContent attempting to find xml search content", e);
 144  0
                         throw new RuntimeException("Error trying to get xml search content.", e);
 145  
                 }
 146  
         }
 147  
 
 148  
         public List getSearchStorageValues(DocumentSearchContext documentSearchContext) {
 149  0
                 List<SearchableAttributeValue> searchStorageValues = new ArrayList<SearchableAttributeValue>();
 150  
                 Document document;
 151  0
         if (StringUtils.isBlank(documentSearchContext.getDocumentContent())) {
 152  0
             LOG.warn("Empty Document Content found '" + documentSearchContext.getDocumentContent() + "'");
 153  0
             return searchStorageValues;
 154  
         }
 155  
                 try {
 156  0
                         document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
 157  
                                         new InputSource(new BufferedReader(new StringReader(documentSearchContext.getDocumentContent()))));
 158  0
                 } catch (Exception e){
 159  0
                         LOG.error("error parsing docContent: "+documentSearchContext.getDocumentContent(), e);
 160  0
                         throw new RuntimeException("Error trying to parse docContent: "+documentSearchContext.getDocumentContent(), e);
 161  0
                 }
 162  0
                 XPath xpath = XPathHelper.newXPath(document);
 163  0
                 String findField = "//searchingConfig/" + FIELD_DEF_E;
 164  
                 try {
 165  0
                         NodeList nodes = (NodeList) xpath.evaluate(findField, getConfigXML(), XPathConstants.NODESET);
 166  0
             if (nodes == null) {
 167  0
                 LOG.error("Could not find searching configuration (<searchingConfig>) for this XMLSearchAttribute");
 168  
             } else {
 169  
 
 170  0
                             for (int i = 0; i < nodes.getLength(); i++) {
 171  0
                                     Node field = nodes.item(i);
 172  0
                                     NamedNodeMap fieldAttributes = field.getAttributes();
 173  
 
 174  0
                                     String findXpathExpressionPrefix = "//searchingConfig/" + FIELD_DEF_E + "[@name='" + fieldAttributes.getNamedItem("name").getNodeValue() + "']";
 175  0
                                     String findDataTypeXpathExpression = findXpathExpressionPrefix + "/searchDefinition/@dataType";
 176  0
                                     String findXpathExpression = findXpathExpressionPrefix + "/fieldEvaluation/xpathexpression";
 177  0
                                     String fieldDataType = null;
 178  0
                                     String xpathExpression = null;
 179  
                                     try {
 180  0
                         fieldDataType = (String) xpath.evaluate(findDataTypeXpathExpression, getConfigXML(), XPathConstants.STRING);
 181  0
                                             if (org.apache.commons.lang.StringUtils.isEmpty(fieldDataType)) {
 182  0
                                                     fieldDataType = KEWConstants.SearchableAttributeConstants.DEFAULT_SEARCHABLE_ATTRIBUTE_TYPE_NAME;
 183  
                                             }
 184  0
                                         xpathExpression = (String) xpath.evaluate(findXpathExpression, getConfigXML(), XPathConstants.STRING);
 185  0
                                             if (!org.apache.commons.lang.StringUtils.isEmpty(xpathExpression)) {
 186  
 
 187  
                             try {
 188  0
                                 NodeList searchValues = (NodeList) xpath.evaluate(xpathExpression, document.getDocumentElement(), XPathConstants.NODESET);
 189  
                               //being that this is the standard xml attribute we will return the key with an empty value
 190  
                                 // so we can find it from a doc search using this key
 191  0
                                 if (searchValues.getLength() == 0) {
 192  0
                                         SearchableAttributeValue searchableValue = this.setupSearchableAttributeValue(fieldDataType, fieldAttributes.getNamedItem("name").getNodeValue(), null);
 193  0
                                         if (searchableValue != null) {
 194  0
                                         searchStorageValues.add(searchableValue);
 195  
                                         }
 196  0
                                 } else {
 197  0
                                         for (int j = 0; j < searchValues.getLength(); j++) {
 198  0
                                         Node searchValue = searchValues.item(j);
 199  0
                                         String value = null;
 200  0
                                         if (searchValue.getFirstChild() != null && (!StringUtils.isEmpty(searchValue.getFirstChild().getNodeValue()))) {
 201  0
                                                 value = searchValue.getFirstChild().getNodeValue();
 202  
                                         }
 203  0
                                             SearchableAttributeValue searchableValue = this.setupSearchableAttributeValue(fieldDataType, fieldAttributes.getNamedItem("name").getNodeValue(), value);
 204  0
                                             if (searchableValue != null) {
 205  0
                                             searchStorageValues.add(searchableValue);
 206  
                                             }
 207  
                                     }
 208  
                                 }
 209  0
                             } catch (XPathExpressionException e) {
 210  
                                 //try for a string being returned from the expression.  This
 211  
                                 //seems like a poor way to determine our expression return type but
 212  
                                 //it's all I can come up with at the moment.
 213  0
                                 String searchValue = (String) xpath.evaluate(xpathExpression, DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
 214  
                                                 new InputSource(new BufferedReader(new StringReader(documentSearchContext.getDocumentContent())))).getDocumentElement(), XPathConstants.STRING);
 215  0
                                 String value = null;
 216  0
                                 if (StringUtils.isNotBlank(searchValue)) {
 217  0
                                     value = searchValue;
 218  
                                 }
 219  0
                                     SearchableAttributeValue searchableValue = this.setupSearchableAttributeValue(fieldDataType, fieldAttributes.getNamedItem("name").getNodeValue(), value);
 220  0
                                     if (searchableValue != null) {
 221  0
                                     searchStorageValues.add(searchableValue);
 222  
                                     }
 223  0
                             }
 224  
                                             }
 225  0
                                     } catch (XPathExpressionException e) {
 226  0
                                             LOG.error("error in isMatch ", e);
 227  0
                                             throw new RuntimeException("Error trying to find xml content with xpath expressions: " + findXpathExpression + " or " + xpathExpression, e);
 228  0
                                     } catch (Exception e){
 229  0
                                             LOG.error("error parsing docContent: "+documentSearchContext.getDocumentContent(), e);
 230  0
                                             throw new RuntimeException("Error trying to parse docContent: "+documentSearchContext.getDocumentContent(), e);
 231  0
                                     }
 232  
                 }
 233  
                         }
 234  0
                 } catch (XPathExpressionException e) {
 235  0
                         LOG.error("error in getSearchStorageValues ", e);
 236  0
                         throw new RuntimeException("Error trying to find xml content with xpath expression: " + findField, e);
 237  0
                 }
 238  0
                 return searchStorageValues;
 239  
         }
 240  
 
 241  
         private SearchableAttributeValue setupSearchableAttributeValue(String dataType,String key,String value) {
 242  0
                 SearchableAttributeValue attValue = DocSearchUtils.getSearchableAttributeValueByDataTypeString(dataType);
 243  0
                 if (attValue == null) {
 244  0
                         String errorMsg = "Cannot find a SearchableAttributeValue associated with the data type '" + dataType + "'";
 245  0
                     LOG.error("setupSearchableAttributeValue() " + errorMsg);
 246  0
                     throw new RuntimeException(errorMsg);
 247  
                 }
 248  0
         value = (value != null) ? value.trim() : null;
 249  0
         if ( (StringUtils.isNotBlank(value)) && (!attValue.isPassesDefaultValidation(value)) ) {
 250  0
             String errorMsg = "SearchableAttributeValue with the data type '" + dataType + "', key '" + key + "', and value '" + value + "' does not pass default validation and cannot be saved to the database";
 251  0
             LOG.error("setupSearchableAttributeValue() " + errorMsg);
 252  0
             throw new RuntimeException(errorMsg);
 253  
         }
 254  0
                 attValue.setSearchableAttributeKey(key);
 255  0
                 attValue.setupAttributeValue(value);
 256  0
             return attValue;
 257  
         }
 258  
 
 259  
         public List<Row> getSearchingRows(DocumentSearchContext documentSearchContext) {
 260  0
                 if (searchRows.isEmpty()) {
 261  0
                         List<SearchableAttributeValue> searchableAttributeValues = DocSearchUtils.getSearchableAttributeValueObjectTypes();
 262  0
                         List<Row> rows = new ArrayList<Row>();
 263  0
                         NodeList fieldNodeList = getConfigXML().getElementsByTagName(FIELD_DEF_E);
 264  0
                         for (int i = 0; i < fieldNodeList.getLength(); i++) {
 265  0
                                 Node field = fieldNodeList.item(i);
 266  0
                                 NamedNodeMap fieldAttributes = field.getAttributes();
 267  
 
 268  0
                                 List<Field> fields = new ArrayList<Field>();
 269  0
                                 boolean isColumnVisible = true;
 270  0
                 boolean hasXPathExpression = false;
 271  0
                                 Field myField = new Field(fieldAttributes.getNamedItem("name").getNodeValue(), fieldAttributes.getNamedItem("title").getNodeValue());
 272  
 
 273  0
                                 String quickfinderService = null;
 274  
                                 // range search details
 275  0
                                 Field rangeLowerBoundField = null;
 276  0
                                 Field rangeUpperBoundField = null;
 277  0
                                 myField.setUpperCase(true); // this defaults us to case insensitive.
 278  0
                                 for (int j = 0; j < field.getChildNodes().getLength(); j++) {
 279  0
                                         Node childNode = field.getChildNodes().item(j);
 280  0
                                         if ("value".equals(childNode.getNodeName())) {
 281  0
                                                 myField.setPropertyValue(childNode.getFirstChild().getNodeValue());
 282  0
                                         } else if ("display".equals(childNode.getNodeName())) {
 283  0
                                                 List<KeyValue> options = new ArrayList<KeyValue>();
 284  0
                         List<String> selectedOptions = new ArrayList<String>();
 285  0
                                                 for (int k = 0; k < childNode.getChildNodes().getLength(); k++) {
 286  0
                                                         Node displayChildNode = childNode.getChildNodes().item(k);
 287  0
                                                         if ("type".equals(displayChildNode.getNodeName())) {
 288  0
                                                                 String typeValue = displayChildNode.getFirstChild().getNodeValue();
 289  0
                                                                 myField.setFieldType(convertTypeToFieldType(typeValue));
 290  0
                                                                 if ("date".equals(typeValue)) {
 291  0
                                                                         myField.setDatePicker(Boolean.TRUE);
 292  0
                                                                         myField.setFieldDataType(KEWConstants.SearchableAttributeConstants.DATA_TYPE_DATE);
 293  
                                                                 }
 294  0
                                                         } else if ("meta".equals(displayChildNode.getNodeName())) {
 295  
 
 296  0
                                                         } else if ("values".equals(displayChildNode.getNodeName())) {
 297  0
                                                                 NamedNodeMap valuesAttributes = displayChildNode.getAttributes();
 298  
 //                              this is to allow an empty drop down choice and can probably implemented in a better way
 299  0
                                 if (displayChildNode.getFirstChild() != null) {
 300  0
                                     options.add(new ConcreteKeyValue(displayChildNode.getFirstChild().getNodeValue(), valuesAttributes.getNamedItem("title").getNodeValue()));
 301  0
                                     if (valuesAttributes.getNamedItem("selected") != null) {
 302  0
                                         selectedOptions.add(displayChildNode.getFirstChild().getNodeValue());
 303  
                                     }
 304  
                                 } else {
 305  0
                                     options.add(new ConcreteKeyValue("", valuesAttributes.getNamedItem("title").getNodeValue()));
 306  
                                 }
 307  
                                                         }
 308  
                                                 }
 309  0
                                                 if (!options.isEmpty()) {
 310  0
                                                         myField.setFieldValidValues(options);
 311  0
                             if (!selectedOptions.isEmpty()) {
 312  0
                                 if (Field.MULTI_VALUE_FIELD_TYPES.contains(myField.getFieldType())) {
 313  0
                                     String[] newSelectedOptions = new String[selectedOptions.size()];
 314  0
                                     int k = 0;
 315  0
                                     for (String option : selectedOptions)
 316  
                                     {
 317  0
                                         newSelectedOptions[k] = option;
 318  0
                                         k++;
 319  
                                     }
 320  0
                                     myField.setPropertyValues(newSelectedOptions);
 321  0
                                 } else {
 322  0
                                     myField.setPropertyValue((String)selectedOptions.get(0));
 323  
                                 }
 324  
                             }
 325  
                                                 }
 326  0
                                         } else if ("visibility".equals(childNode.getNodeName())) {
 327  0
                                                 parseVisibility(myField, (Element)childNode);
 328  0
                                         } else if ("searchDefinition".equals(childNode.getNodeName())) {
 329  0
                                                 NamedNodeMap searchDefAttributes = childNode.getAttributes();
 330  
                                                 // data type operations
 331  0
                                                 String dataType = (searchDefAttributes.getNamedItem("dataType") == null) ? null : searchDefAttributes.getNamedItem("dataType").getNodeValue();
 332  0
                                                 if (!org.apache.commons.lang.StringUtils.isEmpty(dataType)) {
 333  0
                                                         myField.setFieldDataType(dataType);
 334  
                                                 } else {
 335  
                                                         // no data type means we default to String which disallows range search
 336  0
                                                         myField.setFieldDataType(KEWConstants.SearchableAttributeConstants.DEFAULT_SEARCHABLE_ATTRIBUTE_TYPE_NAME);
 337  
                                                 }
 338  0
                                                 if (KEWConstants.SearchableAttributeConstants.DATA_TYPE_DATE.equalsIgnoreCase(myField.getFieldDataType())) {
 339  0
                                                         myField.setDatePicker(Boolean.TRUE);
 340  
                                                 }
 341  
                                                 //if () {
 342  
                                                 //    myField.setFormatter((Formatter) formatterClass.newInstance());
 343  
                                                 //}
 344  
 
 345  
                                                 // figure out if this is a range search
 346  0
                                                 myField.setMemberOfRange(isRangeSearchField(searchableAttributeValues, myField.getFieldDataType(), searchDefAttributes, childNode));
 347  0
                                                 if (!myField.isMemberOfRange()) {
 348  0
                                                         Boolean caseSensitive = getBooleanValue(searchDefAttributes, "caseSensitive");
 349  0
                                                         if (caseSensitive == null) {
 350  0
                                                                 caseSensitive = false; // we mimmic the KNS. KNS is case insensitive by default
 351  
                                                         }
 352  0
                                                         myField.setUpperCase(!caseSensitive);
 353  0
                                                 } else {
 354  
                                                     // by now we know we have a range that uses the default values at least
 355  
                                                     // these will be
 356  0
                                                     rangeLowerBoundField = new Field("", KEWConstants.SearchableAttributeConstants.DEFAULT_RANGE_SEARCH_LOWER_BOUND_LABEL);
 357  0
                                                     rangeLowerBoundField.setMemberOfRange(true);
 358  0
                                                     rangeUpperBoundField = new Field("", KEWConstants.SearchableAttributeConstants.DEFAULT_RANGE_SEARCH_UPPER_BOUND_LABEL);
 359  0
                                                     rangeUpperBoundField.setMemberOfRange(true);
 360  0
                                                     setupBoundFields(childNode, rangeLowerBoundField, rangeUpperBoundField);
 361  
                         }
 362  
 
 363  0
                                                 String formatterClass = (searchDefAttributes.getNamedItem("formatterClass") == null) ? null : searchDefAttributes.getNamedItem("formatterClass").getNodeValue();
 364  0
                                                 if (!StringUtils.isEmpty(formatterClass)) {
 365  
                                                     try {
 366  0
                                                         myField.setFormatter((Formatter)Class.forName(formatterClass).newInstance());
 367  0
                                                     } catch (InstantiationException e) {
 368  0
                                                 LOG.error("Unable to get new instance of formatter class: " + formatterClass);
 369  0
                                                 throw new RuntimeException("Unable to get new instance of formatter class: " + formatterClass);
 370  
                                             }
 371  0
                                             catch (IllegalAccessException e) {
 372  0
                                                 LOG.error("Unable to get new instance of formatter class: " + formatterClass);
 373  0
                                                 throw new RuntimeException("Unable to get new instance of formatter class: " + formatterClass);
 374  0
                                             } catch (ClassNotFoundException e) {
 375  0
                                                 LOG.error("Unable to find formatter class: " + formatterClass);
 376  0
                                 throw new RuntimeException("Unable to find formatter class: " + formatterClass);
 377  0
                             }
 378  
                                                 }
 379  
 
 380  0
                                         } else if ("resultColumn".equals(childNode.getNodeName())) {
 381  0
                                                 NamedNodeMap columnAttributes = childNode.getAttributes();
 382  0
                                                 Node showNode = columnAttributes.getNamedItem("show");
 383  0
                                                 if (showNode != null && showNode.getNodeValue() != null) {
 384  0
                                                         isColumnVisible = Boolean.valueOf(showNode.getNodeValue());
 385  
                                                 }
 386  0
                                                 myField.setColumnVisible(isColumnVisible);
 387  0
                     } else if ("fieldEvaluation".equals(childNode.getNodeName())) {
 388  0
                         for (int k = 0; k < childNode.getChildNodes().getLength(); k++) {
 389  0
                             Node displayChildNode = childNode.getChildNodes().item(k);
 390  0
                             if ("xpathexpression".equals(displayChildNode.getNodeName())) {
 391  0
                                 hasXPathExpression = true;
 392  0
                                 break;
 393  
                             }
 394  
                         }
 395  0
                                         } else if ("lookup".equals(childNode.getNodeName())) {
 396  0
                                                 XMLAttributeUtils.establishFieldLookup(myField, childNode);
 397  
                                         }
 398  
                                 }
 399  0
                 myField.setIndexedForSearch(hasXPathExpression);
 400  
 
 401  0
                                 if (myField.isMemberOfRange()) {
 402  
                                         // we have a ranged search... we need to add the bound fields and NOT the myField object
 403  0
                                         addRangeFields(KEWConstants.SearchableAttributeConstants.RANGE_LOWER_BOUND_PROPERTY_PREFIX, rangeLowerBoundField, myField, rows, quickfinderService);
 404  0
                                         addRangeFields(KEWConstants.SearchableAttributeConstants.RANGE_UPPER_BOUND_PROPERTY_PREFIX, rangeUpperBoundField, myField, rows, quickfinderService);
 405  
                                 } else {
 406  0
                                         fields.add(myField);
 407  0
                                         if (!myField.getFieldType().equals(Field.HIDDEN)) {
 408  0
                                                 if (myField.isDatePicker()) {
 409  0
                                                         addDatePickerField(fields, myField.getPropertyName());
 410  
                                                 }
 411  
                                         }
 412  0
                                         rows.add(new Row(fields));
 413  
                                 }
 414  
                         }
 415  0
                         searchRows = rows;
 416  
                 }
 417  0
                 return searchRows;
 418  
         }
 419  
 
 420  
     private boolean isRangeSearchField(List<SearchableAttributeValue> searchableAttributeValues, String dataType, NamedNodeMap searchDefAttributes, Node searchDefNode) {
 421  0
         for (SearchableAttributeValue attValue : searchableAttributeValues)
 422  
         {
 423  0
             if (dataType.equalsIgnoreCase(attValue.getAttributeDataType()))
 424  
             {
 425  0
                 return isRangeSearchField(attValue, dataType, searchDefAttributes, searchDefNode);
 426  
             }
 427  
         }
 428  0
         String errorMsg = "Could not find searchable attribute value for data type '" + dataType + "'";
 429  0
         LOG.error("isRangeSearchField(List, String, NamedNodeMap, Node) " + errorMsg);
 430  0
         throw new RuntimeException(errorMsg);
 431  
     }
 432  
 
 433  
     private boolean isRangeSearchField(SearchableAttributeValue searchableAttributeValue, String dataType, NamedNodeMap searchDefAttributes, Node searchDefNode) {
 434  0
         boolean allowRangedSearch = searchableAttributeValue.allowsRangeSearches();
 435  0
         Boolean rangeSearchBoolean = getBooleanValue(searchDefAttributes, "rangeSearch");
 436  0
         boolean rangeSearch = (rangeSearchBoolean != null) && rangeSearchBoolean;
 437  0
         Node rangeDefinition = getPotentialChildNode(searchDefNode, "rangeDefinition");
 438  0
         return ( (allowRangedSearch) && ((rangeDefinition != null) || (rangeSearch)) );
 439  
     }
 440  
 
 441  
     private void setupBoundFields(Node searchDefinitionNode, Field lowerBoundField, Field upperBoundField) {
 442  0
         NamedNodeMap searchDefAttributes = searchDefinitionNode.getAttributes();
 443  0
         Node rangeDefinitionNode = getPotentialChildNode(searchDefinitionNode, "rangeDefinition");
 444  0
         NamedNodeMap rangeDefinitionAttributes = null;
 445  0
         NamedNodeMap lowerBoundNodeAttributes = null;
 446  0
         NamedNodeMap upperBoundNodeAttributes = null;
 447  0
         if (rangeDefinitionNode != null) {
 448  0
             rangeDefinitionAttributes = rangeDefinitionNode.getAttributes();
 449  0
             lowerBoundNodeAttributes = getAttributesForPotentialChildNode(rangeDefinitionNode, "lower");
 450  0
             upperBoundNodeAttributes = getAttributesForPotentialChildNode(rangeDefinitionNode, "upper");
 451  
         }
 452  
         // below methods allow for nullable attribute NamedNodeMaps
 453  0
         setupRangeBoundFieldOverridableSettings(searchDefAttributes, rangeDefinitionAttributes, lowerBoundNodeAttributes, lowerBoundField);
 454  0
         setupRangeBoundFieldOverridableSettings(searchDefAttributes, rangeDefinitionAttributes, upperBoundNodeAttributes, upperBoundField);
 455  0
     }
 456  
 
 457  
         private void addRangeFields(String propertyPrefix, Field rangeBoundField,Field mainField, List<Row> rows,String quickfinderService) {
 458  0
                 List<Field> rangeFields = new ArrayList<Field>();
 459  0
                 rangeBoundField.setColumnVisible(mainField.isColumnVisible());
 460  0
                 rangeBoundField.setFieldDataType(mainField.getFieldDataType());
 461  0
                 rangeBoundField.setFieldHelpUrl(mainField.getFieldHelpUrl());
 462  0
                 rangeBoundField.setFieldType(mainField.getFieldType());
 463  0
         rangeBoundField.setMainFieldLabel(mainField.getFieldLabel());
 464  0
                 rangeBoundField.setFieldValidValues(mainField.getFieldValidValues());
 465  0
                 rangeBoundField.setPropertyName(propertyPrefix + mainField.getPropertyName());
 466  0
                 rangeBoundField.setQuickFinderClassNameImpl(mainField.getQuickFinderClassNameImpl());
 467  
                 //rangeBoundField.setDefaultLookupableName(mainField.getDefaultLookupableName());
 468  0
                 rangeFields.add(rangeBoundField);
 469  0
                 if (!mainField.getFieldType().equals(Field.HIDDEN)) {
 470  
                         // disabling the additional quickfinder field for now, should be included as a single field in the KNS instead of 2 as it was in KEW
 471  
 //                        if (!org.apache.commons.lang.StringUtils.isEmpty(quickfinderService)) {
 472  
 //                                rangeFields.add(new Field("", "", Field.QUICKFINDER, "", "", null, quickfinderService));
 473  
 //                        }
 474  0
                         if (rangeBoundField.isDatePicker()) {
 475  
                                 // variable was set on the bound field
 476  0
                                 if (rangeBoundField.isDatePicker()) {
 477  0
                                         addDatePickerField(rangeFields, rangeBoundField.getPropertyName());
 478  
                                 }
 479  
                         } else {
 480  0
                                 if (mainField.isDatePicker()) {
 481  0
                                         addDatePickerField(rangeFields, rangeBoundField.getPropertyName());
 482  
                                 }
 483  
                         }
 484  
                 }
 485  0
                 rows.add(new Row(rangeFields));
 486  0
         }
 487  
 
 488  
     private void addDatePickerField(List<Field> fields,String propertyName) {
 489  0
         Field Field = new Field(propertyName,"");
 490  0
         Field.setDatePicker(true);
 491  0
                 fields.add(Field);
 492  0
     }
 493  
 
 494  
         private NamedNodeMap getAttributesForPotentialChildNode(Node node, String potentialChildNodeName) {
 495  0
                 Node testNode = getPotentialChildNode(node, potentialChildNodeName);
 496  0
                 return (testNode != null) ? testNode.getAttributes() : null;
 497  
         }
 498  
 
 499  
         private Node getPotentialChildNode(Node node, String childNodeName) {
 500  0
                 if (node != null) {
 501  0
                         for (int k = 0; k < node.getChildNodes().getLength(); k++) {
 502  0
                                 Node testNode = node.getChildNodes().item(k);
 503  0
                                 if (testNode.getNodeName().equals(childNodeName)) {
 504  0
                                         return testNode;
 505  
                                 }
 506  
                         }
 507  
                 }
 508  0
                 return null;
 509  
         }
 510  
 
 511  
         private void setupRangeBoundFieldOverridableSettings(NamedNodeMap searchDefinitionAttributes,NamedNodeMap rangeDefinitionAttributes,NamedNodeMap rangeBoundAttributes,Field boundField) {
 512  0
         String potentialLabel = getPotentialRangeBoundLabelFromAttributes(rangeBoundAttributes);
 513  0
         if (StringUtils.isNotBlank(potentialLabel)) {
 514  0
             boundField.setFieldLabel(potentialLabel);
 515  
         }
 516  0
                 ArrayList<NamedNodeMap> namedNodeMapsByImportance = new ArrayList<NamedNodeMap>();
 517  0
                 namedNodeMapsByImportance.add(rangeBoundAttributes);
 518  0
                 namedNodeMapsByImportance.add(rangeDefinitionAttributes);
 519  0
                 namedNodeMapsByImportance.add(searchDefinitionAttributes);
 520  0
                 Boolean caseSensitive = getBooleanWithPotentialOverrides(namedNodeMapsByImportance, "caseSensitive");
 521  0
                 if (caseSensitive == null) {
 522  0
                         caseSensitive = false; // we mimmic the KNS. KNS is case insensitive by default
 523  
                 }
 524  0
                 boundField.setUpperCase(!caseSensitive);
 525  
                 // TODO: after face-to-face work in december 2008, this was throwing a nullpointerexception for lookups with date pickers
 526  
                 // assuming this code will go away after the document search conversion
 527  0
                 Boolean datePickerBoolean = getBooleanWithPotentialOverrides(namedNodeMapsByImportance, "datePicker");
 528  0
                 if (datePickerBoolean == null) {
 529  0
                         datePickerBoolean = false;
 530  
                 }
 531  0
                 boundField.setDatePicker(datePickerBoolean);
 532  0
                 boundField.setRangeFieldInclusive(getBooleanWithPotentialOverrides(namedNodeMapsByImportance, "inclusive"));
 533  
 
 534  0
         }
 535  
 
 536  
     private String getPotentialRangeBoundLabelFromAttributes(NamedNodeMap rangeBoundAttributes) {
 537  0
         if (rangeBoundAttributes != null) {
 538  0
             String boundLabel = (rangeBoundAttributes.getNamedItem("label") == null) ? null : rangeBoundAttributes.getNamedItem("label").getNodeValue();
 539  0
             if (!org.apache.commons.lang.StringUtils.isEmpty(boundLabel)) {
 540  0
                 return boundLabel;
 541  
             }
 542  
         }
 543  0
         return null;
 544  
     }
 545  
 
 546  
         private Boolean getBooleanWithPotentialOverrides(String attributeName,NamedNodeMap searchDefinitionAttributes,NamedNodeMap rangeDefinitionAttributes,NamedNodeMap rangeBoundAttributes) {
 547  0
                 ArrayList<NamedNodeMap> namedNodeMapsByImportance = new ArrayList<NamedNodeMap>();
 548  0
                 namedNodeMapsByImportance.add(rangeBoundAttributes);
 549  0
                 namedNodeMapsByImportance.add(rangeDefinitionAttributes);
 550  0
                 namedNodeMapsByImportance.add(searchDefinitionAttributes);
 551  0
                 return getBooleanWithPotentialOverrides(namedNodeMapsByImportance, attributeName);
 552  
         }
 553  
 
 554  
         private Boolean getBooleanWithPotentialOverrides(ArrayList<NamedNodeMap> namedNodeMapsByImportance, String attributeName) {
 555  0
         for (NamedNodeMap aNamedNodeMapsByImportance : namedNodeMapsByImportance)
 556  
         {
 557  0
             NamedNodeMap nodeMap = (NamedNodeMap) aNamedNodeMapsByImportance;
 558  0
             Boolean booleanValue = getBooleanValue(nodeMap, attributeName);
 559  0
             if (booleanValue != null)
 560  
             {
 561  0
                 return booleanValue;
 562  
             }
 563  0
         }
 564  0
                 return null;
 565  
         }
 566  
 
 567  
         private Boolean getBooleanValue(NamedNodeMap nodeMap, String attributeName) {
 568  0
                 String nodeValue = getStringValue(nodeMap, attributeName);
 569  0
                 if (nodeValue != null) {
 570  0
                         return Boolean.valueOf(nodeValue);
 571  
                 }
 572  0
                 return null;
 573  
         }
 574  
 
 575  
         private String getStringValue(NamedNodeMap nodeMap, String attributeName) {
 576  0
                 return ( (nodeMap == null) || (nodeMap.getNamedItem(attributeName) == null) || (org.apache.commons.lang.StringUtils.isEmpty(nodeMap.getNamedItem(attributeName).getNodeValue())) ) ? null : nodeMap.getNamedItem(attributeName).getNodeValue();
 577  
         }
 578  
 
 579  
         private void parseVisibility(Field field, Element visibilityElement) {
 580  0
                 for (int vIndex = 0; vIndex < visibilityElement.getChildNodes().getLength(); vIndex++) {
 581  0
                         Node visibilityChildNode = visibilityElement.getChildNodes().item(vIndex);
 582  0
                         if (visibilityChildNode.getNodeType() == Node.ELEMENT_NODE) {
 583  0
                                 boolean visible = true;
 584  0
                                 NamedNodeMap visibilityAttributes = visibilityChildNode.getAttributes();
 585  0
                                 Node visibleNode = visibilityAttributes.getNamedItem("visible");
 586  0
                                 if (visibleNode != null && visibleNode.getNodeValue() != null) {
 587  0
                                         visible = Boolean.valueOf(visibleNode.getNodeValue());
 588  
                                 } else {
 589  0
                                         NodeList visibilityDecls = visibilityChildNode.getChildNodes();
 590  0
                                         for (int vdIndex = 0; vdIndex < visibilityDecls.getLength(); vdIndex++) {
 591  0
                                                 Node visibilityDecl = visibilityDecls.item(vdIndex);
 592  0
                         if (visibilityDecl.getNodeType() == Node.ELEMENT_NODE) {
 593  0
                                 boolean hasIsMemberOfGroupElement = false;
 594  0
                                 String groupName = null;
 595  0
                                 String groupNamespace = null;
 596  0
                                 if (XmlConstants.IS_MEMBER_OF_GROUP.equals(visibilityDecl.getNodeName())) { // Found an "isMemberOfGroup" element.
 597  0
                                         hasIsMemberOfGroupElement = true;
 598  0
                                         groupName = Utilities.substituteConfigParameters(visibilityDecl.getTextContent()).trim();
 599  0
                                         groupNamespace = Utilities.substituteConfigParameters(((Element)visibilityDecl).getAttribute(XmlConstants.NAMESPACE)).trim();
 600  
                                 }
 601  0
                                 else if (XmlConstants.IS_MEMBER_OF_WORKGROUP.equals(visibilityDecl.getNodeName())) { // Found a deprecated "isMemberOfWorkgroup" element.
 602  0
                                         LOG.warn((new StringBuilder()).append("Rule Attribute XML is using deprecated element '").append(
 603  
                                                         XmlConstants.IS_MEMBER_OF_WORKGROUP).append("', please use '").append(XmlConstants.IS_MEMBER_OF_GROUP).append(
 604  
                                                                         "' instead.").toString());
 605  0
                                         hasIsMemberOfGroupElement = true;
 606  0
                                                             String workgroupName = Utilities.substituteConfigParameters(visibilityDecl.getFirstChild().getNodeValue());
 607  0
                                                             groupNamespace = Utilities.parseGroupNamespaceCode(workgroupName);
 608  0
                                                             groupName = Utilities.parseGroupName(workgroupName);
 609  
                                                     }
 610  0
                                                     if (hasIsMemberOfGroupElement) { // Found one of the "isMemberOf..." elements.
 611  0
                                                             UserSession session = GlobalVariables.getUserSession();
 612  0
                                                             if (session == null) {
 613  0
                                                                     throw new WorkflowRuntimeException("UserSession is null!  Attempted to render the searchable attribute outside of an established session.");
 614  
                                                             }
 615  0
                                 GroupService groupService = KimApiServiceLocator.getGroupService();
 616  
 
 617  0
                                                         Group group = groupService.getGroupByName(groupNamespace, groupName);
 618  0
                                         visible =  group == null ? false : groupService.isMemberOfGroup(session.getPerson().getPrincipalId(), group.getId());
 619  
                                                     }
 620  
                         }
 621  
                                         }
 622  
                                 }
 623  0
                                 String type = visibilityChildNode.getNodeName();
 624  0
                                 if ("field".equals(type) || "fieldAndColumn".equals(type)) {
 625  
                                         // if it's not visible, coerce this field to a hidden type
 626  0
                                         if (!visible) {
 627  0
                                                 field.setFieldType(Field.HIDDEN);
 628  
                                         }
 629  
                                 }
 630  0
                                 if ("column".equals(type) || "fieldAndColumn".equals(type)) {
 631  0
                                         field.setColumnVisible(visible);
 632  
                                 }
 633  
                         }
 634  
 
 635  
                 }
 636  0
         }
 637  
 
 638  
         private String convertTypeToFieldType(String type) {
 639  0
                 if ("text".equals(type)) {
 640  0
                         return Field.TEXT;
 641  0
                 } else if ("select".equals(type)) {
 642  0
                         return Field.DROPDOWN;
 643  0
                 } else if ("radio".equals(type)) {
 644  0
                         return Field.RADIO;
 645  0
                 } else if ("quickfinder".equals(type)) {
 646  0
                         return Field.QUICKFINDER;
 647  0
                 } else if ("hidden".equals(type)) {
 648  0
                         return Field.HIDDEN;
 649  0
                 } else if ("date".equals(type)) {
 650  0
                         return Field.TEXT;
 651  0
         } else if ("multibox".equals(type)) {
 652  0
             return Field.MULTIBOX;
 653  
         }
 654  0
                 throw new IllegalArgumentException("Illegal field type found: " + type);
 655  
         }
 656  
 
 657  
         public List validateUserSearchInputs(Map paramMap, DocumentSearchContext documentSearchContext) {
 658  0
                 this.paramMap = paramMap;
 659  0
                 List<WorkflowAttributeValidationError> errors = new ArrayList<WorkflowAttributeValidationError>();
 660  
 
 661  0
                 XPath xpath = XPathHelper.newXPath();
 662  0
                 String findField = "//searchingConfig/" + FIELD_DEF_E;
 663  
                 try {
 664  0
                         NodeList nodes = (NodeList) xpath.evaluate(findField, getConfigXML(), XPathConstants.NODESET);
 665  0
                         if (nodes == null) {
 666  
                                 // no field definitions is de facto valid
 667  0
                             LOG.warn("Could not find any field definitions (<" + FIELD_DEF_E + ">) or possibly a searching configuration (<searchingConfig>) for this XMLSearchAttribute");
 668  
                         } else {
 669  0
                             for (int i = 0; i < nodes.getLength(); i++) {
 670  0
                                     Node field = nodes.item(i);
 671  0
                                     NamedNodeMap fieldAttributes = field.getAttributes();
 672  0
                                         String fieldDefName = fieldAttributes.getNamedItem("name").getNodeValue();
 673  0
                     String fieldDefTitle = ((fieldAttributes.getNamedItem("title")) != null) ? fieldAttributes.getNamedItem("title").getNodeValue() : "";
 674  
                     // check for range search members in the parameter map
 675  0
                     boolean rangeMemberInSearchParams = false;
 676  0
                     if (getParamMap() != null) {
 677  0
                         Object lowerObj = getParamMap().get(KEWConstants.SearchableAttributeConstants.RANGE_LOWER_BOUND_PROPERTY_PREFIX + fieldDefName);
 678  0
                         if ( (lowerObj != null) && (lowerObj instanceof String) ) {
 679  0
                             rangeMemberInSearchParams |= StringUtils.isNotBlank((String) lowerObj);
 680  
                         }
 681  0
                         Object upperObj = getParamMap().get(KEWConstants.SearchableAttributeConstants.RANGE_UPPER_BOUND_PROPERTY_PREFIX + fieldDefName);
 682  0
                         if ( (upperObj != null) && (upperObj instanceof String) ) {
 683  0
                             rangeMemberInSearchParams |= StringUtils.isNotBlank((String) upperObj);
 684  
                         }
 685  0
                         Object testObject = getParamMap().get(fieldDefName);
 686  0
                                             if ( (testObject != null) || rangeMemberInSearchParams ) {
 687  
                             // check to see if we need to process this field at all
 688  0
                             if (!rangeMemberInSearchParams) {
 689  0
                                 if (testObject instanceof String) {
 690  0
                                     String stringVariable = (String) testObject;
 691  0
                                     if (StringUtils.isBlank(stringVariable)) {
 692  
                                         // field is not multi value and is empty... skip it
 693  0
                                         continue;
 694  
                                     }
 695  0
                                 } else if (testObject instanceof Collection) {
 696  0
                                     Collection stringVariables = (Collection<String>)testObject;
 697  0
                                     boolean allAreBlank = true;
 698  0
                                     for (Iterator iter = stringVariables.iterator(); iter.hasNext();) {
 699  0
                                         String testString = (String) iter.next();
 700  0
                                         if (StringUtils.isNotBlank(testString)) {
 701  0
                                             allAreBlank = false;
 702  0
                                             break;
 703  
                                         }
 704  0
                                     }
 705  0
                                     if (allAreBlank) {
 706  
                                         // field is multivalue but all values are blank... skip it
 707  0
                                         continue;
 708  
                                     }
 709  0
                                 } else {
 710  0
                                     String errorMessage = "Only String or String[] objects should come from entered parameters of an attribute. Current parameter is '" + testObject.getClass() + "'";
 711  0
                                     LOG.error(errorMessage);
 712  0
                                     throw new RuntimeException(errorMessage);
 713  
                                 }
 714  
                             }
 715  0
                             String findXpathExpressionPrefix = "//searchingConfig/" + FIELD_DEF_E + "[@name='" + fieldDefName + "']";
 716  0
                                                 Node searchDefNode = (Node) xpath.evaluate(findXpathExpressionPrefix + "/searchDefinition", getConfigXML(), XPathConstants.NODE);
 717  0
                                                 NamedNodeMap searchDefAttributes = null;
 718  0
                                             String fieldDataType = null;
 719  0
                                                 if (searchDefNode != null) {
 720  
                                                     // get the data type from the xml
 721  0
                                                         searchDefAttributes = searchDefNode.getAttributes();
 722  0
                                                         if (searchDefAttributes.getNamedItem("dataType") != null) {
 723  0
                                                             fieldDataType = searchDefAttributes.getNamedItem("dataType").getNodeValue();
 724  
                                                         }
 725  
 
 726  
                                                 }
 727  0
                                                 if (org.apache.commons.lang.StringUtils.isEmpty(fieldDataType)) {
 728  0
                                                         fieldDataType = KEWConstants.SearchableAttributeConstants.DEFAULT_SEARCHABLE_ATTRIBUTE_TYPE_NAME;
 729  
                                                 }
 730  
                                                 // get the searchable attribute value by using the data type
 731  0
                                                 SearchableAttributeValue attributeValue = DocSearchUtils.getSearchableAttributeValueByDataTypeString(fieldDataType);
 732  0
                                                 if (attributeValue == null) {
 733  0
                                                         String errorMsg = "Cannot find SearchableAttributeValue for field data type '" + fieldDataType + "'";
 734  0
                                                         LOG.error("validateUserSearchInputs() " + errorMsg);
 735  0
                                                         throw new RuntimeException(errorMsg);
 736  
                                                 }
 737  
 
 738  0
                                                 if (rangeMemberInSearchParams) {
 739  0
                                 String lowerBoundFieldDefName = KEWConstants.SearchableAttributeConstants.RANGE_LOWER_BOUND_PROPERTY_PREFIX + fieldDefName;
 740  0
                                 String upperBoundFieldDefName = KEWConstants.SearchableAttributeConstants.RANGE_UPPER_BOUND_PROPERTY_PREFIX + fieldDefName;
 741  0
                                 String lowerBoundEnteredValue = null;
 742  0
                                 String upperBoundEnteredValue = null;
 743  0
                                 NamedNodeMap lowerBoundRangeAttributes = null;
 744  0
                                 NamedNodeMap upperBoundRangeAttributes = null;
 745  0
                                                         Node rangeDefinitionNode = getPotentialChildNode(searchDefNode, "rangeDefinition");
 746  0
                                                         NamedNodeMap rangeDefinitionAttributes = (rangeDefinitionNode != null) ? rangeDefinitionNode.getAttributes() : null;
 747  0
                                                         lowerBoundEnteredValue = (String) getParamMap().get(lowerBoundFieldDefName);
 748  0
                                                         upperBoundEnteredValue = (String) getParamMap().get(upperBoundFieldDefName);
 749  0
                                                         if (!org.apache.commons.lang.StringUtils.isEmpty(lowerBoundEnteredValue)) {
 750  0
                                     lowerBoundRangeAttributes = getAttributesForPotentialChildNode(rangeDefinitionNode, "lower");
 751  0
                                                                 errors.addAll(performValidation(attributeValue,
 752  
                                                                                 lowerBoundFieldDefName, lowerBoundEnteredValue, constructRangeFieldErrorPrefix(fieldDefTitle,lowerBoundRangeAttributes), findXpathExpressionPrefix));
 753  
                                                         }
 754  0
                                 if (!org.apache.commons.lang.StringUtils.isEmpty(upperBoundEnteredValue)) {
 755  0
                                     upperBoundRangeAttributes = getAttributesForPotentialChildNode(rangeDefinitionNode, "upper");
 756  0
                                                                 errors.addAll(performValidation(attributeValue,
 757  
                                                                                 upperBoundFieldDefName, upperBoundEnteredValue, constructRangeFieldErrorPrefix(fieldDefTitle,upperBoundRangeAttributes), findXpathExpressionPrefix));
 758  
                                                         }
 759  0
                                 if (errors.isEmpty()) {
 760  0
                                     Boolean rangeValid = attributeValue.isRangeValid(lowerBoundEnteredValue, upperBoundEnteredValue);
 761  0
                                     if ( (rangeValid != null) && (!rangeValid) ) {
 762  0
                                         String lowerLabel = getPotentialRangeBoundLabelFromAttributes(lowerBoundRangeAttributes);
 763  0
                                         String upperLabel = getPotentialRangeBoundLabelFromAttributes(upperBoundRangeAttributes);
 764  0
                                         String errorMsg = "The " + fieldDefTitle + " range is incorrect.  The " + (StringUtils.isNotBlank(lowerLabel) ? lowerLabel : KEWConstants.SearchableAttributeConstants.DEFAULT_RANGE_SEARCH_LOWER_BOUND_LABEL) + " value entered must come before the " + (StringUtils.isNotBlank(upperLabel) ? upperLabel : KEWConstants.SearchableAttributeConstants.DEFAULT_RANGE_SEARCH_UPPER_BOUND_LABEL) + " value";
 765  0
                                         LOG.debug("validateUserSearchInputs() " + errorMsg + " :: field type '" + attributeValue.getAttributeDataType() + "'");
 766  0
                                         errors.add(new WorkflowAttributeValidationError(fieldDefName, errorMsg));
 767  
                                     }
 768  
                                 }
 769  
 
 770  0
                                                 } else {
 771  0
                                 Object enteredValue = getParamMap().get(fieldDefName);
 772  0
                                 if (enteredValue instanceof String) {
 773  0
                                     String stringVariable = (String) enteredValue;
 774  0
                                     errors.addAll(performValidation(attributeValue, fieldDefName, stringVariable, fieldDefTitle, findXpathExpressionPrefix));
 775  0
                                 } else if (enteredValue instanceof Collection) {
 776  0
                                     Collection stringVariables = (Collection<String>)enteredValue;
 777  0
                                     for (Iterator iter = stringVariables.iterator(); iter.hasNext();) {
 778  0
                                         String stringVariable = (String) iter.next();
 779  0
                                         errors.addAll(performValidation(attributeValue, fieldDefName, stringVariable, "One value for " + fieldDefTitle, findXpathExpressionPrefix));
 780  0
                                     }
 781  
 
 782  0
                                 } else {
 783  0
                                     String errorMessage = "Only String or String[] objects should come from entered parameters of an attribute.";
 784  0
                                     LOG.error(errorMessage);
 785  0
                                     throw new RuntimeException(errorMessage);
 786  
                                 }
 787  
                                             }
 788  
                                         } else {
 789  
 //                                            String findValidation = "//searchingConfig/field[@name='" + fieldAttributes.getNamedItem("name").getNodeValue() + "']/validation";
 790  
 //                                            Node validation = (Node) xpath.evaluate(findValidation, getConfigXML(), XPathConstants.NODE);
 791  
 //                                            if (validation != null) {
 792  
 //                                                NamedNodeMap validationAttributes = validation.getAttributes();
 793  
 //                                                Node required = validationAttributes.getNamedItem("required");
 794  
 //                                                if (required != null && "true".equalsIgnoreCase(required.getNodeValue())) {
 795  
 //                                                    errors.add(new WorkflowAttributeValidationError(fieldAttributes.getNamedItem("name").getNodeValue(),fieldAttributes.getNamedItem("title").getNodeValue()+" is required."));
 796  
 //                                                }
 797  
 //                            }
 798  
                                         }
 799  
                     }
 800  
                             }
 801  
             }
 802  0
                 } catch (XPathExpressionException e) {
 803  0
                         LOG.error("error in validateUserSearchInputs ", e);
 804  0
                         throw new RuntimeException("Error trying to find xml content with xpath expression: " + findField, e);
 805  0
                 }
 806  0
                 return errors;
 807  
         }
 808  
 
 809  
     private String constructRangeFieldErrorPrefix(String fieldDefLabel, NamedNodeMap rangeBoundAttributes) {
 810  0
         String potentialLabel = getPotentialRangeBoundLabelFromAttributes(rangeBoundAttributes);
 811  0
         if ( (StringUtils.isNotBlank(potentialLabel)) && (StringUtils.isNotBlank(fieldDefLabel)) ) {
 812  0
             return fieldDefLabel + " " + potentialLabel + " Field";
 813  0
         } else if (StringUtils.isNotBlank(fieldDefLabel)) {
 814  0
             return fieldDefLabel + " Range Field";
 815  0
         } else if (StringUtils.isNotBlank(potentialLabel)) {
 816  0
             return "Range Field " + potentialLabel + " Field";
 817  
         }
 818  0
         return null;
 819  
     }
 820  
 
 821  
         private List<WorkflowAttributeValidationError> performValidation(SearchableAttributeValue attributeValue, String fieldDefName, String enteredValue, String errorMessagePrefix, String findXpathExpressionPrefix) throws XPathExpressionException {
 822  0
                 List<WorkflowAttributeValidationError> errors = new ArrayList<WorkflowAttributeValidationError>();
 823  0
                 XPath xpath = XPathHelper.newXPath();
 824  0
                 if ( attributeValue.allowsWildcards()) {
 825  0
                         enteredValue = enteredValue.replaceAll(KEWConstants.SearchableAttributeConstants.SEARCH_WILDCARD_CHARACTER_REGEX_ESCAPED, "");
 826  
                 }
 827  0
                 if (!attributeValue.isPassesDefaultValidation(enteredValue)) {
 828  0
             errorMessagePrefix = (StringUtils.isNotBlank(errorMessagePrefix)) ? errorMessagePrefix : "Field";
 829  0
                         String errorMsg = errorMessagePrefix + " with value '" + enteredValue + "' does not conform to standard validation for field type.";
 830  0
                         LOG.debug("validateUserSearchInputs() " + errorMsg + " :: field type '" + attributeValue.getAttributeDataType() + "'");
 831  0
                         errors.add(new WorkflowAttributeValidationError(fieldDefName, errorMsg));
 832  0
                 } else {
 833  0
                         String findValidation = findXpathExpressionPrefix + "/validation/regex";
 834  0
                         String regex = (String) xpath.evaluate(findValidation, getConfigXML(), XPathConstants.STRING);
 835  0
                         if (!org.apache.commons.lang.StringUtils.isEmpty(regex)) {
 836  0
                                 Pattern pattern = Pattern.compile(regex);
 837  0
                                 Matcher matcher = pattern.matcher(enteredValue);
 838  0
                                 if (!matcher.matches()) {
 839  0
                                         String findErrorMessage = findXpathExpressionPrefix + "/validation/message";
 840  0
                                         String message = (String) xpath.evaluate(findErrorMessage, getConfigXML(), XPathConstants.STRING);
 841  0
                                         errors.add(new WorkflowAttributeValidationError(fieldDefName, message));
 842  
                                 }
 843  
                         }
 844  
                 }
 845  0
                 return errors;
 846  
         }
 847  
 
 848  
         public Element getConfigXML() {
 849  
                 try {
 850  0
                         return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new BufferedReader(new StringReader(ruleAttribute.getXmlConfigData())))).getDocumentElement();
 851  0
                 } catch (Exception e) {
 852  0
                         String ruleAttrStr = (ruleAttribute == null ? null : ruleAttribute.getName());
 853  0
                         LOG.error("error parsing xml data from search attribute: " + ruleAttrStr, e);
 854  0
                         throw new RuntimeException("error parsing xml data from searchable attribute: " + ruleAttrStr, e);
 855  
                 }
 856  
         }
 857  
 }