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