View Javadoc

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.docsearch.dao.impl;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.uif.RemotableAttributeField;
20  import org.kuali.rice.core.framework.services.CoreFrameworkServiceLocator;
21  import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
22  import org.kuali.rice.kew.api.document.search.DocumentSearchResults;
23  import org.kuali.rice.kew.impl.document.search.DocumentSearchGenerator;
24  import org.kuali.rice.kew.docsearch.dao.DocumentSearchDAO;
25  import org.kuali.rice.kew.api.KewApiConstants;
26  import org.kuali.rice.kew.util.PerformanceLogger;
27  import org.kuali.rice.krad.util.KRADConstants;
28  import org.springframework.dao.DataAccessException;
29  import org.springframework.jdbc.core.ConnectionCallback;
30  import org.springframework.jdbc.core.JdbcTemplate;
31  import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
32  
33  import javax.sql.DataSource;
34  import java.sql.Connection;
35  import java.sql.ResultSet;
36  import java.sql.SQLException;
37  import java.sql.Statement;
38  import java.util.List;
39  
40  /**
41   * Spring JdbcTemplate implementation of DocumentSearchDAO
42   *
43   * @author Kuali Rice Team (rice.collab@kuali.org)
44   *
45   */
46  public class DocumentSearchDAOJdbcImpl implements DocumentSearchDAO {
47  
48      public static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentSearchDAOJdbcImpl.class);
49      private static final int DEFAULT_FETCH_MORE_ITERATION_LIMIT = 10;
50      
51      private DataSource dataSource;
52  
53      public void setDataSource(DataSource dataSource) {
54          this.dataSource = new TransactionAwareDataSourceProxy(dataSource);
55      }
56  
57      @Override
58      public DocumentSearchResults.Builder findDocuments(final DocumentSearchGenerator documentSearchGenerator, final DocumentSearchCriteria criteria, final boolean criteriaModified, final List<RemotableAttributeField> searchFields) {
59          final int maxResultCap = getMaxResultCap(criteria);
60          try {
61              final JdbcTemplate template = new JdbcTemplate(dataSource);
62  
63              return template.execute(new ConnectionCallback<DocumentSearchResults.Builder>() {
64                  @Override
65                  public DocumentSearchResults.Builder doInConnection(final Connection con) throws SQLException {
66                      final Statement statement = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
67                      try {
68                          final int fetchIterationLimit = getFetchMoreIterationLimit();
69                          final int fetchLimit = fetchIterationLimit * maxResultCap;
70                          statement.setFetchSize(maxResultCap + 1);
71                          statement.setMaxRows(fetchLimit + 1);
72  
73                          PerformanceLogger perfLog = new PerformanceLogger();
74                          String sql = documentSearchGenerator.generateSearchSql(criteria, searchFields);
75                          perfLog.log("Time to generate search sql from documentSearchGenerator class: " + documentSearchGenerator
76                                  .getClass().getName(), true);
77                          LOG.info("Executing document search with statement max rows: " + statement.getMaxRows());
78                          LOG.info("Executing document search with statement fetch size: " + statement.getFetchSize());
79                          perfLog = new PerformanceLogger();
80                          final ResultSet rs = statement.executeQuery(sql);
81                          try {
82                              perfLog.log("Time to execute doc search database query.", true);
83                              final Statement searchAttributeStatement = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
84                              try {
85                             		return documentSearchGenerator.processResultSet(criteria, criteriaModified, searchAttributeStatement, rs, maxResultCap, fetchLimit);
86                              } finally {
87                                  try {
88                                      searchAttributeStatement.close();
89                                  } catch (SQLException e) {
90                                      LOG.warn("Could not close search attribute statement.");
91                                  }
92                              }
93                          } finally {
94                              try {
95                                  rs.close();
96                              } catch (SQLException e) {
97                                  LOG.warn("Could not close result set.");
98                              }
99                          }
100                     } finally {
101                         try {
102                             statement.close();
103                         } catch (SQLException e) {
104                             LOG.warn("Could not close statement.");
105                         }
106                     }
107                 }
108             });
109 
110         } catch (DataAccessException dae) {
111             String errorMsg = "DataAccessException: " + dae.getMessage();
112             LOG.error("getList() " + errorMsg, dae);
113             throw new RuntimeException(errorMsg, dae);
114         } catch (Exception e) {
115             String errorMsg = "LookupException: " + e.getMessage();
116             LOG.error("getList() " + errorMsg, e);
117             throw new RuntimeException(errorMsg, e);
118         }
119     }
120 
121     /**
122      * Returns the maximum number of results that should be returned from the document search.
123      *
124      * @param criteria the criteria in which to check for a max results value
125      * @return the maximum number of results that should be returned from a document search
126      */
127     protected int getMaxResultCap(DocumentSearchCriteria criteria) {
128         int maxResults = KewApiConstants.DOCUMENT_LOOKUP_DEFAULT_RESULT_CAP;
129         if (criteria.getMaxResults() != null) {
130             maxResults = criteria.getMaxResults().intValue();
131         }
132         String resultCapValue = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.DOCUMENT_SEARCH_DETAIL_TYPE, KewApiConstants.DOC_SEARCH_RESULT_CAP);
133         if (StringUtils.isNotBlank(resultCapValue)) {
134             try {
135                 Integer maxResultCap = Integer.parseInt(resultCapValue);
136                 if (maxResults > maxResultCap) {
137                     LOG.warn("Result set cap of " + maxResults + " is greater than parameter " + KewApiConstants.DOC_SEARCH_RESULT_CAP + " value of " + maxResultCap);
138                     maxResults = maxResultCap;
139                 } else if (maxResultCap <= 0) {
140                     LOG.warn(KewApiConstants.DOC_SEARCH_RESULT_CAP + " was less than or equal to zero.  Please use a positive integer.");
141                 }
142             } catch (NumberFormatException e) {
143                 LOG.warn(KewApiConstants.DOC_SEARCH_RESULT_CAP + " is not a valid number.  Value was " + resultCapValue);
144             }
145         }
146         return maxResults;
147     }
148 
149     protected int getFetchMoreIterationLimit() {
150         int fetchMoreLimit = DEFAULT_FETCH_MORE_ITERATION_LIMIT;
151         String fetchMoreLimitValue = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.DOCUMENT_SEARCH_DETAIL_TYPE, KewApiConstants.DOC_SEARCH_FETCH_MORE_ITERATION_LIMIT);
152         if (!StringUtils.isBlank(fetchMoreLimitValue)) {
153             try {
154                 fetchMoreLimit = Integer.parseInt(fetchMoreLimitValue);
155                 if (fetchMoreLimit < 0) {
156                     LOG.warn(KewApiConstants.DOC_SEARCH_FETCH_MORE_ITERATION_LIMIT + " was less than zero.  Please use a value greater than or equal to zero.");
157                     fetchMoreLimit = DEFAULT_FETCH_MORE_ITERATION_LIMIT;
158                 }
159             } catch (NumberFormatException e) {
160                 LOG.warn(KewApiConstants.DOC_SEARCH_FETCH_MORE_ITERATION_LIMIT + " is not a valid number.  Value was " + fetchMoreLimitValue);
161             }
162         }
163         return fetchMoreLimit;
164     }
165 
166 }