Coverage Report - org.kuali.rice.kew.impl.document.search.DocumentSearchGeneratorImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
DocumentSearchGeneratorImpl
0%
0/380
0%
0/188
3.732
 
 1  
 /**
 2  
  * Copyright 2005-2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.kew.impl.document.search;
 17  
 
 18  
 import org.apache.commons.collections.CollectionUtils;
 19  
 import org.apache.commons.lang.StringUtils;
 20  
 import org.joda.time.DateTime;
 21  
 import org.kuali.rice.core.api.CoreApiServiceLocator;
 22  
 import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
 23  
 import org.kuali.rice.core.api.uif.RemotableAttributeError;
 24  
 import org.kuali.rice.core.api.uif.RemotableAttributeField;
 25  
 import org.kuali.rice.core.api.util.RiceConstants;
 26  
 import org.kuali.rice.core.framework.persistence.jdbc.sql.Criteria;
 27  
 import org.kuali.rice.core.framework.persistence.jdbc.sql.SqlBuilder;
 28  
 import org.kuali.rice.core.framework.persistence.platform.DatabasePlatform;
 29  
 import org.kuali.rice.kew.api.KewApiServiceLocator;
 30  
 import org.kuali.rice.kew.api.document.Document;
 31  
 import org.kuali.rice.kew.api.document.DocumentStatus;
 32  
 import org.kuali.rice.kew.api.document.DocumentStatusCategory;
 33  
 import org.kuali.rice.kew.api.document.attribute.DocumentAttribute;
 34  
 import org.kuali.rice.kew.api.document.attribute.DocumentAttributeFactory;
 35  
 import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
 36  
 import org.kuali.rice.kew.api.document.search.DocumentSearchResult;
 37  
 import org.kuali.rice.kew.api.document.search.DocumentSearchResults;
 38  
 import org.kuali.rice.kew.api.document.search.RouteNodeLookupLogic;
 39  
 import org.kuali.rice.kew.docsearch.DocumentSearchInternalUtils;
 40  
 import org.kuali.rice.kew.docsearch.QueryComponent;
 41  
 import org.kuali.rice.kew.docsearch.SearchableAttributeValue;
 42  
 import org.kuali.rice.kew.doctype.bo.DocumentType;
 43  
 import org.kuali.rice.kew.doctype.service.DocumentTypeService;
 44  
 import org.kuali.rice.kew.engine.node.RouteNode;
 45  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 46  
 import org.kuali.rice.kew.api.KewApiConstants;
 47  
 import org.kuali.rice.kew.util.PerformanceLogger;
 48  
 import org.kuali.rice.kim.api.identity.Person;
 49  
 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
 50  
 import org.kuali.rice.krad.util.MessageMap;
 51  
 
 52  
 import java.sql.ResultSet;
 53  
 import java.sql.SQLException;
 54  
 import java.sql.Statement;
 55  
 import java.sql.Timestamp;
 56  
 import java.util.ArrayList;
 57  
 import java.util.Collection;
 58  
 import java.util.Collections;
 59  
 import java.util.HashMap;
 60  
 import java.util.HashSet;
 61  
 import java.util.List;
 62  
 import java.util.Map;
 63  
 import java.util.Set;
 64  
 import java.util.TreeSet;
 65  
 
 66  
 
 67  
 /**
 68  
  * Reference implementation of the {@code DocumentSearchGenerator}.
 69  
  *
 70  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 71  
  */
 72  0
 public class DocumentSearchGeneratorImpl implements DocumentSearchGenerator {
 73  
 
 74  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentSearchGeneratorImpl.class);
 75  
 
 76  
     private static final String ROUTE_NODE_TABLE = "KREW_RTE_NODE_T";
 77  
     private static final String ROUTE_NODE_INST_TABLE = "KREW_RTE_NODE_INSTN_T";
 78  
     private static final String DATABASE_WILDCARD_CHARACTER_STRING = "%";
 79  0
     private static final char DATABASE_WILDCARD_CHARACTER = DATABASE_WILDCARD_CHARACTER_STRING.toCharArray()[0];
 80  
 
 81  
     private DatabasePlatform dbPlatform;
 82  
     private MessageMap messageMap;
 83  
 
 84  0
     private SqlBuilder sqlBuilder = null;
 85  
 
 86  
     @Override
 87  
     public DocumentSearchCriteria clearSearch(DocumentSearchCriteria criteria) {
 88  0
         return DocumentSearchCriteria.Builder.create().build();
 89  
     }
 90  
 
 91  
     public DocumentType getValidDocumentType(String documentTypeFullName) {
 92  0
         if (!org.apache.commons.lang.StringUtils.isEmpty(documentTypeFullName)) {
 93  0
             DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeFullName);
 94  0
             if (documentType == null) {
 95  0
                 throw new RuntimeException("No Valid Document Type Found for document type name '" + documentTypeFullName + "'");
 96  
             }
 97  0
             return documentType;
 98  
         }
 99  0
         return null;
 100  
     }
 101  
 
 102  
     @Override
 103  
     public List<RemotableAttributeError> validateSearchableAttributes(DocumentSearchCriteria.Builder criteria) {
 104  0
         List<RemotableAttributeError> errors = new ArrayList<RemotableAttributeError>();
 105  0
         DocumentType documentType = getValidDocumentType(criteria.getDocumentTypeName());
 106  0
         if (documentType != null) {
 107  0
             errors = KEWServiceLocator.getDocumentSearchCustomizationMediator().validateLookupFieldParameters(documentType, criteria.build());
 108  
         }
 109  0
         return errors == null ? Collections.<RemotableAttributeError>emptyList() : Collections.unmodifiableList(errors);
 110  
     }
 111  
 
 112  
     public QueryComponent getSearchableAttributeSql(Map<String, List<String>> documentAttributeValues, List<RemotableAttributeField> searchFields, String whereClausePredicatePrefix) {
 113  
 
 114  0
         StringBuilder fromSql = new StringBuilder();
 115  0
         StringBuilder whereSql = new StringBuilder();
 116  
 
 117  
         //Map<String, List<SearchAttributeCriteriaComponent>> searchableAttributeRangeComponents = new HashMap<String,List<SearchAttributeCriteriaComponent>>();
 118  0
         Criteria finalCriteria = null;
 119  0
         int tableIndex = 1;
 120  0
         SqlBuilder sqlBuilder = this.getSqlBuilder();
 121  
 
 122  0
         for (String documentAttributeName : documentAttributeValues.keySet()) {
 123  
 
 124  0
             List<String> searchValues = documentAttributeValues.get(documentAttributeName);
 125  0
             if (CollectionUtils.isEmpty(searchValues)) {
 126  0
                 continue;
 127  
             }
 128  
 
 129  0
             String tableAlias = "EXT" + tableIndex;
 130  0
             RemotableAttributeField searchField = getSearchFieldByName(documentAttributeName, searchFields);
 131  0
             String tableName = DocumentSearchInternalUtils.getAttributeTableName(searchField);
 132  0
             boolean caseSensitive = DocumentSearchInternalUtils.isLookupCaseSensitive(searchField);
 133  
 
 134  0
             Criteria crit = null;
 135  
 
 136  0
             Class<?> dataTypeClass = DocumentSearchInternalUtils.getDataTypeClass(searchField);
 137  0
             if (searchValues.size() > 1) {
 138  
                 // if there's more than one entry, we need to do an "in"
 139  0
                 crit = new Criteria(tableName, tableAlias);
 140  0
                 crit.setDbPlatform(sqlBuilder.getDbPlatform());
 141  0
                 crit.in("VAL", searchValues, dataTypeClass);
 142  
             } else {
 143  0
                 crit = sqlBuilder.createCriteria("VAL", searchValues.get(0) , tableName, tableAlias, dataTypeClass, !caseSensitive);
 144  
             }
 145  0
             sqlBuilder.addCriteria("KEY_CD", documentAttributeName, String.class, false, false, crit); // this is always of type string.
 146  0
             sqlBuilder.andCriteria("DOC_HDR_ID", tableAlias + ".DOC_HDR_ID", "KREW_DOC_HDR_T", "DOC_HDR", SqlBuilder.JoinType.class, false, false, crit);
 147  
 
 148  0
             if (finalCriteria == null ){
 149  0
                 finalCriteria = crit;
 150  
             } else{
 151  0
                 sqlBuilder.andCriteria(finalCriteria, crit);
 152  
             }
 153  
 
 154  
             // - below is the old code
 155  
             // if where clause is empty then use passed in prefix... otherwise generate one
 156  0
             String whereClausePrefix = (whereSql.length() == 0) ? whereClausePredicatePrefix : getGeneratedPredicatePrefix(whereSql.length());
 157  0
             QueryComponent qc = generateSearchableAttributeSql(tableName, documentAttributeName, whereClausePrefix, tableIndex);
 158  0
             fromSql.append(qc.getFromSql());
 159  0
             tableIndex++;
 160  0
         }
 161  
 
 162  0
         if (finalCriteria == null) {
 163  0
             return new QueryComponent("", "", "");
 164  
         }
 165  
 
 166  0
         String whereClausePrefix = (whereSql.length() == 0) ? whereClausePredicatePrefix : getGeneratedPredicatePrefix(whereSql.length());
 167  
 
 168  0
         return new QueryComponent("", fromSql.toString(), whereClausePrefix + " " + finalCriteria.buildWhere());
 169  
     }
 170  
 
 171  
     private RemotableAttributeField getSearchFieldByName(String fieldName, List<RemotableAttributeField> searchFields) {
 172  0
         for (RemotableAttributeField searchField : searchFields) {
 173  0
             if (searchField.getName().equals(fieldName)) {
 174  0
                 return searchField;
 175  
             }
 176  
         }
 177  0
         throw new IllegalStateException("Failed to locate a RemotableAttributeField for fieldName=" + fieldName);
 178  
     }
 179  
 
 180  
     public QueryComponent generateSearchableAttributeSql(String tableName, String documentAttributeName, String whereSqlStarter,int tableIndex) {
 181  0
         String tableIdentifier = "EXT" + tableIndex;
 182  0
         QueryComponent joinSqlComponent = getSearchableAttributeJoinSql(tableName, tableIdentifier, whereSqlStarter, documentAttributeName);
 183  0
         return new QueryComponent("", joinSqlComponent.getFromSql(), joinSqlComponent.getWhereSql());
 184  
     }
 185  
 
 186  
     public QueryComponent getSearchableAttributeJoinSql(String tableName, String tableIdentifier, String whereSqlStarter, String attributeTableKeyColumnName) {
 187  0
         return new QueryComponent("", generateSearchableAttributeFromSql(tableName, tableIdentifier).toString(), generateSearchableAttributeWhereClauseJoin(whereSqlStarter, tableIdentifier, attributeTableKeyColumnName).toString());
 188  
     }
 189  
 
 190  
     public StringBuilder generateSearchableAttributeWhereClauseJoin(String whereSqlStarter,String tableIdentifier,String attributeTableKeyColumnName) {
 191  0
         StringBuilder whereSql = new StringBuilder(constructWhereClauseElement(whereSqlStarter, "DOC_HDR.DOC_HDR_ID", "=", getDbPlatform().escapeString(tableIdentifier + ".DOC_HDR_ID"), null, null));
 192  0
         whereSql.append(constructWhereClauseElement(" and ", tableIdentifier + ".KEY_CD", "=",
 193  
                 getDbPlatform().escapeString(attributeTableKeyColumnName), "'", "'"));
 194  0
         return whereSql;
 195  
     }
 196  
 
 197  
     public StringBuilder generateSearchableAttributeFromSql(String tableName, String tableIdentifier) {
 198  0
         if (StringUtils.isBlank(tableName)) {
 199  0
             throw new IllegalArgumentException("tableName was null or blank");
 200  
         }
 201  0
         if (StringUtils.isBlank(tableIdentifier)) {
 202  0
             throw new IllegalArgumentException("tableIdentifier was null or blank");
 203  
         }
 204  0
         StringBuilder fromSql = new StringBuilder();
 205  0
         fromSql.append(" ,").append(tableName).append(" ").append(getDbPlatform().escapeString(tableIdentifier)).append(" ");
 206  0
         return fromSql;
 207  
     }
 208  
 
 209  
     public StringBuilder constructWhereClauseElement(String clauseStarter,String queryTableColumnName,String operand,String valueToSearch,String valuePrefix,String valueSuffix) {
 210  0
         StringBuilder whereSql = new StringBuilder();
 211  0
         valuePrefix = (valuePrefix != null) ? valuePrefix : "";
 212  0
         valueSuffix = (valueSuffix != null) ? valueSuffix : "";
 213  0
         whereSql.append(" " + clauseStarter + " ").append(getDbPlatform().escapeString(queryTableColumnName)).append(" " + operand + " ").append(valuePrefix).append(valueToSearch).append(valueSuffix).append(" ");
 214  0
         return whereSql;
 215  
     }
 216  
 
 217  
     @Override
 218  
     public DocumentSearchResults.Builder processResultSet(DocumentSearchCriteria criteria, boolean criteriaModified, Statement searchAttributeStatement, ResultSet resultSet, int maxResultCap, int fetchLimit) throws SQLException {
 219  0
         DocumentSearchCriteria.Builder criteriaBuilder = DocumentSearchCriteria.Builder.create(criteria);
 220  0
         DocumentSearchResults.Builder results = DocumentSearchResults.Builder.create(criteriaBuilder);
 221  0
         results.setCriteriaModified(criteriaModified);
 222  0
         int size = 0;
 223  0
         List<DocumentSearchResult.Builder> resultList = new ArrayList<DocumentSearchResult.Builder>();
 224  0
         results.setSearchResults(resultList);
 225  0
         Map<String, DocumentSearchResult.Builder> resultMap = new HashMap<String, DocumentSearchResult.Builder>();
 226  0
         PerformanceLogger perfLog = new PerformanceLogger();
 227  0
         int iteration = 0;
 228  0
         boolean resultSetHasNext = resultSet.next();
 229  0
         while ( resultSetHasNext && resultMap.size() < maxResultCap && iteration++ < fetchLimit) {
 230  0
             DocumentSearchResult.Builder resultBuilder = processRow(criteria, searchAttributeStatement, resultSet);
 231  0
             String documentId = resultBuilder.getDocument().getDocumentId();
 232  0
             if (!resultMap.containsKey(documentId)) {
 233  0
                 resultList.add(resultBuilder);
 234  0
                 resultMap.put(documentId, resultBuilder);
 235  0
                 size++;
 236  
             } else {
 237  
                 // handle duplicate rows with different search data
 238  0
                 DocumentSearchResult.Builder previousEntry = resultMap.get(documentId);
 239  0
                 handleMultipleDocumentRows(previousEntry, resultBuilder);
 240  
             }
 241  0
             resultSetHasNext = resultSet.next();
 242  0
         }
 243  
         
 244  0
         perfLog.log("Time to read doc search results.", true);
 245  
         // if we have threshold+1 results, then we have more results than we are going to display
 246  0
         results.setOverThreshold(resultSetHasNext);
 247  
 
 248  0
         LOG.debug("Processed "+size+" document search result rows.");
 249  0
         return results;
 250  
     }
 251  
 
 252  
     /**
 253  
      * Handles multiple document rows by collapsing them into the list of document attributes on the existing row.
 254  
      * The two rows must represent the same document.
 255  
      *
 256  
      * @param existingRow the existing row to combine the new row into
 257  
      * @param newRow the new row from which to combine document attributes with the existing row
 258  
      */
 259  
     private void handleMultipleDocumentRows(DocumentSearchResult.Builder existingRow, DocumentSearchResult.Builder newRow) {
 260  0
         for (DocumentAttribute.AbstractBuilder<?> newDocumentAttribute : newRow.getDocumentAttributes()) {
 261  0
             existingRow.getDocumentAttributes().add(newDocumentAttribute);
 262  
         }
 263  0
     }
 264  
 
 265  
     protected DocumentSearchResult.Builder processRow(DocumentSearchCriteria criteria, Statement searchAttributeStatement, ResultSet rs) throws SQLException {
 266  
 
 267  0
         String documentId = rs.getString("DOC_HDR_ID");
 268  0
         String initiatorPrincipalId = rs.getString("INITR_PRNCPL_ID");
 269  0
         String documentTypeName = rs.getString("DOC_TYP_NM");
 270  0
         org.kuali.rice.kew.api.doctype.DocumentType documentType =
 271  
                 KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(documentTypeName);
 272  0
         if (documentType == null) {
 273  0
             throw new IllegalStateException("Failed to locate a document type with the given name: " + documentTypeName);
 274  
         }
 275  0
         String documentTypeId = documentType.getId();
 276  
 
 277  0
         Document.Builder documentBuilder = Document.Builder.create(documentId, initiatorPrincipalId, documentTypeName, documentTypeId);
 278  0
         DocumentSearchResult.Builder resultBuilder = DocumentSearchResult.Builder.create(documentBuilder);
 279  
 
 280  0
         String statusCode = rs.getString("DOC_HDR_STAT_CD");
 281  0
         Timestamp createTimestamp = rs.getTimestamp("CRTE_DT");
 282  0
         String title = rs.getString("TTL");
 283  0
         String applicationDocumentStatus = rs.getString("APP_DOC_STAT");
 284  
 
 285  0
         documentBuilder.setStatus(DocumentStatus.fromCode(statusCode));
 286  0
         documentBuilder.setDateCreated(new DateTime(createTimestamp.getTime()));
 287  0
         documentBuilder.setTitle(title);
 288  0
         documentBuilder.setApplicationDocumentStatus(applicationDocumentStatus);
 289  
 
 290  
         // TODO - KULRICE-5755 - should probably set as many properties on the document as we can
 291  
 
 292  0
         if (isUsingAtLeastOneSearchAttribute(criteria)) {
 293  0
             populateDocumentAttributesValues(resultBuilder, searchAttributeStatement);
 294  
         }
 295  
 
 296  0
         return resultBuilder;
 297  
     }
 298  
 
 299  
     /**
 300  
      * This method performs searches against the search attribute value tables (see classes implementing
 301  
      * {@link org.kuali.rice.kew.docsearch.SearchableAttributeValue}) to get data to fill in search attribute values on the given resultBuilder parameter
 302  
      *
 303  
      * @param resultBuilder - document search result object getting search attributes added to it
 304  
      * @param searchAttributeStatement - statement being used to call the database for queries
 305  
      * @throws SQLException
 306  
      */
 307  
     public void populateDocumentAttributesValues(DocumentSearchResult.Builder resultBuilder, Statement searchAttributeStatement) throws SQLException {
 308  0
         searchAttributeStatement.setFetchSize(50);
 309  0
         String documentId = resultBuilder.getDocument().getDocumentId();
 310  0
         List<SearchableAttributeValue> attributeValues = DocumentSearchInternalUtils
 311  
                 .getSearchableAttributeValueObjectTypes();
 312  0
         PerformanceLogger perfLog = new PerformanceLogger(documentId);
 313  0
         for (SearchableAttributeValue searchAttValue : attributeValues) {
 314  0
             String attributeSql = "select KEY_CD, VAL from " + searchAttValue.getAttributeTableName() + " where DOC_HDR_ID = '" + documentId + "'";
 315  0
             ResultSet attributeResultSet = null;
 316  
             try {
 317  0
                 attributeResultSet = searchAttributeStatement.executeQuery(attributeSql);
 318  0
                 while (attributeResultSet.next()) {
 319  0
                     searchAttValue.setSearchableAttributeKey(attributeResultSet.getString("KEY_CD"));
 320  0
                     searchAttValue.setupAttributeValue(attributeResultSet, "VAL");
 321  0
                     if ( (!org.apache.commons.lang.StringUtils.isEmpty(searchAttValue.getSearchableAttributeKey())) && (searchAttValue.getSearchableAttributeValue() != null) ) {
 322  0
                         DocumentAttribute documentAttribute = searchAttValue.toDocumentAttribute();
 323  0
                         resultBuilder.getDocumentAttributes().add(DocumentAttributeFactory.loadContractIntoBuilder(
 324  
                                 documentAttribute));
 325  0
                     }
 326  
                 }
 327  
             } finally {
 328  0
                 if (attributeResultSet != null) {
 329  
                     try {
 330  0
                         attributeResultSet.close();
 331  0
                     } catch (Exception e) {
 332  0
                         LOG.warn("Could not close searchable attribute result set for class " + searchAttValue.getClass().getName(),e);
 333  0
                     }
 334  
                 }
 335  
             }
 336  0
         }
 337  0
         perfLog.log("Time to execute doc search search attribute queries.", true);
 338  0
     }
 339  
 
 340  
     public String generateSearchSql(DocumentSearchCriteria criteria, List<RemotableAttributeField> searchFields) {
 341  
 
 342  0
         String docTypeTableAlias   = "DOC1";
 343  0
         String docHeaderTableAlias = "DOC_HDR";
 344  
 
 345  0
         String sqlPrefix = "Select * from (";
 346  0
         String sqlSuffix = ") FINAL_SEARCH order by FINAL_SEARCH.CRTE_DT desc";
 347  
         // the DISTINCT here is important as it filters out duplicate rows which could occur as the result of doc search extension values...
 348  0
         StringBuilder selectSQL = new StringBuilder("select DISTINCT("+ docHeaderTableAlias +".DOC_HDR_ID), "+ docHeaderTableAlias +".INITR_PRNCPL_ID, "
 349  
                 + docHeaderTableAlias +".DOC_HDR_STAT_CD, "+ docHeaderTableAlias +".CRTE_DT, "+ docHeaderTableAlias +".TTL, "+ docHeaderTableAlias +".APP_DOC_STAT, "+ docTypeTableAlias +".DOC_TYP_NM, "
 350  
                 + docTypeTableAlias +".LBL, "+ docTypeTableAlias +".DOC_HDLR_URL, "+ docTypeTableAlias +".ACTV_IND");
 351  0
         StringBuilder fromSQL = new StringBuilder(" from KREW_DOC_TYP_T "+ docTypeTableAlias +" ");
 352  0
         StringBuilder fromSQLForDocHeaderTable = new StringBuilder(", KREW_DOC_HDR_T " + docHeaderTableAlias + " ");
 353  
 
 354  0
         StringBuilder whereSQL = new StringBuilder();
 355  0
         whereSQL.append(getDocumentIdSql(criteria.getDocumentId(), getGeneratedPredicatePrefix(whereSQL.length()), docHeaderTableAlias));
 356  0
         whereSQL.append(getInitiatorSql(criteria.getInitiatorPrincipalName(), getGeneratedPredicatePrefix(whereSQL.length())));
 357  0
         whereSQL.append(getAppDocIdSql(criteria.getApplicationDocumentId(), getGeneratedPredicatePrefix(whereSQL.length())));
 358  0
         whereSQL.append(getDateCreatedSql(criteria.getDateCreatedFrom(), criteria.getDateCreatedTo(), getGeneratedPredicatePrefix(whereSQL.length())));
 359  0
         whereSQL.append(getDateLastModifiedSql(criteria.getDateLastModifiedFrom(), criteria.getDateLastModifiedTo(), getGeneratedPredicatePrefix(whereSQL.length())));
 360  0
         whereSQL.append(getDateApprovedSql(criteria.getDateApprovedFrom(), criteria.getDateApprovedTo(), getGeneratedPredicatePrefix(whereSQL.length())));
 361  0
         whereSQL.append(getDateFinalizedSql(criteria.getDateFinalizedFrom(), criteria.getDateFinalizedTo(), getGeneratedPredicatePrefix(whereSQL.length())));
 362  
 
 363  
         // flags for the table being added to the FROM class of the sql
 364  0
         String principalViewerSql = getViewerSql(criteria.getViewerPrincipalName(), getGeneratedPredicatePrefix(whereSQL.length()));
 365  0
         String groupViewerSql = getGroupViewerSql(criteria.getViewerGroupId(), getGeneratedPredicatePrefix(whereSQL.length()));
 366  0
         if (StringUtils.isNotBlank(principalViewerSql) || StringUtils.isNotBlank(groupViewerSql)) {
 367  0
             whereSQL.append(principalViewerSql);
 368  0
             whereSQL.append(groupViewerSql);
 369  0
             fromSQL.append(", KREW_ACTN_RQST_T ");
 370  
         }
 371  
 
 372  0
         if (!("".equals(getApproverSql(criteria.getApproverPrincipalName(), getGeneratedPredicatePrefix(whereSQL.length()))))) {
 373  0
             whereSQL.append(getApproverSql(criteria.getApproverPrincipalName(), getGeneratedPredicatePrefix(whereSQL.length())));
 374  0
             fromSQL.append(", KREW_ACTN_TKN_T ");
 375  
         }
 376  
 
 377  
 
 378  
 
 379  0
         String docRouteNodeSql = getDocRouteNodeSql(criteria.getDocumentTypeName(), criteria.getRouteNodeName(), criteria.getRouteNodeLookupLogic(), getGeneratedPredicatePrefix(whereSQL.length()));
 380  0
         if (StringUtils.isNotBlank(docRouteNodeSql)) {
 381  0
             whereSQL.append(docRouteNodeSql);
 382  0
             fromSQL.append(", KREW_RTE_NODE_INSTN_T ");
 383  0
             fromSQL.append(", KREW_RTE_NODE_T ");
 384  
         }
 385  
 
 386  0
         if (!criteria.getDocumentAttributeValues().isEmpty()) {
 387  0
             QueryComponent queryComponent = getSearchableAttributeSql(criteria.getDocumentAttributeValues(), searchFields, getGeneratedPredicatePrefix(
 388  
                     whereSQL.length()));
 389  0
             selectSQL.append(queryComponent.getSelectSql());
 390  0
             fromSQL.append(queryComponent.getFromSql());
 391  0
             whereSQL.append(queryComponent.getWhereSql());
 392  
         }
 393  
 
 394  0
         whereSQL.append(getDocTypeFullNameWhereSql(criteria, getGeneratedPredicatePrefix(whereSQL.length())));
 395  0
         whereSQL.append(getDocTitleSql(criteria.getTitle(), getGeneratedPredicatePrefix(whereSQL.length())));
 396  0
         whereSQL.append(getDocumentStatusSql(criteria.getDocumentStatuses(), criteria.getDocumentStatusCategories(), getGeneratedPredicatePrefix(whereSQL.length())));
 397  0
         whereSQL.append(getGeneratedPredicatePrefix(whereSQL.length())).append(" DOC_HDR.DOC_TYP_ID = DOC1.DOC_TYP_ID ");
 398  0
         fromSQL.append(fromSQLForDocHeaderTable);
 399  
 
 400  
         // App Doc Status Value and Transition clauses
 401  0
         String statusTransitionWhereClause = getStatusTransitionDateSql(criteria.getDateApplicationDocumentStatusChangedFrom(), criteria.getDateApplicationDocumentStatusChangedTo(), getGeneratedPredicatePrefix(whereSQL.length()));
 402  0
         whereSQL.append(getAppDocStatusSql(criteria.getApplicationDocumentStatus(), getGeneratedPredicatePrefix(whereSQL.length()), statusTransitionWhereClause.length() ));
 403  0
         if (statusTransitionWhereClause.length() > 0){
 404  0
                 whereSQL.append(statusTransitionWhereClause);
 405  0
             whereSQL.append(getGeneratedPredicatePrefix(whereSQL.length())).append(" DOC_HDR.DOC_HDR_ID = STAT_TRAN.DOC_HDR_ID ");
 406  0
                 fromSQL.append(", KREW_APP_DOC_STAT_TRAN_T STAT_TRAN ");
 407  
         }
 408  
 
 409  0
         String finalizedSql = sqlPrefix + " " + selectSQL.toString() + " " + fromSQL.toString() + " " + whereSQL.toString() + " " + sqlSuffix;
 410  
 
 411  0
         LOG.info("*********** SEARCH SQL ***************");
 412  0
         LOG.info(finalizedSql);
 413  0
         LOG.info("**************************************");
 414  0
         return finalizedSql;
 415  
     }
 416  
 
 417  
     public String getDocumentIdSql(String documentId, String whereClausePredicatePrefix, String tableAlias) {
 418  0
         if (StringUtils.isBlank(documentId)) {
 419  0
             return "";
 420  
         } else {
 421  
                 // Using true for caseInsensitive causes bad performance for MYSQL databases since function indexes cannot be added.
 422  
                 // Due to this, false is passed for caseInsensitive
 423  0
             Criteria crit = getSqlBuilder().createCriteria("DOC_HDR_ID", documentId, "KREW_DOC_HDR_T", tableAlias, String.class, false, true);
 424  0
             return new StringBuilder(whereClausePredicatePrefix + crit.buildWhere()).toString();
 425  
         }
 426  
     }
 427  
 
 428  
     public String getDocTitleSql(String docTitle, String whereClausePredicatePrefix) {
 429  0
         if (StringUtils.isBlank(docTitle)) {
 430  0
             return "";
 431  
         } else {
 432  
             // quick and dirty ' replacement that isn't the best but should work for all dbs
 433  0
             docTitle = docTitle.trim().replace("\'", "\'\'");
 434  0
             SqlBuilder sqlBuild = new SqlBuilder();
 435  0
             Criteria crit = new Criteria("KREW_DOC_HDR_T", "DOC_HDR");
 436  0
             sqlBuild.addCriteria("TTL", docTitle, String.class, true, true, crit);
 437  0
             return new StringBuilder(whereClausePredicatePrefix + crit.buildWhere()).toString();
 438  
         }
 439  
     }
 440  
 
 441  
     // special methods that return the sql needed to complete the search
 442  
     // or nothing if the field was not filled in
 443  
     public String getAppDocIdSql(String appDocId, String whereClausePredicatePrefix) {
 444  0
         if (StringUtils.isBlank(appDocId)) {
 445  0
             return "";
 446  
         } else {
 447  0
             String tableAlias = "DOC_HDR";
 448  0
             Criteria crit = getSqlBuilder().createCriteria("APP_DOC_ID", appDocId, "KREW_DOC_HDR_T", tableAlias,String.class);
 449  0
             return new StringBuilder(whereClausePredicatePrefix + crit.buildWhere()).toString();
 450  
         }
 451  
     }
 452  
 
 453  
     public String getDateCreatedSql(DateTime fromDateCreated, DateTime toDateCreated, String whereClausePredicatePrefix) {
 454  0
         return establishDateString(fromDateCreated, toDateCreated, "KREW_DOC_HDR_T", "DOC_HDR", "CRTE_DT", whereClausePredicatePrefix);
 455  
     }
 456  
 
 457  
     public String getDateApprovedSql(DateTime fromDateApproved, DateTime toDateApproved, String whereClausePredicatePrefix) {
 458  0
         return establishDateString(fromDateApproved, toDateApproved, "KREW_DOC_HDR_T", "DOC_HDR", "APRV_DT", whereClausePredicatePrefix);
 459  
     }
 460  
 
 461  
     public String getDateFinalizedSql(DateTime fromDateFinalized, DateTime toDateFinalized, String whereClausePredicatePrefix) {
 462  0
         return establishDateString(fromDateFinalized, toDateFinalized, "KREW_DOC_HDR_T", "DOC_HDR", "FNL_DT", whereClausePredicatePrefix);
 463  
     }
 464  
 
 465  
     public String getDateLastModifiedSql(DateTime fromDateLastModified, DateTime toDateLastModified, String whereClausePredicatePrefix) {
 466  0
         return establishDateString(fromDateLastModified, toDateLastModified, "KREW_DOC_HDR_T", "DOC_HDR", "STAT_MDFN_DT", whereClausePredicatePrefix);
 467  
     }
 468  
 
 469  
         public String getStatusTransitionDateSql(DateTime fromStatusTransitionDate, DateTime toStatusTransitionDate, String whereClausePredicatePrefix) {
 470  0
         return establishDateString(fromStatusTransitionDate, toStatusTransitionDate, "KREW_DOC_HDR_T", "DOC_HDR", "APP_DOC_STAT_MDFN_DT", whereClausePredicatePrefix);
 471  
     }
 472  
 
 473  
     public String getViewerSql(String viewer, String whereClausePredicatePrefix) {
 474  0
         StringBuilder returnSql = new StringBuilder();
 475  0
         if (StringUtils.isNotBlank(viewer)) {
 476  0
             Map<String, String> m = new HashMap<String, String>();
 477  0
             m.put("principalName", viewer);
 478  
 
 479  
             // This will search for people with the ability for the valid operands.
 480  0
             List<Person> personList = KimApiServiceLocator.getPersonService().findPeople(m, false);
 481  0
             if(CollectionUtils.isEmpty(personList)) {
 482  
                 // they entered something that returned nothing... so we should return nothing
 483  0
                 return new StringBuilder(whereClausePredicatePrefix + " 1 = 0 ").toString();
 484  
             }
 485  
 
 486  0
             List<String> principalList = new ArrayList<String>();
 487  0
             for (Person person : personList){
 488  0
                 principalList.add(person.getPrincipalId());
 489  
             }
 490  
 
 491  0
             Criteria crit = new Criteria("KREW_ACTN_RQST_T", "KREW_ACTN_RQST_T");
 492  0
             crit.in("PRNCPL_ID", principalList, String.class);
 493  0
             returnSql.append(whereClausePredicatePrefix + "( (DOC_HDR.DOC_HDR_ID = KREW_ACTN_RQST_T.DOC_HDR_ID and " + crit.buildWhere() + " )");
 494  
 
 495  0
             Set<String> viewerGroupIds = new TreeSet<String>();
 496  
 
 497  0
             if(CollectionUtils.isNotEmpty(principalList)) {
 498  0
                 for(String principalId: principalList){
 499  0
                     viewerGroupIds.addAll(KimApiServiceLocator.getGroupService().getGroupIdsByPrincipalId(principalId));
 500  
                 }
 501  
             }
 502  
 
 503  
             // Documents routed to users as part of a workgoup should be returned.
 504  
             // Use Chad's escape stuff
 505  0
             if (viewerGroupIds != null && !viewerGroupIds.isEmpty()) {
 506  
 
 507  0
                 returnSql.append(" or ( " +
 508  
                     "DOC_HDR.DOC_HDR_ID = KREW_ACTN_RQST_T.DOC_HDR_ID " +
 509  
                     "and KREW_ACTN_RQST_T.GRP_ID in (");
 510  
 
 511  0
                 boolean first = true;
 512  0
                 for (String groupId : viewerGroupIds){
 513  0
                     if(!first){
 514  0
                         returnSql.append(",");
 515  
                     }
 516  0
                     returnSql.append("'").append(groupId).append("'");
 517  0
                     first = false;
 518  
                 }
 519  0
                 returnSql.append("))");
 520  
             }
 521  0
             returnSql.append(")");
 522  
         }
 523  0
         return returnSql.toString();
 524  
     }
 525  
 
 526  
     public String getGroupViewerSql(String groupId, String whereClausePredicatePrefix) {
 527  0
         String sql = "";
 528  0
         if (StringUtils.isNotBlank(groupId)) {
 529  0
             sql = whereClausePredicatePrefix + " DOC_HDR.DOC_HDR_ID = KREW_ACTN_RQST_T.DOC_HDR_ID and KREW_ACTN_RQST_T.GRP_ID = '" + groupId + "'";
 530  
         }
 531  0
         return sql;
 532  
     }
 533  
 
 534  
     public String getInitiatorSql(String initiatorPrincipalName, String whereClausePredicatePrefix) {
 535  
 
 536  0
         if (StringUtils.isBlank(initiatorPrincipalName)) {
 537  0
             return "";
 538  
         }
 539  
 
 540  0
         String tableAlias = "DOC_HDR";
 541  
 
 542  0
         Map<String, String> m = new HashMap<String, String>();
 543  0
         m.put("principalName", initiatorPrincipalName);
 544  
 
 545  
         // This will search for people with the ability for the valid operands.
 546  0
         List<Person> pList = KimApiServiceLocator.getPersonService().findPeople(m, false);
 547  
 
 548  0
         if(pList == null || pList.isEmpty() ){
 549  
             // they entered something that returned nothing... so we should return nothing
 550  0
              return new StringBuilder(whereClausePredicatePrefix + " 1 = 0 ").toString();
 551  
         }
 552  
 
 553  0
         List<String> principalList = new ArrayList<String>();
 554  
 
 555  0
         for(Person p: pList){
 556  0
             principalList.add(p.getPrincipalId());
 557  
         }
 558  
 
 559  0
         Criteria crit = new Criteria("KREW_DOC_HDR_T", tableAlias);
 560  0
         crit.in("INITR_PRNCPL_ID", principalList, String.class);
 561  
 
 562  0
         return new StringBuilder(whereClausePredicatePrefix + crit.buildWhere()).toString();
 563  
     }
 564  
 
 565  
     public String getApproverSql(String approver, String whereClausePredicatePrefix) {
 566  0
         String returnSql = "";
 567  0
         if (StringUtils.isNotBlank(approver)) {
 568  0
             Map<String, String> m = new HashMap<String, String>();
 569  0
             m.put("principalName", approver);
 570  
 
 571  
             // This will search for people with the ability for the valid operands.
 572  0
             List<Person> pList = KimApiServiceLocator.getPersonService().findPeople(m, false);
 573  
 
 574  0
             if(pList == null || pList.isEmpty() ){
 575  0
                  return "";
 576  
             }
 577  
 
 578  0
             List<String> principalList = new ArrayList<String>();
 579  
 
 580  0
             for(Person p: pList){
 581  0
                 principalList.add(p.getPrincipalId());
 582  
             }
 583  
 
 584  0
             Criteria crit = new Criteria("KREW_ACTN_TKN_T", "KREW_ACTN_TKN_T");
 585  0
             crit.in("PRNCPL_ID", principalList, String.class);
 586  
 
 587  0
             returnSql = whereClausePredicatePrefix +
 588  
             " DOC_HDR.DOC_HDR_ID = KREW_ACTN_TKN_T.DOC_HDR_ID and upper(KREW_ACTN_TKN_T.ACTN_CD) in ('" +
 589  
             KewApiConstants.ACTION_TAKEN_APPROVED_CD + "','" + KewApiConstants.ACTION_TAKEN_BLANKET_APPROVE_CD + "')" +
 590  
             " and " + crit.buildWhere();
 591  
         }
 592  0
         return returnSql;
 593  
     }
 594  
 
 595  
     public String getDocTypeFullNameWhereSql(DocumentSearchCriteria criteria, String whereClausePredicatePrefix) {
 596  0
         List<String> documentTypeNamesToSearch = new ArrayList<String>();
 597  0
         String primaryDocumentTypeName = criteria.getDocumentTypeName();
 598  0
         if (StringUtils.isNotBlank(primaryDocumentTypeName)) {
 599  0
             documentTypeNamesToSearch.add(primaryDocumentTypeName);
 600  
         }
 601  0
         documentTypeNamesToSearch.addAll(criteria.getAdditionalDocumentTypeNames());
 602  0
         StringBuilder returnSql = new StringBuilder("");
 603  0
         if (CollectionUtils.isNotEmpty(documentTypeNamesToSearch)) {
 604  0
             int index = 0;
 605  0
             for (String documentTypeName : documentTypeNamesToSearch) {
 606  0
                 if (StringUtils.isNotBlank(documentTypeName)) {
 607  0
                     String clause = index++ == 0 ? "" : " or ";
 608  0
                     DocumentTypeService docSrv = KEWServiceLocator.getDocumentTypeService();
 609  0
                     DocumentType docType = docSrv.findByName(documentTypeName.trim());
 610  0
                     if (docType != null) {
 611  0
                         addDocumentTypeNameToSearchOn(returnSql, documentTypeName.trim(), clause);
 612  0
                         if (docType.getChildrenDocTypes() != null) {
 613  0
                             addChildDocumentTypes(returnSql, docType.getChildrenDocTypes());
 614  
                         }
 615  
                     } else{
 616  0
                         addDocumentTypeLikeNameToSearchOn(returnSql, documentTypeName.trim(), clause);
 617  
                     }
 618  0
                 }
 619  
             }
 620  
         }
 621  0
         if (returnSql.length() > 0) {
 622  0
             returnSql.insert(0, "(");
 623  0
             returnSql.insert(0, whereClausePredicatePrefix);
 624  0
             returnSql.append(")");
 625  
         }
 626  0
         return returnSql.toString();
 627  
     }
 628  
 
 629  
     public void addChildDocumentTypes(StringBuilder whereSql, Collection<DocumentType> childDocumentTypes) {
 630  0
         for (DocumentType child : childDocumentTypes) {
 631  0
             addDocumentTypeNameToSearchOn(whereSql, child.getName());
 632  0
             addChildDocumentTypes(whereSql, child.getChildrenDocTypes());
 633  
         }
 634  0
     }
 635  
 
 636  
     public void addDocumentTypeNameToSearchOn(StringBuilder whereSql, String documentTypeName) {
 637  0
         this.addDocumentTypeNameToSearchOn(whereSql, documentTypeName, " or ");
 638  0
     }
 639  
 
 640  
     public void addDocumentTypeNameToSearchOn(StringBuilder whereSql, String documentTypeName, String clause) {
 641  0
         whereSql.append(clause).append(" DOC1.DOC_TYP_NM = '" + documentTypeName + "'");
 642  0
     }
 643  
     public void addDocumentTypeLikeNameToSearchOn(StringBuilder whereSql, String documentTypeName, String clause) {
 644  0
         documentTypeName = documentTypeName.replace('*', '%');
 645  0
         whereSql.append(clause).append(" DOC1.DOC_TYP_NM LIKE '" + documentTypeName + "'");
 646  0
     }
 647  
 
 648  
     public String getDocRouteNodeSql(String documentTypeFullName, String routeNodeName, RouteNodeLookupLogic docRouteLevelLogic, String whereClausePredicatePrefix) {
 649  
         // -1 is the default 'blank' choice from the route node drop down a number is used because the ojb RouteNode object is used to
 650  
         // render the node choices on the form.
 651  0
         String returnSql = "";
 652  0
         if (StringUtils.isNotBlank(routeNodeName)) {
 653  0
             if (docRouteLevelLogic == null) {
 654  0
                 docRouteLevelLogic = RouteNodeLookupLogic.EXACTLY;
 655  
             }
 656  0
             StringBuilder routeNodeCriteria = new StringBuilder("and " + ROUTE_NODE_TABLE + ".NM ");
 657  0
             if (RouteNodeLookupLogic.EXACTLY == docRouteLevelLogic) {
 658  0
                         routeNodeCriteria.append("= '" + getDbPlatform().escapeString(routeNodeName) + "' ");
 659  
             } else {
 660  0
                 routeNodeCriteria.append("in (");
 661  
                 // below buffer used to facilitate the addition of the string ", " to separate out route node names
 662  0
                 StringBuilder routeNodeInCriteria = new StringBuilder();
 663  0
                 boolean foundSpecifiedNode = false;
 664  0
                 List<RouteNode> routeNodes = KEWServiceLocator.getRouteNodeService().getFlattenedNodes(getValidDocumentType(documentTypeFullName), true);
 665  0
                 for (RouteNode routeNode : routeNodes) {
 666  0
                     if (routeNodeName.equals(routeNode.getRouteNodeName())) {
 667  
                         // current node is specified node so we ignore it outside of the boolean below
 668  0
                         foundSpecifiedNode = true;
 669  0
                         continue;
 670  
                     }
 671  
                     // below logic should be to add the current node to the criteria if we haven't found the specified node
 672  
                     // and the logic qualifier is 'route nodes before specified'... or we have found the specified node and
 673  
                     // the logic qualifier is 'route nodes after specified'
 674  0
                     if ( (!foundSpecifiedNode && RouteNodeLookupLogic.BEFORE == docRouteLevelLogic) ||
 675  
                          (foundSpecifiedNode && RouteNodeLookupLogic.AFTER == docRouteLevelLogic) ) {
 676  0
                         if (routeNodeInCriteria.length() > 0) {
 677  0
                             routeNodeInCriteria.append(", ");
 678  
                         }
 679  0
                         routeNodeInCriteria.append("'" + routeNode.getRouteNodeName() + "'");
 680  
                     }
 681  
                 }
 682  0
                 if (routeNodeInCriteria.length() > 0) {
 683  0
                     routeNodeCriteria.append(routeNodeInCriteria);
 684  
                 } else {
 685  0
                     routeNodeCriteria.append("''");
 686  
                 }
 687  0
                 routeNodeCriteria.append(") ");
 688  
             }
 689  0
             returnSql = whereClausePredicatePrefix + "DOC_HDR.DOC_HDR_ID = " + ROUTE_NODE_INST_TABLE + ".DOC_HDR_ID and " + ROUTE_NODE_INST_TABLE + ".RTE_NODE_ID = " + ROUTE_NODE_TABLE + ".RTE_NODE_ID and " + ROUTE_NODE_INST_TABLE + ".ACTV_IND = 1 " + routeNodeCriteria.toString() + " ";
 690  
         }
 691  0
         return returnSql;
 692  
     }
 693  
 
 694  
     public String getDocumentStatusSql(List<DocumentStatus> documentStatuses, List<DocumentStatusCategory> categories, String whereClausePredicatePrefix) {
 695  0
         if (CollectionUtils.isEmpty(documentStatuses) && CollectionUtils.isEmpty(categories)) {
 696  0
             return whereClausePredicatePrefix + "DOC_HDR.DOC_HDR_STAT_CD != '" + DocumentStatus.INITIATED.getCode() + "'";
 697  
         } else {
 698  
             // include all given document statuses
 699  0
             Set<DocumentStatus> statusesToInclude = new HashSet<DocumentStatus>(documentStatuses);
 700  
 
 701  
             // add all statuses from each category
 702  0
             for (DocumentStatusCategory category : categories) {
 703  0
                 Set<DocumentStatus> categoryStatuses = DocumentStatus.getStatusesForCategory(category);
 704  0
                 statusesToInclude.addAll(categoryStatuses);
 705  0
             }
 706  
 
 707  0
             Set<String> statusCodes = new HashSet<String>();
 708  0
             for (DocumentStatus statusToInclude : statusesToInclude) {
 709  0
                 statusCodes.add("'" + getDbPlatform().escapeString(statusToInclude.getCode()) + "'");
 710  
             }
 711  0
             return whereClausePredicatePrefix + " DOC_HDR.DOC_HDR_STAT_CD in (" + StringUtils.join(statusCodes, ", ") +")";
 712  
         }
 713  
     }
 714  
 
 715  
     /**
 716  
      * This method generates the where clause fragment related to Application Document Status.
 717  
      * If the Status value only is defined, search for the appDocStatus value in the route header.
 718  
      * If either the transition from/to dates are defined, search agains the status transition history.
 719  
      */
 720  
     public String getAppDocStatusSql(String appDocStatus, String whereClausePredicatePrefix, int statusTransitionWhereClauseLength) {
 721  0
         if (StringUtils.isBlank(appDocStatus)) {
 722  0
             return "";
 723  
         } else {
 724  0
                 if (statusTransitionWhereClauseLength > 0){
 725  0
                         return whereClausePredicatePrefix + " STAT_TRAN.APP_DOC_STAT_TO = '" + getDbPlatform().escapeString(appDocStatus.trim()) + "'";
 726  
                 }else{
 727  0
                         return whereClausePredicatePrefix + " DOC_HDR.APP_DOC_STAT = '" + getDbPlatform().escapeString(appDocStatus.trim()) + "'";
 728  
                 }
 729  
         }
 730  
     }
 731  
 
 732  
     public String getGeneratedPredicatePrefix(int whereClauseSize) {
 733  0
         return (whereClauseSize > 0) ? " and " : " where ";
 734  
     }
 735  
 
 736  
     public String establishDateString(DateTime fromDate, DateTime toDate, String tableName, String tableAlias, String colName, String whereStatementClause) {
 737  
 
 738  0
         String fromDateValue = null;
 739  0
         if (fromDate != null) {
 740  0
             fromDateValue = CoreApiServiceLocator.getDateTimeService().toDateString(fromDate.toDate());
 741  
         }
 742  
 
 743  0
         String toDateValue = null;
 744  0
         if (toDate != null) {
 745  0
             toDateValue = CoreApiServiceLocator.getDateTimeService().toDateString(toDate.toDate());
 746  0
             toDateValue += " 23:59:59";
 747  
         }
 748  
 
 749  0
         String searchValue = null;
 750  0
         if (fromDateValue != null && toDateValue != null) {
 751  0
             searchValue = fromDateValue + " .. " + toDateValue;
 752  0
         } else if (fromDateValue != null) {
 753  0
             searchValue = ">= " + fromDateValue;
 754  0
         } else if (toDateValue != null) {
 755  0
             searchValue = "<= " + toDateValue;
 756  
         } else {
 757  0
             return "";
 758  
         }
 759  
 
 760  0
         Criteria crit = getSqlBuilder().createCriteria(colName, searchValue, tableName, tableAlias, java.sql.Date.class, true, true);
 761  0
         return new StringBuilder(whereStatementClause).append(crit.buildWhere()).toString();
 762  
 
 763  
     }
 764  
 
 765  
     public DatabasePlatform getDbPlatform() {
 766  0
         if (dbPlatform == null) {
 767  0
             dbPlatform = (DatabasePlatform) GlobalResourceLoader.getService(RiceConstants.DB_PLATFORM);
 768  
         }
 769  0
         return dbPlatform;
 770  
     }
 771  
 
 772  
     public SqlBuilder getSqlBuilder() {
 773  0
         if(sqlBuilder == null){
 774  0
             sqlBuilder = new SqlBuilder();
 775  0
             sqlBuilder.setDbPlatform(getDbPlatform());
 776  0
             sqlBuilder.setDateTimeService(CoreApiServiceLocator.getDateTimeService());
 777  
         }
 778  0
         return this.sqlBuilder;
 779  
     }
 780  
 
 781  
     public void setSqlBuilder(SqlBuilder sqlBuilder) {
 782  0
         this.sqlBuilder = sqlBuilder;
 783  0
     }
 784  
 
 785  
     /**
 786  
      * A helper method for determining whether any searchable attributes are in use for the search.
 787  
      *
 788  
      * @return True if the search criteria contains at least one searchable attribute or the criteria's doc type name is
 789  
      * non-blank; false otherwise.
 790  
      */
 791  
     protected boolean isUsingAtLeastOneSearchAttribute(DocumentSearchCriteria criteria) {
 792  0
         return criteria.getDocumentAttributeValues().size() > 0 || StringUtils.isNotBlank(criteria.getDocumentTypeName());
 793  
     }
 794  
 
 795  
 }