001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.kew.routeheader.dao.impl; 017 018import org.apache.commons.lang.StringUtils; 019import org.apache.commons.lang.exception.ExceptionUtils; 020import org.apache.ojb.broker.OptimisticLockException; 021import org.apache.ojb.broker.PersistenceBroker; 022import org.apache.ojb.broker.accesslayer.LookupException; 023import org.apache.ojb.broker.query.Criteria; 024import org.apache.ojb.broker.query.QueryByCriteria; 025import org.apache.ojb.broker.query.QueryFactory; 026import org.apache.ojb.broker.query.ReportQueryByCriteria; 027import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; 028import org.kuali.rice.core.api.util.RiceConstants; 029import org.kuali.rice.core.framework.persistence.platform.DatabasePlatform; 030import org.kuali.rice.kew.actionitem.ActionItem; 031import org.kuali.rice.kew.actionlist.service.ActionListService; 032import org.kuali.rice.kew.api.WorkflowRuntimeException; 033import org.kuali.rice.kew.api.action.ActionRequestStatus; 034import org.kuali.rice.kew.api.exception.LockingException; 035import org.kuali.rice.kew.docsearch.SearchableAttributeValue; 036import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue; 037import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValueContent; 038import org.kuali.rice.kew.routeheader.dao.DocumentRouteHeaderDAO; 039import org.kuali.rice.kew.service.KEWServiceLocator; 040import org.springframework.dao.CannotAcquireLockException; 041import org.springmodules.orm.ojb.OjbFactoryUtils; 042import org.springmodules.orm.ojb.PersistenceBrokerCallback; 043import org.springmodules.orm.ojb.support.PersistenceBrokerDaoSupport; 044 045import java.sql.Connection; 046import java.sql.PreparedStatement; 047import java.sql.ResultSet; 048import java.sql.SQLException; 049import java.sql.Statement; 050import java.util.ArrayList; 051import java.util.Collection; 052import java.util.Iterator; 053import java.util.List; 054import java.util.Set; 055 056public class DocumentRouteHeaderDAOOjbImpl extends PersistenceBrokerDaoSupport implements DocumentRouteHeaderDAO { 057 058 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentRouteHeaderDAOOjbImpl.class); 059 060 public void saveRouteHeader(DocumentRouteHeaderValue routeHeader) { 061 if ( LOG.isDebugEnabled() ) { 062 LOG.debug( "About to Save the route Header: " + routeHeader.getDocumentId() + " / version=" + routeHeader.getVersionNumber() ); 063 DocumentRouteHeaderValue currHeader = findRouteHeader(routeHeader.getDocumentId()); 064 if ( currHeader != null ) { 065 LOG.debug( "Current Header Version: " + currHeader.getVersionNumber() ); 066// for ( SearchableAttributeValue s : currHeader.get() ) { 067// LOG.debug( "SA: " + s.getSearchableAttributeValueId() + " / version=" + s.get ) 068// } 069 } else { 070 LOG.debug( "Current Header: null" ); 071 } 072 LOG.debug( ExceptionUtils.getStackTrace(new Throwable()) ); 073 } 074 try { 075 getPersistenceBrokerTemplate().store(routeHeader); 076 routeHeader.getDocumentContent().setDocumentId(routeHeader.getDocumentId()); 077 getPersistenceBrokerTemplate().store(routeHeader.getDocumentContent()); 078 } catch ( RuntimeException ex ) { 079 if ( ex.getCause() instanceof OptimisticLockException ) { 080 LOG.error( "Optimistic Locking Exception saving document header or content. Offending object: " + ((OptimisticLockException)ex.getCause()).getSourceObject() 081 + "; DocumentId = " + routeHeader.getDocumentId() + " ; Version Number = " + routeHeader.getVersionNumber()); 082 } 083 LOG.error( "Unable to save document header or content. Route Header: " + routeHeader, ex ); 084 throw ex; 085 } 086 } 087 088 public DocumentRouteHeaderValueContent getContent(String documentId) { 089 Criteria crit = new Criteria(); 090 crit.addEqualTo("documentId", documentId); 091 return (DocumentRouteHeaderValueContent)this.getPersistenceBrokerTemplate().getObjectByQuery(new QueryByCriteria(DocumentRouteHeaderValueContent.class, crit)); 092 } 093 094 public void clearRouteHeaderSearchValues(String documentId) { 095 Criteria crit = new Criteria(); 096 crit.addEqualTo("documentId", documentId); 097 QueryByCriteria query = new QueryByCriteria(SearchableAttributeValue.class, crit); 098 query.addOrderByAscending("searchableAttributeValueId"); 099 Collection<SearchableAttributeValue> results = this.getPersistenceBrokerTemplate().getCollectionByQuery(query); 100 if (!results.isEmpty()) { 101 for (SearchableAttributeValue srchAttrVal: results) { 102 this.getPersistenceBrokerTemplate().delete(srchAttrVal); 103 } 104 } 105 } 106 107 public Collection<SearchableAttributeValue> findSearchableAttributeValues(String documentId) { 108 Criteria crit = new Criteria(); 109 crit.addEqualTo("documentId", documentId); 110 QueryByCriteria query = new QueryByCriteria(SearchableAttributeValue.class, crit); 111 query.addOrderByAscending("searchableAttributeValueId"); 112 return this.getPersistenceBrokerTemplate().getCollectionByQuery(query); 113 } 114 115 public void lockRouteHeader(final String documentId, final boolean wait) { 116 117 /* 118 * String sql = (wait ? LOCK_SQL_WAIT : LOCK_SQL_NOWAIT); try { getJdbcTemplate().update(sql, new Object[] { documentId }); } catch (CannotAcquireLockException e) { throw new LockingException("Could not aquire lock on document, documentId=" + documentId, e); } 119 */ 120 121 this.getPersistenceBrokerTemplate().execute(new PersistenceBrokerCallback() { 122 public Object doInPersistenceBroker(PersistenceBroker broker) { 123 PreparedStatement statement = null; 124 try { 125 Connection connection = broker.serviceConnectionManager().getConnection(); 126 String sql = getPlatform().getLockRouteHeaderQuerySQL(documentId, wait); 127 statement = connection.prepareStatement(sql); 128 statement.setString(1, documentId); 129 statement.execute(); 130 return null; 131 } catch (SQLException e) { 132 throw new LockingException("Could not aquire lock on document, documentId=" + documentId, e); 133 } catch (LookupException e) { 134 throw new LockingException("Could not aquire lock on document, documentId=" + documentId, e); 135 } catch (CannotAcquireLockException e) { 136 throw new LockingException("Could not aquire lock on document, documentId=" + documentId, e); 137 } finally { 138 if (statement != null) { 139 try { 140 statement.close(); 141 } catch (SQLException e) { 142 } 143 } 144 } 145 } 146 }); 147 148 } 149 150 public DocumentRouteHeaderValue findRouteHeader(String documentId) { 151 return findRouteHeader(documentId, false); 152 } 153 154 public DocumentRouteHeaderValue findRouteHeader(String documentId, boolean clearCache) { 155 Criteria crit = new Criteria(); 156 crit.addEqualTo("documentId", documentId); 157 if (clearCache) { 158 this.getPersistenceBrokerTemplate().clearCache(); 159 } 160 return (DocumentRouteHeaderValue) this.getPersistenceBrokerTemplate().getObjectByQuery(new QueryByCriteria(DocumentRouteHeaderValue.class, crit)); 161 } 162 163 public Collection<DocumentRouteHeaderValue> findRouteHeaders(Collection<String> documentIds) { 164 return findRouteHeaders(documentIds, false); 165 } 166 167 public Collection<DocumentRouteHeaderValue> findRouteHeaders(Collection<String> documentIds, boolean clearCache) { 168 if (documentIds == null || documentIds.isEmpty()) { 169 return null; 170 } 171 Criteria crit = new Criteria(); 172 crit.addIn("documentId", documentIds); 173 if (clearCache) { 174 this.getPersistenceBrokerTemplate().clearCache(); 175 } 176 return (Collection<DocumentRouteHeaderValue>) this.getPersistenceBrokerTemplate().getCollectionByQuery(new QueryByCriteria(DocumentRouteHeaderValue.class, crit)); 177 } 178 179 public void deleteRouteHeader(DocumentRouteHeaderValue routeHeader) { 180 this.getPersistenceBrokerTemplate().delete(routeHeader); 181 } 182 183 public String getNextDocumentId() { 184 return (String)this.getPersistenceBrokerTemplate().execute(new PersistenceBrokerCallback() { 185 public Object doInPersistenceBroker(PersistenceBroker broker) { 186 return getPlatform().getNextValSQL("KREW_DOC_HDR_S", broker).toString(); 187 } 188 }); 189 } 190 191 protected DatabasePlatform getPlatform() { 192 return (DatabasePlatform)GlobalResourceLoader.getService(RiceConstants.DB_PLATFORM); 193 } 194 195 public Collection<String> findPendingByResponsibilityIds(Set<String> responsibilityIds) { 196 Collection<String> documentIds = new ArrayList(); 197 if (responsibilityIds.isEmpty()) { 198 return documentIds; 199 } 200 PersistenceBroker broker = null; 201 Connection conn = null; 202 Statement statement = null; 203 ResultSet rs = null; 204 try { 205 broker = getPersistenceBroker(false); 206 conn = broker.serviceConnectionManager().getConnection(); 207 String respIds = "('"; 208 int index = 0; 209 for (String responsibilityId : responsibilityIds) { 210 respIds += responsibilityId + (index == responsibilityIds.size()-1 ? "" : "','"); 211 index++; 212 } 213 respIds += "')"; 214 String query = "SELECT DISTINCT(doc_hdr_id) FROM KREW_ACTN_RQST_T "+ 215 "WHERE (STAT_CD='" + 216 ActionRequestStatus.INITIALIZED.getCode()+ 217 "' OR STAT_CD='"+ 218 ActionRequestStatus.ACTIVATED.getCode()+ 219 "') AND RSP_ID IN "+respIds; 220 LOG.debug("Query to find pending documents for requeue: " + query); 221 statement = conn.createStatement(); 222 rs = statement.executeQuery(query); 223 while (rs.next()) { 224 documentIds.add(rs.getString(1)); 225 } 226 } catch (SQLException sqle) { 227 LOG.error("SQLException: " + sqle.getMessage(), sqle); 228 throw new WorkflowRuntimeException(sqle); 229 } catch (LookupException le) { 230 LOG.error("LookupException: " + le.getMessage(), le); 231 throw new WorkflowRuntimeException(le); 232 } finally { 233 if (rs != null) { 234 try { 235 rs.close(); 236 } catch (SQLException e) { 237 LOG.warn("Could not close result set."); 238 } 239 } 240 if (statement != null) { 241 try { 242 statement.close(); 243 } catch (SQLException e) { 244 LOG.warn("Could not close statement."); 245 } 246 } 247 try { 248 if (broker != null) { 249 OjbFactoryUtils.releasePersistenceBroker(broker, this.getPersistenceBrokerTemplate().getPbKey()); 250 } 251 } catch (Exception e) { 252 LOG.error("Failed closing connection: " + e.getMessage(), e); 253 } 254 } 255 return documentIds; 256 } 257 258 public boolean hasSearchableAttributeValue(String documentId, String searchableAttributeKey, String searchableAttributeValue) { 259 Criteria crit = new Criteria(); 260 crit.addEqualTo("documentId", documentId); 261 crit.addEqualTo("searchableAttributeKey", searchableAttributeKey); 262 Collection results = getPersistenceBrokerTemplate().getCollectionByQuery(new QueryByCriteria(SearchableAttributeValue.class, crit)); 263 if (!results.isEmpty()) { 264 for (Iterator iterator = results.iterator(); iterator.hasNext();) { 265 SearchableAttributeValue attribute = (SearchableAttributeValue) iterator.next(); 266 if (StringUtils.equals(attribute.getSearchableAttributeDisplayValue(), searchableAttributeValue)) { 267 return true; 268 } 269 } 270 } 271 return false; 272 } 273 274 public String getApplicationIdByDocumentId(String documentId) { 275 if (documentId == null) { 276 throw new IllegalArgumentException("Encountered a null document ID."); 277 } 278 String applicationId = null; 279 PersistenceBroker broker = null; 280 Connection conn = null; 281 PreparedStatement statement = null; 282 ResultSet rs = null; 283 try { 284 broker = this.getPersistenceBroker(false); 285 conn = broker.serviceConnectionManager().getConnection(); 286 String query = "SELECT DT.APPL_ID FROM KREW_DOC_TYP_T DT, KREW_DOC_HDR_T DH "+ 287 "WHERE DH.DOC_TYP_ID=DT.DOC_TYP_ID AND "+ 288 "DH.DOC_HDR_ID=?"; 289 statement = conn.prepareStatement(query); 290 statement.setString(1, documentId); 291 rs = statement.executeQuery(); 292 if (rs.next()) { 293 applicationId = rs.getString(1); 294 if (rs.wasNull()) { 295 applicationId = null; 296 } 297 } 298 } catch (SQLException sqle) { 299 LOG.error("SQLException: " + sqle.getMessage(), sqle); 300 throw new WorkflowRuntimeException(sqle); 301 } catch (LookupException le) { 302 LOG.error("LookupException: " + le.getMessage(), le); 303 throw new WorkflowRuntimeException(le); 304 } finally { 305 if (rs != null) { 306 try { 307 rs.close(); 308 } catch (SQLException e) { 309 LOG.warn("Could not close result set."); 310 } 311 } 312 if (statement != null) { 313 try { 314 statement.close(); 315 } catch (SQLException e) { 316 LOG.warn("Could not close statement."); 317 } 318 } 319 try { 320 if (broker != null) { 321 OjbFactoryUtils.releasePersistenceBroker(broker, this.getPersistenceBrokerTemplate().getPbKey()); 322 } 323 } catch (Exception e) { 324 LOG.error("Failed closing connection: " + e.getMessage(), e); 325 } 326 } 327 return applicationId; 328 } 329 330 public String getDocumentStatus(String documentId) { 331 Criteria crit = new Criteria(); 332 crit.addEqualTo("documentId", documentId); 333 ReportQueryByCriteria query = QueryFactory.newReportQuery(DocumentRouteHeaderValue.class, crit); 334 query.setAttributes(new String[] { "docRouteStatus" }); 335 String status = null; 336 Iterator iter = getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(query); 337 while (iter.hasNext()) { 338 Object[] row = (Object[]) iter.next(); 339 status = (String)row[0]; 340 } 341 return status; 342 } 343 344 public String getAppDocId(String documentId) { 345 Criteria crit = new Criteria(); 346 crit.addEqualTo("documentId", documentId); 347 ReportQueryByCriteria query = QueryFactory.newReportQuery(DocumentRouteHeaderValue.class, crit); 348 query.setAttributes(new String[] { "appDocId" }); 349 String appDocId = null; 350 Iterator iter = getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(query); 351 while (iter.hasNext()) { 352 Object[] row = (Object[]) iter.next(); 353 appDocId = (String)row[0]; 354 } 355 return appDocId; 356 } 357 358 public String getAppDocStatus(String documentId) { 359 Criteria crit = new Criteria(); 360 crit.addEqualTo("documentId", documentId); 361 ReportQueryByCriteria query = QueryFactory.newReportQuery(DocumentRouteHeaderValue.class, crit); 362 query.setAttributes(new String[] { "appDocStatus" }); 363 String appDocStatus = null; 364 Iterator iter = getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(query); 365 while (iter.hasNext()) { 366 Object[] row = (Object[]) iter.next(); 367 appDocStatus = (String)row[0]; 368 } 369 return appDocStatus; 370 } 371 372 public void save(SearchableAttributeValue searchableAttributeValue) { 373 getPersistenceBrokerTemplate().store(searchableAttributeValue); 374 } 375 376 public Collection findByDocTypeAndAppId(String documentTypeName, 377 String appId) { 378 Collection documentIds = new ArrayList(); 379 380 PersistenceBroker broker = null; 381 Connection conn = null; 382 ResultSet rs = null; 383 try { 384 broker = getPersistenceBroker(false); 385 conn = broker.serviceConnectionManager().getConnection(); 386 387 String query = 388 "SELECT DISTINCT " + 389 " (docHdr.doc_hdr_id) " + 390 "FROM " + 391 " KREW_DOC_HDR_T docHdr, " + 392 " KREW_DOC_TYP_T docTyp " + 393 "WHERE " + 394 " docHdr.APP_DOC_ID = ? " + 395 " AND docHdr.DOC_TYP_ID = docTyp.DOC_TYP_ID " + 396 " AND docTyp.DOC_TYP_NM = ?"; 397 398 LOG.debug("Query to find documents by app id: " + query); 399 400 PreparedStatement stmt = conn.prepareStatement(query); 401 stmt.setString(1, appId); 402 stmt.setString(2, documentTypeName); 403 rs = stmt.executeQuery(); 404 405 while (rs.next()) { 406 documentIds.add(new String(rs.getString(1))); 407 } 408 rs.close(); 409 } catch (SQLException sqle) { 410 LOG.error("SQLException: " + sqle.getMessage(), sqle); 411 throw new WorkflowRuntimeException(sqle); 412 } catch (LookupException le) { 413 LOG.error("LookupException: " + le.getMessage(), le); 414 throw new WorkflowRuntimeException(le); 415 } finally { 416 try { 417 if (broker != null) { 418 OjbFactoryUtils.releasePersistenceBroker(broker, this.getPersistenceBrokerTemplate().getPbKey()); 419 } 420 } catch (Exception e) { 421 LOG.error("Failed closing connection: " + e.getMessage(), e); 422 } 423 } 424 return documentIds; 425 } 426 427}