Coverage Report - org.kuali.rice.kew.docsearch.DocSearchUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
DocSearchUtils
0%
0/271
0%
0/140
5.5
DocSearchUtils$DateComponent
0%
0/8
N/A
5.5
 
 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;
 18  
 
 19  
 import org.apache.commons.lang.StringUtils;
 20  
 import org.kuali.rice.core.exception.RiceRuntimeException;
 21  
 import org.kuali.rice.core.reflect.ObjectDefinition;
 22  
 import org.kuali.rice.core.resourceloader.ObjectDefinitionResolver;
 23  
 import org.kuali.rice.core.util.ClassLoaderUtils;
 24  
 import org.kuali.rice.core.util.RiceConstants;
 25  
 import org.kuali.rice.kew.docsearch.web.SearchAttributeFormContainer;
 26  
 import org.kuali.rice.kew.doctype.bo.DocumentType;
 27  
 import org.kuali.rice.kew.doctype.service.DocumentTypeService;
 28  
 import org.kuali.rice.kew.exception.WorkflowRuntimeException;
 29  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 30  
 import org.kuali.rice.kew.user.UserUtils;
 31  
 import org.kuali.rice.kew.util.Utilities;
 32  
 import org.kuali.rice.kew.web.session.UserSession;
 33  
 import org.kuali.rice.kns.web.ui.Field;
 34  
 import org.kuali.rice.kns.web.ui.Row;
 35  
 
 36  
 import java.sql.Date;
 37  
 import java.sql.Timestamp;
 38  
 import java.util.*;
 39  
 import java.util.regex.Matcher;
 40  
 import java.util.regex.Pattern;
 41  
 
 42  
 
 43  
 /**
 44  
  * Various static utility methods for helping with Searcha.
 45  
  *
 46  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 47  
  */
 48  0
 public class DocSearchUtils {
 49  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocSearchUtils.class);
 50  
 
 51  
 //    private static final String DATE_REGEX_PASS = "^\\d{2}/\\d{2}/\\d{4}$|^\\d{2}-\\d{2}-\\d{4}$"; // matches MM/dd/yyyy or MM-dd-yyyy
 52  
 //    private static final String DATE_REGEX_PASS_SPLIT = "(\\d{2})[/|-](\\d{2})[/|-](\\d{4})";
 53  
     private static final String DATE_REGEX_SMALL_TWO_DIGIT_YEAR = "^\\d{1,2}/\\d{1,2}/\\d{2}$|^\\d{1,2}-\\d{1,2}-\\d{2}$"; // matches M/d/yy or MM/dd/yy or M-d-yy or MM-dd-yy
 54  
     private static final String DATE_REGEX_SMALL_TWO_DIGIT_YEAR_SPLIT = "(\\d{1,2})[/,-](\\d{1,2})[/,-](\\d{2})";
 55  
     private static final String DATE_REGEX_SMALL_FOUR_DIGIT_YEAR = "^\\d{1,2}/\\d{1,2}/\\d{4}$|^\\d{1,2}-\\d{1,2}-\\d{4}$"; // matches M/d/yyyy or MM/dd/yyyy or M-d-yyyy or MM-dd-yyyy
 56  
     private static final String DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_SPLIT = "(\\d{1,2})[/,-](\\d{1,2})[/,-](\\d{4})";
 57  
 
 58  
     private static final String DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST = "^\\d{4}/\\d{1,2}/\\d{1,2}$|^\\d{4}-\\d{1,2}-\\d{1,2}$"; // matches yyyy/M/d or yyyy/MM/dd or yyyy-M-d or yyyy-MM-dd
 59  
     private static final String DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST_SPLIT = "(\\d{4})[/,-](\\d{1,2})[/,-](\\d{1,2})";
 60  
 
 61  
     private static final String DATE_REGEX_WHOLENUM_SMALL = "^\\d{6}$"; // matches MMddyy
 62  
     private static final String DATE_REGEX_WHOLENUM_SMALL_SPLIT = "(\\d{2})(\\d{2})(\\d{2})";
 63  
     private static final String DATE_REGEX_WHOLENUM_LARGE = "^\\d{8}$"; // matches MMddyyyy
 64  
     private static final String DATE_REGEX_WHOLENUM_LARGE_SPLIT = "(\\d{2})(\\d{2})(\\d{4})";
 65  
 
 66  
     private static final String TIME_REGEX = "([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])";
 67  0
         private static final Map<String, String> REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION = new HashMap<String, String>();
 68  
         static {
 69  
 //                REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.put(DATE_REGEX_PASS, DATE_REGEX_PASS_SPLIT);
 70  0
                 REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.put(DATE_REGEX_SMALL_TWO_DIGIT_YEAR, DATE_REGEX_SMALL_TWO_DIGIT_YEAR_SPLIT);
 71  0
         REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.put(DATE_REGEX_SMALL_FOUR_DIGIT_YEAR, DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_SPLIT);
 72  0
         REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.put(DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST, DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST_SPLIT);
 73  0
                 REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.put(DATE_REGEX_WHOLENUM_SMALL, DATE_REGEX_WHOLENUM_SMALL_SPLIT);
 74  0
                 REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.put(DATE_REGEX_WHOLENUM_LARGE,DATE_REGEX_WHOLENUM_LARGE_SPLIT);
 75  
         }
 76  
 
 77  0
     public static final List DOCUMENT_SEARCH_DATE_VALIDATION_REGEX_EXPRESSIONS = Arrays.asList(DATE_REGEX_SMALL_FOUR_DIGIT_YEAR, DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST);
 78  
 
 79  
     public static List<SearchableAttributeValue> getSearchableAttributeValueObjectTypes() {
 80  0
         List<SearchableAttributeValue> searchableAttributeValueClasses = new ArrayList<SearchableAttributeValue>();
 81  0
         for (Object aSEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST : SearchableAttribute.SEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST)
 82  
         {
 83  0
             Class searchAttributeValueClass = (Class) aSEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST;
 84  0
             ObjectDefinition objDef = new ObjectDefinition(searchAttributeValueClass);
 85  0
             SearchableAttributeValue attributeValue = (SearchableAttributeValue) ObjectDefinitionResolver.createObject(objDef, ClassLoaderUtils.getDefaultClassLoader(), false);
 86  0
             searchableAttributeValueClasses.add(attributeValue);
 87  0
         }
 88  0
         return searchableAttributeValueClasses;
 89  
     }
 90  
 
 91  
     public static SearchableAttributeValue getSearchableAttributeValueByDataTypeString(String dataType) {
 92  0
         SearchableAttributeValue returnableValue = null;
 93  0
         if (StringUtils.isBlank(dataType)) {
 94  0
             return returnableValue;
 95  
         }
 96  0
         for (SearchableAttributeValue attValue : getSearchableAttributeValueObjectTypes())
 97  
         {
 98  0
             if (dataType.equalsIgnoreCase(attValue.getAttributeDataType()))
 99  
             {
 100  0
                 if (returnableValue != null)
 101  
                 {
 102  0
                     String errorMsg = "Found two SearchableAttributeValue objects with same data type string ('" + dataType + "' while ignoring case):  " + returnableValue.getClass().getName() + " and " + attValue.getClass().getName();
 103  0
                     LOG.error("getSearchableAttributeValueByDataTypeString() " + errorMsg);
 104  0
                     throw new RuntimeException(errorMsg);
 105  
                 }
 106  0
                 LOG.debug("getSearchableAttributeValueByDataTypeString() SearchableAttributeValue class name is " + attValue.getClass().getName() + "... ojbConcreteClassName is " + attValue.getOjbConcreteClass());
 107  0
                 ObjectDefinition objDef = new ObjectDefinition(attValue.getClass());
 108  0
                 returnableValue = (SearchableAttributeValue) ObjectDefinitionResolver.createObject(objDef, ClassLoaderUtils.getDefaultClassLoader(), false);
 109  0
             }
 110  
         }
 111  0
         return returnableValue;
 112  
     }
 113  
 
 114  
     /**
 115  
      * A method to format any variety of date strings into a common format
 116  
      *
 117  
      * @param date
 118  
      *            A string date in one of a few different formats
 119  
      * @return A string representing a date in the format yyyy/MM/dd or null if date is invalid
 120  
      */
 121  
     public static String getSqlFormattedDate(String date) {
 122  0
         DateComponent dc = formatDateToDateComponent(date, Arrays.asList(REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.keySet().toArray()));
 123  0
         if (dc == null) {
 124  0
             return null;
 125  
         }
 126  0
         return dc.getYear() + "/" + dc.getMonth() + "/" + dc.getDate();
 127  
     }
 128  
 
 129  
     /**
 130  
      * A method to format any variety of date strings into a common format
 131  
      *
 132  
      * @param date
 133  
      *            A string date in one of a few different formats
 134  
      * @return A string representing a date in the format MM/dd/yyyy or null if date is invalid
 135  
      */
 136  
     public static String getEntryFormattedDate(String date) {
 137  0
         Pattern p = Pattern.compile(TIME_REGEX);
 138  0
         Matcher util = p.matcher(date);
 139  0
         if (util.find()) {
 140  0
             date = StringUtils.substringBeforeLast(date, " ");
 141  
         }
 142  0
         DateComponent dc = formatDateToDateComponent(date, DOCUMENT_SEARCH_DATE_VALIDATION_REGEX_EXPRESSIONS);
 143  0
         if (dc == null) {
 144  0
             return null;
 145  
         }
 146  0
         return dc.getMonth() + "/" + dc.getDate() + "/" + dc.getYear();
 147  
     }
 148  
 
 149  
     private static DateComponent formatDateToDateComponent(String date, List regularExpressionList) {
 150  0
         String matchingRegexExpression = null;
 151  0
         for (Iterator iter = regularExpressionList.iterator(); iter.hasNext();) {
 152  0
             String matchRegex = (String) iter.next();
 153  0
             if (!REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.containsKey(matchRegex)) {
 154  0
                 String errorMsg = "";
 155  0
                 LOG.error("formatDateToDateComponent(String,List) " + errorMsg);
 156  
 
 157  
             }
 158  0
             Pattern p = Pattern.compile(matchRegex);
 159  0
             if ((p.matcher(date)).matches()) {
 160  0
                 matchingRegexExpression = matchRegex;
 161  0
                 break;
 162  
             }
 163  0
         }
 164  
 
 165  0
         if (matchingRegexExpression == null) {
 166  0
             String errorMsg = "formatDate(String,List) Date string given '" + date + "' is not valid according to Workflow defaults.  Returning null value.";
 167  0
             if (StringUtils.isNotBlank(date)) {
 168  0
                 LOG.warn(errorMsg);
 169  
             } else {
 170  0
                 LOG.debug(errorMsg);
 171  
             }
 172  0
             return null;
 173  
         }
 174  0
         String regexSplitExpression = (String) REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.get(matchingRegexExpression);
 175  
 
 176  
         // Check date formats and reformat to yyyy/MM/dd
 177  
         // well formed MM/dd/yyyy
 178  0
         Pattern p = Pattern.compile(regexSplitExpression);
 179  0
         Matcher util = p.matcher(date);
 180  0
         util.matches();
 181  0
         if (regexSplitExpression.equals(DATE_REGEX_SMALL_TWO_DIGIT_YEAR_SPLIT)) {
 182  0
             StringBuffer yearBuf = new StringBuffer();
 183  0
             StringBuffer monthBuf = new StringBuffer();
 184  0
             StringBuffer dateBuf = new StringBuffer();
 185  0
             Integer year = new Integer(util.group(3));
 186  
 
 187  0
             if (year <= 50) {
 188  0
                 yearBuf.append("20").append(util.group(3));
 189  0
             } else if (util.group(3).length() < 3) {
 190  0
                 yearBuf.append("19").append(util.group(3));
 191  
             } else {
 192  0
                 yearBuf.append(util.group(3));
 193  
             }
 194  
 
 195  0
             if (util.group(1).length() < 2) {
 196  0
                 monthBuf.append("0").append(util.group(1));
 197  
             } else {
 198  0
                 monthBuf.append(util.group(1));
 199  
             }
 200  
 
 201  0
             if (util.group(2).length() < 2) {
 202  0
                 dateBuf.append("0").append(util.group(2));
 203  
             } else {
 204  0
                 dateBuf.append(util.group(2));
 205  
             }
 206  
 
 207  0
             return new DateComponent(yearBuf.toString(), monthBuf.toString(), dateBuf.toString());
 208  
 
 209  
             // small date format M/d/yyyy | MM/dd/yyyy | M-d-yyyy | MM-dd-yyyy
 210  0
         } else if (regexSplitExpression.equals(DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_SPLIT)) {
 211  0
             StringBuffer yearBuf = new StringBuffer(util.group(3));
 212  0
             StringBuffer monthBuf = new StringBuffer();
 213  0
             StringBuffer dateBuf = new StringBuffer();
 214  
 
 215  0
             if (util.group(1).length() < 2) {
 216  0
                 monthBuf.append("0").append(util.group(1));
 217  
             } else {
 218  0
                 monthBuf.append(util.group(1));
 219  
             }
 220  
 
 221  0
             if (util.group(2).length() < 2) {
 222  0
                 dateBuf.append("0").append(util.group(2));
 223  
             } else {
 224  0
                 dateBuf.append(util.group(2));
 225  
             }
 226  
 
 227  0
             return new DateComponent(yearBuf.toString(), monthBuf.toString(), dateBuf.toString());
 228  
 
 229  
             // small date format yyyy/M/d | yyyy/MM/dd | yyyy-M-d | yyyy-MM-dd
 230  0
         } else if (regexSplitExpression.equals(DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST_SPLIT)) {
 231  0
             StringBuffer yearBuf = new StringBuffer(util.group(1));
 232  0
             StringBuffer monthBuf = new StringBuffer();
 233  0
             StringBuffer dateBuf = new StringBuffer();
 234  
 
 235  0
             if (util.group(2).length() < 2) {
 236  0
                 monthBuf.append("0").append(util.group(2));
 237  
             } else {
 238  0
                 monthBuf.append(util.group(2));
 239  
             }
 240  
 
 241  0
             if (util.group(3).length() < 2) {
 242  0
                 dateBuf.append("0").append(util.group(3));
 243  
             } else {
 244  0
                 dateBuf.append(util.group(3));
 245  
             }
 246  
 
 247  0
             return new DateComponent(yearBuf.toString(), monthBuf.toString(), dateBuf.toString());
 248  
 
 249  
             // large number MMddyyyy
 250  0
         } else if (regexSplitExpression.equals(DATE_REGEX_WHOLENUM_LARGE_SPLIT)) {
 251  0
             return new DateComponent(util.group(3), util.group(1), util.group(2));
 252  
 
 253  
             // small number MMddyy
 254  0
         } else if (regexSplitExpression.equals(DATE_REGEX_WHOLENUM_SMALL_SPLIT)) {
 255  0
             StringBuffer yearBuf = new StringBuffer();
 256  0
             Integer year = new Integer(util.group(3));
 257  
 
 258  0
             if (year < 50) {
 259  0
                 yearBuf.append("20");
 260  
             } else {
 261  0
                 yearBuf.append("19");
 262  
             }
 263  0
             yearBuf.append(util.group(3));
 264  0
             return new DateComponent(yearBuf.toString(), util.group(1), util.group(2));
 265  
         } else {
 266  0
             LOG.warn("formatDate(String,List) Date string given '" + date + "' is not valid according to Workflow defaults.  Returning null value.");
 267  0
             return null;
 268  
         }
 269  
     }
 270  
 
 271  
     public static String getDisplayValueWithDateOnly(Timestamp value) {
 272  0
         return RiceConstants.getDefaultDateFormat().format(new Date(value.getTime()));
 273  
     }
 274  
 
 275  
     public static String getDisplayValueWithDateTime(Timestamp value) {
 276  0
         return RiceConstants.getDefaultDateAndTimeFormat().format(new Date(value.getTime()));
 277  
     }
 278  
 
 279  
     public static Timestamp convertStringDateToTimestamp(String dateWithoutTime) {
 280  0
         Pattern p = Pattern.compile(TIME_REGEX);
 281  0
         Matcher util = p.matcher(dateWithoutTime);
 282  0
         if (util.find()) {
 283  0
             dateWithoutTime = StringUtils.substringBeforeLast(dateWithoutTime, " ");
 284  
         }
 285  0
         DateComponent formattedDate = formatDateToDateComponent(dateWithoutTime, Arrays.asList(REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.keySet().toArray()));
 286  0
         if (formattedDate == null) {
 287  0
             return null;
 288  
         }
 289  0
         Calendar c = Calendar.getInstance();
 290  0
         c.clear();
 291  0
         c.set(Calendar.MONTH, Integer.valueOf(formattedDate.getMonth()) - 1);
 292  0
         c.set(Calendar.DATE, Integer.valueOf(formattedDate.getDate()));
 293  0
         c.set(Calendar.YEAR, Integer.valueOf(formattedDate.getYear()));
 294  0
         return Utilities.convertCalendar(c);
 295  
     }
 296  
 
 297  0
     public static class DateComponent {
 298  
         protected String month;
 299  
         protected String date;
 300  
         protected String year;
 301  
 
 302  0
         public DateComponent(String year, String month, String date) {
 303  0
             this.month = month;
 304  0
             this.date = date;
 305  0
             this.year = year;
 306  0
         }
 307  
 
 308  
         public String getDate() {
 309  0
             return date;
 310  
         }
 311  
 
 312  
         public String getMonth() {
 313  0
             return month;
 314  
         }
 315  
 
 316  
         public String getYear() {
 317  0
             return year;
 318  
         }
 319  
     }
 320  
 
 321  
     private static final String CURRENT_USER_PREFIX = "CURRENT_USER.";
 322  
 
 323  
     /**
 324  
      * Build List of searchable attributes from saved searchable attributes string
 325  
      *
 326  
      * @param searchableAttributeString
 327  
      *            String representation of searchable attributes
 328  
      * @param documentTypeName document type name
 329  
      * @return searchable attributes list
 330  
      */
 331  
     public static List<SearchAttributeCriteriaComponent> buildSearchableAttributesFromString(String searchableAttributeString, String documentTypeName) {
 332  0
         List<SearchAttributeCriteriaComponent> searchableAttributes = new ArrayList<SearchAttributeCriteriaComponent>();
 333  0
         Map<String, SearchAttributeCriteriaComponent> criteriaComponentsByKey = new HashMap<String, SearchAttributeCriteriaComponent>();
 334  
 
 335  0
         DocumentType docType = getDocumentType(documentTypeName);
 336  
 
 337  0
         if (docType != null) {
 338  
 
 339  0
             for (SearchableAttribute searchableAttribute : docType.getSearchableAttributes()) {
 340  
                     //KFSMI-1466 - DocumentSearchContext
 341  0
                 for (Row row : searchableAttribute.getSearchingRows(
 342  
                                 DocSearchUtils.getDocumentSearchContext("", docType.getName(), ""))) {
 343  0
                     for (org.kuali.rice.kns.web.ui.Field field : row.getFields()) {
 344  0
                         if (field instanceof Field) {
 345  0
                             SearchableAttributeValue searchableAttributeValue = DocSearchUtils.getSearchableAttributeValueByDataTypeString(field.getFieldDataType());
 346  0
                             SearchAttributeCriteriaComponent sacc = new SearchAttributeCriteriaComponent(field.getPropertyName(), null, field.getPropertyName(), searchableAttributeValue);
 347  0
                             sacc.setRangeSearch(field.isMemberOfRange());
 348  0
                             sacc.setSearchInclusive(field.isInclusive());
 349  0
                             sacc.setSearchable(field.isIndexedForSearch());
 350  0
                             sacc.setLookupableFieldType(field.getFieldType());
 351  0
                             sacc.setCanHoldMultipleValues(Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType()));
 352  0
                             criteriaComponentsByKey.put(field.getPropertyName(), sacc);
 353  0
                         } else {
 354  0
                             throw new RiceRuntimeException("Fields must be of type org.kuali.rice.kew.docsearch.Field");
 355  
                         }
 356  
                     }
 357  
                 }
 358  
             }
 359  
         }
 360  
 
 361  0
         Map<String, List<String>> checkForMultiValueSearchableAttributes = new HashMap<String, List<String>>();
 362  0
         if ((searchableAttributeString != null) && (searchableAttributeString.trim().length() > 0)) {
 363  0
             StringTokenizer tokenizer = new StringTokenizer(searchableAttributeString, ",");
 364  0
             while (tokenizer.hasMoreTokens()) {
 365  0
                 String searchableAttribute = tokenizer.nextToken();
 366  0
                 int index = searchableAttribute.indexOf(":");
 367  0
                 if (index != -1) {
 368  0
                     String key = searchableAttribute.substring(0, index);
 369  
                     // String savedKey = key;
 370  
                     // if (key.indexOf(SearchableAttribute.RANGE_LOWER_BOUND_PROPERTY_PREFIX) == 0) {
 371  
                     // savedKey = key.substring(SearchableAttribute.RANGE_LOWER_BOUND_PROPERTY_PREFIX.length());
 372  
                     // } else if (key.indexOf(SearchableAttribute.RANGE_UPPER_BOUND_PROPERTY_PREFIX) == 0) {
 373  
                     // savedKey = key.substring(SearchableAttribute.RANGE_UPPER_BOUND_PROPERTY_PREFIX.length());
 374  
                     // }
 375  0
                     String value = searchableAttribute.substring(index + 1);
 376  0
                     if (value.startsWith(CURRENT_USER_PREFIX)) {
 377  0
                         String idType = value.substring(CURRENT_USER_PREFIX.length());
 378  0
                         UserSession session = UserSession.getAuthenticatedUser();
 379  0
                         String idValue = UserUtils.getIdValue(idType, session.getPerson());
 380  0
                         if (!StringUtils.isBlank(idValue)) {
 381  0
                             value = idValue;
 382  
                         }
 383  
                     }
 384  0
                     SearchAttributeCriteriaComponent critComponent = (SearchAttributeCriteriaComponent) criteriaComponentsByKey.get(key);
 385  0
                     if (critComponent == null) {
 386  
                         // here we potentially have a change to the searchable attributes dealing with naming or ranges... so
 387  
                         // we just ignore the values
 388  0
                         continue;
 389  
                     }
 390  0
                     if (critComponent.getSearchableAttributeValue() == null) {
 391  0
                         String errorMsg = "Cannot find SearchableAttributeValue for given key '" + key + "'";
 392  0
                         LOG.error("buildSearchableAttributesFromString() " + errorMsg);
 393  0
                         throw new RuntimeException(errorMsg);
 394  
                     }
 395  0
                     if (critComponent.isCanHoldMultipleValues()) {
 396  
                         // should be multivalue
 397  0
                         if (checkForMultiValueSearchableAttributes.containsKey(key)) {
 398  0
                             List<String> keyList = checkForMultiValueSearchableAttributes.get(key);
 399  0
                             keyList.add(value);
 400  0
                             checkForMultiValueSearchableAttributes.put(key, keyList);
 401  0
                         } else {
 402  0
                             List<String> tempList = new ArrayList<String>();
 403  0
                             tempList.add(value);
 404  
                             // tempList.addAll(Arrays.asList(new String[]{value}));
 405  0
                             checkForMultiValueSearchableAttributes.put(key, tempList);
 406  0
                             searchableAttributes.add(critComponent);
 407  0
                         }
 408  
                     } else {
 409  
                         // should be single value
 410  0
                         if (checkForMultiValueSearchableAttributes.containsKey(key)) {
 411  
                             // attempting to use multiple values in a field that does not support it
 412  0
                             String error = "Attempting to add multiple values to a search attribute (key: '" + key + "') that does not suppor them";
 413  0
                             LOG.error("buildSearchableAttributesFromString() " + error);
 414  
                             // we don't blow chunks here in case an attribute has been altered from multi-value to
 415  
                             // non-multi-value
 416  
                         }
 417  0
                         critComponent.setValue(value);
 418  0
                         searchableAttributes.add(critComponent);
 419  
                     }
 420  
 
 421  
                 }
 422  0
             }
 423  0
             for (SearchAttributeCriteriaComponent criteriaComponent : searchableAttributes)
 424  
             {
 425  0
                 if (criteriaComponent.isCanHoldMultipleValues())
 426  
                 {
 427  0
                     List<String> values = (List<String>) checkForMultiValueSearchableAttributes.get(criteriaComponent.getFormKey());
 428  0
                     criteriaComponent.setValue(null);
 429  0
                     criteriaComponent.setValues(values);
 430  0
                 }
 431  
             }
 432  
         }
 433  
 
 434  0
         return searchableAttributes;
 435  
     }
 436  
 
 437  
     /**
 438  
      * This method takes the given <code>propertyFields</code> parameter and populates the {@link DocSearchCriteriaDTO}
 439  
      * object search attributes based on the document type name set on the <code>criteria</code> object.<br>
 440  
      * <br>
 441  
      * This is identical to calling {@link #addSearchableAttributesToCriteria(DocSearchCriteriaDTO, List, String, boolean)}
 442  
      * with a boolean value of false for the <code>setAttributesStrictly</code> parameter.
 443  
      *
 444  
      * @param criteria -
 445  
      *            The object that needs a list of {@link SearchAttributeCriteriaComponent} objects set up based on the
 446  
      *            document type name and <code>propertyFields</code> parameter
 447  
      * @param propertyFields -
 448  
      *            The list of {@link SearchAttributeFormContainer} objects that need to be converted to
 449  
      *            {@link SearchAttributeCriteriaComponent} objects and set on the <code>criteria</code> parameter
 450  
      * @param searchAttributesString -
 451  
      *            A potential string that must be parsed to use to set attributes on the <code>criteria</code> object
 452  
      */
 453  
     public static void addSearchableAttributesToCriteria(DocSearchCriteriaDTO criteria, List propertyFields, String searchAttributesString) {
 454  0
         addSearchableAttributesToCriteria(criteria, propertyFields, searchAttributesString, false);
 455  0
     }
 456  
 
 457  
     /**
 458  
      * This method takes the given <code>propertyFields</code> parameter and populates the {@link DocSearchCriteriaDTO}
 459  
      * object search attributes based on the document type name set on the <code>criteria</code> object.<br>
 460  
      * <br>
 461  
      * This is identical to calling {@link #addSearchableAttributesToCriteria(DocSearchCriteriaDTO, List, String, boolean)}
 462  
      * with a null value for the <code>searchAttributesString</code> parameter.
 463  
      *
 464  
      * @param criteria -
 465  
      *            The object that needs a list of {@link SearchAttributeCriteriaComponent} objects set up based on the
 466  
      *            document type name and <code>propertyFields</code> parameter
 467  
      * @param propertyFields -
 468  
      *            The list of {@link SearchAttributeFormContainer} objects that need to be converted to
 469  
      *            {@link SearchAttributeCriteriaComponent} objects and set on the <code>criteria</code> parameter
 470  
      * @param setAttributesStrictly -
 471  
      *            A boolean to specify whether to explicitly throw an error when a given value from
 472  
      *            <code>propertyFields</code> does not match a search attribute on the specified document type. If set to
 473  
      *            true an error with be thrown. If set to false the mismatch will be ignored.
 474  
      */
 475  
     public static void addSearchableAttributesToCriteria(DocSearchCriteriaDTO criteria, List propertyFields, boolean setAttributesStrictly) {
 476  0
         addSearchableAttributesToCriteria(criteria, propertyFields, null, setAttributesStrictly);
 477  0
     }
 478  
 
 479  
     /**
 480  
      * This method takes the given <code>propertyFields</code> parameter and populates the {@link DocSearchCriteriaDTO}
 481  
      * object search attributes based on the document type name set on the <code>criteria</code> object.
 482  
      *
 483  
      * @param criteria -
 484  
      *            The object that needs a list of {@link SearchAttributeCriteriaComponent} objects set up based on the
 485  
      *            document type name and <code>propertyFields</code> parameter
 486  
      * @param propertyFields -
 487  
      *            The list of {@link SearchAttributeFormContainer} objects that need to be converted to
 488  
      *            {@link SearchAttributeCriteriaComponent} objects and set on the <code>criteria</code> parameter
 489  
      * @param searchAttributesString -
 490  
      *            A potential string that must be parsed to use to set attributes on the <code>criteria</code> object
 491  
      * @param setAttributesStrictly -
 492  
      *            A boolean to specify whether to explicitly throw an error when a given value from
 493  
      *            <code>propertyFields</code> does not match a search attribute on the specified document type. If set to
 494  
      *            true an error with be thrown. If set to false the mismatch will be ignored.
 495  
      */
 496  
     public static void addSearchableAttributesToCriteria(DocSearchCriteriaDTO criteria, List propertyFields, String searchAttributesString, boolean setAttributesStrictly) {
 497  0
         if (criteria != null) {
 498  0
             DocumentType docType = getDocumentType(criteria.getDocTypeFullName());
 499  0
             if (docType == null) {
 500  0
                 return;
 501  
             }
 502  0
             criteria.getSearchableAttributes().clear();
 503  0
             Map<String, SearchAttributeCriteriaComponent> urlParameterSearchAttributesByFormKey = new HashMap<String, SearchAttributeCriteriaComponent>();
 504  0
             if (!StringUtils.isBlank(searchAttributesString)) {
 505  0
                 List<SearchAttributeCriteriaComponent> components = buildSearchableAttributesFromString(searchAttributesString, docType.getName());
 506  0
                 for (SearchAttributeCriteriaComponent component : components) {
 507  0
                     urlParameterSearchAttributesByFormKey.put(component.getFormKey(), component);
 508  0
                     criteria.addSearchableAttribute(component);
 509  
                 }
 510  
 //                docSearchForm.setSearchableAttributes(null);
 511  
             }
 512  0
             if (!propertyFields.isEmpty()) {
 513  0
                 Map<String, SearchAttributeCriteriaComponent> criteriaComponentsByFormKey = new HashMap<String, SearchAttributeCriteriaComponent>();
 514  0
                 for (SearchableAttribute searchableAttribute : docType.getSearchableAttributes()) {
 515  
                         //KFSMI-1466 - DocumentSearchContext
 516  0
                     for (Row row : searchableAttribute.getSearchingRows(
 517  
                                     DocSearchUtils.getDocumentSearchContext("", docType.getName(), ""))) {
 518  0
                         for (org.kuali.rice.kns.web.ui.Field field : row.getFields()) {
 519  0
                             if (field instanceof Field) {
 520  0
                                 SearchableAttributeValue searchableAttributeValue = DocSearchUtils.getSearchableAttributeValueByDataTypeString(field.getFieldDataType());
 521  0
                                 SearchAttributeCriteriaComponent sacc = new SearchAttributeCriteriaComponent(field.getPropertyName(), null, field.getPropertyName(), searchableAttributeValue);
 522  0
                                 sacc.setRangeSearch(field.isMemberOfRange());
 523  0
                                 sacc.setSearchInclusive(field.isInclusive());
 524  0
                                 sacc.setLookupableFieldType(field.getFieldType());
 525  0
                                 sacc.setSearchable(field.isIndexedForSearch());
 526  0
                                 sacc.setCanHoldMultipleValues(field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType()));
 527  0
                                 criteriaComponentsByFormKey.put(field.getPropertyName(), sacc);
 528  0
                             } else {
 529  0
                                 throw new RiceRuntimeException("Fields must be of type org.kuali.rice.kew.docsearch.Field");
 530  
                             }
 531  
                         }
 532  
                     }
 533  
                 }
 534  0
                 for (Iterator iterator = propertyFields.iterator(); iterator.hasNext();) {
 535  0
                     SearchAttributeFormContainer propertyField = (SearchAttributeFormContainer) iterator.next();
 536  0
                     SearchAttributeCriteriaComponent sacc = (SearchAttributeCriteriaComponent) criteriaComponentsByFormKey.get(propertyField.getKey());
 537  0
                     if (sacc != null) {
 538  0
                         if (sacc.getSearchableAttributeValue() == null) {
 539  0
                             String errorMsg = "Searchable attribute with form field key " + sacc.getFormKey() + " does not have a valid SearchableAttributeValue";
 540  0
                             LOG.error("addSearchableAttributesToCriteria() " + errorMsg);
 541  0
                             throw new RuntimeException(errorMsg);
 542  
                         }
 543  
                         // if the url parameter has already set up the search attribute change the propertyField
 544  0
                         if (urlParameterSearchAttributesByFormKey.containsKey(sacc.getFormKey())) {
 545  0
                             setupPropertyField(urlParameterSearchAttributesByFormKey.get(sacc.getFormKey()), propertyFields);
 546  
                         } else {
 547  
                             //if ((Field.CHECKBOX_YES_NO.equals(sacc.getLookupableFieldType())) && (!propertyField.isValueSet())) {
 548  
                                 // value was not set on the form so we must use the alternate value which for checkbox is the
 549  
                                 // 'unchecked' value
 550  
                             //    sacc.setValue(propertyField.getAlternateValue());
 551  
                             //} else
 552  0
                             if (Field.MULTI_VALUE_FIELD_TYPES.contains(sacc.getLookupableFieldType())) {
 553  
                                 // set the multivalue lookup indicator
 554  0
                                 sacc.setCanHoldMultipleValues(true);
 555  0
                                 if (propertyField.getValues() == null) {
 556  0
                                     sacc.setValues(new ArrayList<String>());
 557  
                                 } else {
 558  0
                                     sacc.setValues(Arrays.asList(propertyField.getValues()));
 559  
                                 }
 560  
                             } else {
 561  0
                                 sacc.setValue(propertyField.getValue());
 562  
                             }
 563  0
                             criteria.addSearchableAttribute(sacc);
 564  
                         }
 565  
                     } else {
 566  0
                         if (setAttributesStrictly) {
 567  0
                             String message = "Cannot find matching search attribute with key '" + propertyField.getKey() + "' on document type '" + docType.getName() + "'";
 568  0
                             LOG.error(message);
 569  0
                             throw new WorkflowRuntimeException(message);
 570  
                         }
 571  
                     }
 572  0
                 }
 573  
             }
 574  
         }
 575  0
     }
 576  
 
 577  
     public static void setupPropertyField(SearchAttributeCriteriaComponent searchableAttribute, List propertyFields) {
 578  0
         SearchAttributeFormContainer propertyField = getPropertyField(searchableAttribute.getFormKey(), propertyFields);
 579  0
         if (propertyField != null) {
 580  0
             propertyField.setValue(searchableAttribute.getValue());
 581  0
             if (searchableAttribute.getValues() != null) {
 582  0
                 propertyField.setValues(searchableAttribute.getValues().toArray(new String[searchableAttribute.getValues().size()]));
 583  
             }
 584  
         }
 585  0
     }
 586  
 
 587  
     public static SearchAttributeFormContainer getPropertyField(String key, List propertyFields) {
 588  0
         if (StringUtils.isBlank(key)) {
 589  0
             return null;
 590  
         }
 591  0
         for (Iterator iter = propertyFields.iterator(); iter.hasNext();) {
 592  0
             SearchAttributeFormContainer container = (SearchAttributeFormContainer) iter.next();
 593  0
             if (key.equals(container.getKey())) {
 594  0
                 return container;
 595  
             }
 596  0
         }
 597  0
         return null;
 598  
     }
 599  
 
 600  
     private static DocumentType getDocumentType(String docTypeName) {
 601  0
         if ((docTypeName != null && !"".equals(docTypeName))) {
 602  0
             return ((DocumentTypeService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(docTypeName);
 603  
         }
 604  0
         return null;
 605  
     }
 606  
 
 607  
     public static DocumentSearchContext getDocumentSearchContext(String documentId, String documentTypeName, String documentContent){
 608  0
             DocumentSearchContext documentSearchContext = new DocumentSearchContext();
 609  0
             documentSearchContext.setDocumentId(documentId);
 610  0
             documentSearchContext.setDocumentTypeName(documentTypeName);
 611  0
             documentSearchContext.setDocumentContent(documentContent);
 612  0
             return documentSearchContext;
 613  
     }
 614  
 }