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