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.routeheader.dao.impl;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.commons.lang.exception.ExceptionUtils;
20  import org.apache.ojb.broker.OptimisticLockException;
21  import org.apache.ojb.broker.PersistenceBroker;
22  import org.apache.ojb.broker.accesslayer.LookupException;
23  import org.apache.ojb.broker.query.Criteria;
24  import org.apache.ojb.broker.query.QueryByCriteria;
25  import org.apache.ojb.broker.query.QueryFactory;
26  import org.apache.ojb.broker.query.ReportQueryByCriteria;
27  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
28  import org.kuali.rice.core.api.util.RiceConstants;
29  import org.kuali.rice.core.framework.persistence.platform.DatabasePlatform;
30  import org.kuali.rice.kew.actionitem.ActionItem;
31  import org.kuali.rice.kew.actionlist.service.ActionListService;
32  import org.kuali.rice.kew.api.WorkflowRuntimeException;
33  import org.kuali.rice.kew.api.action.ActionRequestStatus;
34  import org.kuali.rice.kew.api.exception.LockingException;
35  import org.kuali.rice.kew.docsearch.SearchableAttributeValue;
36  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
37  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValueContent;
38  import org.kuali.rice.kew.routeheader.dao.DocumentRouteHeaderDAO;
39  import org.kuali.rice.kew.service.KEWServiceLocator;
40  import org.springframework.dao.CannotAcquireLockException;
41  import org.springmodules.orm.ojb.OjbFactoryUtils;
42  import org.springmodules.orm.ojb.PersistenceBrokerCallback;
43  import org.springmodules.orm.ojb.support.PersistenceBrokerDaoSupport;
44  
45  import java.sql.Connection;
46  import java.sql.PreparedStatement;
47  import java.sql.ResultSet;
48  import java.sql.SQLException;
49  import java.sql.Statement;
50  import java.util.ArrayList;
51  import java.util.Collection;
52  import java.util.Iterator;
53  import java.util.Set;
54  
55  public class DocumentRouteHeaderDAOOjbImpl extends PersistenceBrokerDaoSupport implements DocumentRouteHeaderDAO {
56  
57      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentRouteHeaderDAOOjbImpl.class);
58  
59      public void saveRouteHeader(DocumentRouteHeaderValue routeHeader) {
60          if ( LOG.isDebugEnabled() ) {
61              LOG.debug( "About to Save the route Header: " + routeHeader.getDocumentId() + " / version=" + routeHeader.getVersionNumber() );
62              DocumentRouteHeaderValue currHeader = findRouteHeader(routeHeader.getDocumentId());
63              if ( currHeader != null ) {
64                  LOG.debug( "Current Header Version: " + currHeader.getVersionNumber() );
65  //                for ( SearchableAttributeValue s : currHeader.get() ) {
66  //                    LOG.debug( "SA: " + s.getSearchableAttributeValueId() + " / version=" + s.get )
67  //                }
68              } else {
69                  LOG.debug( "Current Header: null" );
70              }
71              LOG.debug( ExceptionUtils.getStackTrace(new Throwable()) );
72          }
73          try {
74              getPersistenceBrokerTemplate().store(routeHeader);
75              routeHeader.getDocumentContent().setDocumentId(routeHeader.getDocumentId());
76              getPersistenceBrokerTemplate().store(routeHeader.getDocumentContent());
77          } catch ( RuntimeException ex ) {
78              if ( ex.getCause() instanceof OptimisticLockException ) {
79                   LOG.error( "Optimistic Locking Exception saving document header or content. Offending object: " + ((OptimisticLockException)ex.getCause()).getSourceObject() 
80                   + "; DocumentId = " + routeHeader.getDocumentId() + " ;  Version Number = " + routeHeader.getVersionNumber());
81              }
82              LOG.error( "Unable to save document header or content. Route Header: " + routeHeader, ex );
83              throw ex;
84          }
85      }
86  
87      public DocumentRouteHeaderValueContent getContent(String documentId) {
88      	Criteria crit = new Criteria();
89          crit.addEqualTo("documentId", documentId);
90          return (DocumentRouteHeaderValueContent)this.getPersistenceBrokerTemplate().getObjectByQuery(new QueryByCriteria(DocumentRouteHeaderValueContent.class, crit));
91      }
92  
93      public void clearRouteHeaderSearchValues(String documentId) {
94          Criteria crit = new Criteria();
95          crit.addEqualTo("documentId", documentId);
96          QueryByCriteria query = new QueryByCriteria(SearchableAttributeValue.class, crit);
97          query.addOrderByAscending("searchableAttributeValueId");
98          Collection<SearchableAttributeValue> results = this.getPersistenceBrokerTemplate().getCollectionByQuery(query);
99          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 }