1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
42
43
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
123
124
125
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 }