View Javadoc

1   /**
2    * Copyright 2005-2012 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.actionlist.dao.impl;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.delegation.DelegationType;
20  import org.kuali.rice.core.framework.persistence.jpa.OrmUtils;
21  import org.kuali.rice.core.framework.persistence.jpa.criteria.Criteria;
22  import org.kuali.rice.core.framework.persistence.jpa.criteria.QueryByCriteria;
23  import org.kuali.rice.kew.actionitem.ActionItem;
24  import org.kuali.rice.kew.actionitem.ActionItemActionListExtension;
25  import org.kuali.rice.kew.actionitem.OutboxItemActionListExtension;
26  import org.kuali.rice.kew.actionlist.ActionListFilter;
27  import org.kuali.rice.kew.actionlist.dao.ActionListDAO;
28  import org.kuali.rice.kew.doctype.bo.DocumentType;
29  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
30  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValueActionListExtension;
31  import org.kuali.rice.kew.service.KEWServiceLocator;
32  import org.kuali.rice.kew.api.KewApiConstants;
33  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
34  
35  import javax.persistence.EntityManager;
36  import javax.persistence.PersistenceContext;
37  import java.sql.Timestamp;
38  import java.util.ArrayList;
39  import java.util.Calendar;
40  import java.util.Collection;
41  import java.util.Date;
42  import java.util.HashMap;
43  import java.util.Iterator;
44  import java.util.List;
45  import java.util.Map;
46  
47  /**
48   * OJB implementation of the {@link ActionListDAO}.
49   *
50   * @author Kuali Rice Team (rice.collab@kuali.org)
51   */
52  public class ActionListDAOJpaImpl implements ActionListDAO {
53  
54      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ActionListDAOJpaImpl.class);
55  	
56      @PersistenceContext(unitName="kew-unit")
57  	private EntityManager entityManager;
58  	
59      public Collection<ActionItem> getActionList(String principalId, ActionListFilter filter) {
60          return toActionItemActionListExtensions(getActionItemsInActionList(ActionItem.class, principalId, filter));
61      }
62      
63      /**
64  	 * This method ...
65  	 * 
66  	 * @param actionItems
67  	 * @return actionItemActionListExtensions
68  	 */
69  	private Collection<ActionItem> toActionItemActionListExtensions(
70  			Collection<ActionItem> actionItems) {
71  		List<ActionItem> actionItemActionListExtensions = new ArrayList<ActionItem>();
72  		for(ActionItem actionItem:actionItems){
73  			actionItemActionListExtensions.add(toActionItemActionListExtension(actionItem));
74  		}
75  		return actionItemActionListExtensions;
76  	}
77  
78  	/**
79  	 * This method ...
80  	 * 
81  	 * @param actionItem
82  	 * @return
83  	 */
84  	private ActionItemActionListExtension toActionItemActionListExtension(
85  			ActionItem actionItem) {
86  
87  		if(actionItem==null){
88  			return null;
89  		}
90  		
91  		ActionItemActionListExtension actionItemExt = new ActionItemActionListExtension();
92  		
93  		actionItemExt.setId(actionItem.getId());
94  		actionItemExt.setPrincipalId(actionItem.getPrincipalId());
95  		actionItemExt.setDateAssigned(actionItem.getDateAssigned());
96  		actionItemExt.setActionRequestCd(actionItem.getActionRequestCd());
97  		actionItemExt.setActionRequestId(actionItem.getActionRequestId());
98  		actionItemExt.setDocumentId(actionItem.getDocumentId());
99  		actionItemExt.setResponsibilityId(actionItem.getResponsibilityId());
100 		actionItemExt.setGroupId(actionItem.getGroupId());
101 		actionItemExt.setRoleName(actionItem.getRoleName());
102 		actionItemExt.setDocTitle(actionItem.getDocTitle());
103 		actionItemExt.setDocLabel(actionItem.getDocLabel());
104 		actionItemExt.setDocHandlerURL(actionItem.getDocHandlerURL());
105 		actionItemExt.setDocName(actionItem.getDocName());
106 		actionItemExt.setDelegatorPrincipalId(actionItem.getDelegatorPrincipalId());
107 		actionItemExt.setDelegatorGroupId(actionItem.getDelegatorGroupId());
108 		actionItemExt.setDelegationType(actionItem.getDelegationType());
109 		actionItemExt.setLockVerNbr(actionItem.getLockVerNbr());
110 		actionItemExt.setDocumentId(actionItem.getDocumentId());
111 		actionItemExt.setRequestLabel(actionItem.getRequestLabel());
112 		//actionItemExt.setRouteHeader(toDocumentRouteHeaderValueActionListExtension(actionItem.getRouteHeader()));
113 		
114 		// These properties are not mapped in OJB-repository-kew.xml
115 		// actionItemExt.setActionItemIndex(actionItem.getActionItemIndex());
116 		// actionItemExt.setActionToTake(actionItem.getActionToTake());
117 		// actionItemExt.setCustomActions(actionItem.getCustomActions());
118 		// actionItemExt.setDateAssignedString(actionItem.getDateAssignedString());
119 		// actionItemExt.setDelegatorGroup();
120 		// actionItemExt.setDisplayParameters();
121 		// FIXME this causes null pointer - actionItemExt.setGroup(actionItem.getGroup());
122 		// actionItemExt.setLastApprovedDate(actionItem.getLastApprovedDate());
123 		// actionItemExt.setRowStyleClass();
124 		
125 		return actionItemExt;
126 	}
127 
128 	/**
129 	 * This method ...
130 	 * 
131 	 * @param routeHeader
132 	 * @return
133 	 */
134 	private DocumentRouteHeaderValueActionListExtension toDocumentRouteHeaderValueActionListExtension(
135 			DocumentRouteHeaderValue routeHeader) {
136 
137 		if(routeHeader==null){
138 			return null;
139 		}
140 		
141 		DocumentRouteHeaderValueActionListExtension extension = new DocumentRouteHeaderValueActionListExtension();
142 		
143 		extension.setDocumentId(routeHeader.getDocumentId());
144 		extension.setDocumentTypeId(routeHeader.getDocumentTypeId());
145 		extension.setDocRouteStatus(routeHeader.getDocRouteStatus());
146 		extension.setDocRouteLevel(routeHeader.getDocRouteLevel());
147 		extension.setDateModified(routeHeader.getDateModified());
148 		extension.setCreateDate(routeHeader.getCreateDate());
149 		extension.setApprovedDate(routeHeader.getApprovedDate());
150 		extension.setFinalizedDate(routeHeader.getFinalizedDate());
151 		extension.setRouteStatusDate(routeHeader.getRouteStatusDate());
152 		extension.setDocTitle(routeHeader.getDocTitle());
153 		extension.setAppDocId(routeHeader.getAppDocId());
154 		extension.setDocVersion(routeHeader.getDocVersion());
155 		extension.setInitiatorWorkflowId(routeHeader.getInitiatorWorkflowId());
156 		extension.setVersionNumber(routeHeader.getVersionNumber());
157 		extension.setAppDocStatus(routeHeader.getAppDocStatus());
158 		extension.setAppDocStatusDate(routeHeader.getAppDocStatusDate());
159 
160 		return extension;
161 	}
162 
163 	public Collection<ActionItem> getActionListForSingleDocument(String documentId) {
164         LOG.debug("getting action list for document id " + documentId);
165         Criteria crit = new Criteria(ActionItem.class.getName());
166         crit.eq("documentId", documentId);
167         crit.eq("TYPE(__JPA_ALIAS[[0]]__)", ActionItem.class);
168         Collection<ActionItem> collection = new QueryByCriteria(entityManager, crit).toQuery().getResultList();
169         LOG.debug("found " + collection.size() + " action items for document id " + documentId);
170         return toActionItemActionListExtensions(createActionListForRouteHeader(collection));
171     }
172     
173     private Criteria setUpActionListCriteria(Class objectsToRetrieve, String principalId, ActionListFilter filter) {
174         LOG.debug("setting up Action List criteria");
175         Criteria crit = new Criteria(objectsToRetrieve.getName());
176         boolean filterOn = false;
177         String filteredByItems = "";
178         
179         if (filter.getActionRequestCd() != null && !"".equals(filter.getActionRequestCd().trim()) && !filter.getActionRequestCd().equals(KewApiConstants.ALL_CODE)) {
180             if (filter.isExcludeActionRequestCd()) {
181                 crit.ne("actionRequestCd", filter.getActionRequestCd());
182             } else {
183                 crit.eq("actionRequestCd", filter.getActionRequestCd());
184             }
185             filteredByItems += filteredByItems.length() > 0 ? ", " : "";
186             filteredByItems += "Action Requested";
187         }
188 
189         if (filter.getCreateDateFrom() != null || filter.getCreateDateTo() != null) {
190             if (filter.isExcludeCreateDate()) {
191                 if (filter.getCreateDateFrom() != null && filter.getCreateDateTo() != null) {
192                     crit.notBetween("routeHeader.createDate", new Timestamp(beginningOfDay(filter.getCreateDateFrom()).getTime()), new Timestamp(endOfDay(filter.getCreateDateTo()).getTime()));
193                 } else if (filter.getCreateDateFrom() != null && filter.getCreateDateTo() == null) {
194                     crit.lte("routeHeader.createDate", new Timestamp(beginningOfDay(filter.getCreateDateFrom()).getTime()));
195                 } else if (filter.getCreateDateFrom() == null && filter.getCreateDateTo() != null) {
196                     crit.gte("routeHeader.createDate", new Timestamp(endOfDay(filter.getCreateDateTo()).getTime()));
197                 }
198             } else {
199                 if (filter.getCreateDateFrom() != null && filter.getCreateDateTo() != null) {
200                     crit.between("routeHeader.createDate", new Timestamp(beginningOfDay(filter.getCreateDateFrom()).getTime()), new Timestamp(endOfDay(filter.getCreateDateTo()).getTime()));
201                 } else if (filter.getCreateDateFrom() != null && filter.getCreateDateTo() == null) {
202                     crit.gte("routeHeader.createDate", new Timestamp(beginningOfDay(filter.getCreateDateFrom()).getTime()));
203                 } else if (filter.getCreateDateFrom() == null && filter.getCreateDateTo() != null) {
204                     crit.lte("routeHeader.createDate", new Timestamp(endOfDay(filter.getCreateDateTo()).getTime()));
205                 }
206             }
207             filteredByItems += filteredByItems.length() > 0 ? ", " : "";
208             filteredByItems += "Date Created";
209         }
210 
211         if (filter.getDocRouteStatus() != null && !"".equals(filter.getDocRouteStatus().trim()) && !filter.getDocRouteStatus().equals(KewApiConstants.ALL_CODE)) {
212             if (filter.isExcludeRouteStatus()) {
213                 crit.ne("routeHeader.docRouteStatus", filter.getDocRouteStatus());
214             } else {
215                 crit.eq("routeHeader.docRouteStatus", filter.getDocRouteStatus());
216             }
217             filteredByItems += filteredByItems.length() > 0 ? ", " : "";
218             filteredByItems += "Document Route Status";
219         }
220 
221         if (filter.getDocumentTitle() != null && !"".equals(filter.getDocumentTitle().trim())) {
222             String docTitle = filter.getDocumentTitle();
223             if (docTitle.trim().endsWith("*")) {
224                 docTitle = docTitle.substring(0, docTitle.length() - 1);
225             }
226 
227             if (filter.isExcludeDocumentTitle()) {
228                 crit.notLike("docTitle", "%" + docTitle + "%");
229             } else {
230                 crit.like("docTitle", "%" + docTitle + "%");
231             }
232             filteredByItems += filteredByItems.length() > 0 ? ", " : "";
233             filteredByItems += "Document Title";
234         }
235 
236         if (filter.getDocumentType() != null && !"".equals(filter.getDocumentType().trim())) {
237             if (filter.isExcludeDocumentType()) {
238                 crit.notLike("docName", "%" + filter.getDocumentType() + "%");
239             } else {
240             	String documentTypeName = filter.getDocumentType();
241             	DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
242             	if (documentType == null) {
243             	    crit.like("docName", "%" + filter.getDocumentType() + "%");
244             	} else {
245             	    // search this document type plus it's children
246             	    Criteria docTypeCrit = new Criteria(objectsToRetrieve.getName());
247             	    constructDocumentTypeCriteria(objectsToRetrieve.getName(), docTypeCrit, documentType);
248             	    crit.and(docTypeCrit);
249             	}
250             }
251             filteredByItems += filteredByItems.length() > 0 ? ", " : "";
252             filteredByItems += "Document Type";
253         }
254 
255         if (filter.getLastAssignedDateFrom() != null || filter.getLastAssignedDateTo() != null) {
256             if (filter.isExcludeLastAssignedDate()) {
257                 if (filter.getLastAssignedDateFrom() != null && filter.getLastAssignedDateTo() != null) {
258                     crit.notBetween("dateAssigned", new Timestamp(beginningOfDay(filter.getLastAssignedDateFrom()).getTime()), new Timestamp(endOfDay(filter.getLastAssignedDateTo()).getTime()));
259                 } else if (filter.getLastAssignedDateFrom() != null && filter.getLastAssignedDateTo() == null) {
260                     crit.lte("dateAssigned", new Timestamp(beginningOfDay(filter.getLastAssignedDateFrom()).getTime()));
261                 } else if (filter.getLastAssignedDateFrom() == null && filter.getLastAssignedDateTo() != null) {
262                     crit.gte("dateAssigned", new Timestamp(endOfDay(filter.getLastAssignedDateTo()).getTime()));
263                 }
264             } else {
265                 if (filter.getLastAssignedDateFrom() != null && filter.getLastAssignedDateTo() != null) {
266                     crit.between("dateAssigned", new Timestamp(beginningOfDay(filter.getLastAssignedDateFrom()).getTime()), new Timestamp(endOfDay(filter.getLastAssignedDateTo()).getTime()));
267                 } else if (filter.getLastAssignedDateFrom() != null && filter.getLastAssignedDateTo() == null) {
268                     crit.gte("dateAssigned", new Timestamp(beginningOfDay(filter.getLastAssignedDateFrom()).getTime()));
269                 } else if (filter.getLastAssignedDateFrom() == null && filter.getLastAssignedDateTo() != null) {
270                     crit.lte("dateAssigned", new Timestamp(endOfDay(filter.getLastAssignedDateTo()).getTime()));
271                 }
272             }
273             filteredByItems += filteredByItems.length() > 0 ? ", " : "";
274             filteredByItems += "Date Last Assigned";
275         }
276 
277         filter.setGroupId(null);
278         if (filter.getGroupIdString() != null && !"".equals(filter.getGroupIdString().trim()) && !filter.getGroupIdString().trim().equals(KewApiConstants.NO_FILTERING)) {
279             filter.setGroupId(filter.getGroupId());
280             if (filter.isExcludeGroupId()) {
281                 Criteria critNotEqual = new Criteria(objectsToRetrieve.getName());
282                 critNotEqual.ne("groupId", filter.getGroupId());
283                 Criteria critNull = new Criteria(objectsToRetrieve.getName());
284                 critNull.isNull("groupId");
285                 critNotEqual.or(critNull);
286                 crit.and(critNotEqual);
287             } else {
288                 crit.eq("groupId", filter.getGroupId());
289             }
290             filteredByItems += filteredByItems.length() > 0 ? ", " : "";
291             filteredByItems += "Action Request Workgroup";
292         }
293 
294         if (filteredByItems.length() > 0) {
295             filterOn = true;
296         }
297         
298         boolean addedDelegationCriteria = false;
299         if (StringUtils.isBlank(filter.getDelegationType()) && StringUtils.isBlank(filter.getPrimaryDelegateId()) && StringUtils.isBlank(filter.getDelegatorId())) {
300             crit.eq("principalId", principalId);
301             addedDelegationCriteria = true;
302         } else if ((StringUtils.isNotBlank(filter.getDelegationType()) && DelegationType.PRIMARY.getCode().equals(filter.getDelegationType()))
303                 || StringUtils.isNotBlank(filter.getPrimaryDelegateId())) {
304             // using a primary delegation
305             if ((StringUtils.isBlank(filter.getPrimaryDelegateId())) || (filter.getPrimaryDelegateId().trim().equals(KewApiConstants.ALL_CODE))) {
306                 // user wishes to see all primary delegations
307                 Criteria userCrit = new Criteria(objectsToRetrieve.getName());
308                 Criteria groupCrit = new Criteria(objectsToRetrieve.getName());
309                 Criteria orCrit = new Criteria(objectsToRetrieve.getName());
310                 userCrit.eq("delegatorPrincipalId", principalId);
311                 
312                 List<String> userGroupIds = new ArrayList<String>();
313                 for(String id: KimApiServiceLocator.getGroupService().getGroupIdsByPrincipalId(principalId)){
314                 	userGroupIds.add(id);
315                 }
316                 if (!userGroupIds.isEmpty()) {
317                 	groupCrit.in("delegatorGroupId", userGroupIds);
318                 }
319                 orCrit.or(userCrit);
320                 orCrit.or(groupCrit);
321                 crit.and(orCrit);
322                 crit.eq("delegationType", DelegationType.PRIMARY.getCode());
323                 filter.setDelegationType(DelegationType.PRIMARY.getCode());
324                 filter.setExcludeDelegationType(false);
325                 addToFilterDescription(filteredByItems, "Primary Delegator Id");
326                 addedDelegationCriteria = true;
327                 filterOn = true;
328             } else if (!filter.getPrimaryDelegateId().trim().equals(KewApiConstants.PRIMARY_DELEGATION_DEFAULT)) {
329                 // user wishes to see primary delegation for a single user
330                 crit.eq("principalId", filter.getPrimaryDelegateId());
331                 Criteria userCrit = new Criteria(objectsToRetrieve.getName());
332                 Criteria groupCrit = new Criteria(objectsToRetrieve.getName());
333                 Criteria orCrit = new Criteria(objectsToRetrieve.getName());
334                 userCrit.eq("delegatorPrincipalId", principalId);
335                 List<String> userGroupIds = new ArrayList<String>();
336                 for(String id: KimApiServiceLocator.getGroupService().getGroupIdsByPrincipalId(principalId)){
337                 	userGroupIds.add(id);
338                 }
339                 if (!userGroupIds.isEmpty()) {
340                 	groupCrit.in("delegatorGroupId", userGroupIds);
341                 }
342                 orCrit.or(userCrit);
343                 orCrit.or(groupCrit);
344                 crit.and(orCrit);
345                 crit.eq("delegationType", DelegationType.PRIMARY.getCode());
346                 filter.setDelegationType(DelegationType.PRIMARY.getCode());
347                 filter.setExcludeDelegationType(false);
348                 addToFilterDescription(filteredByItems, "Primary Delegator Id");
349                 addedDelegationCriteria = true;
350                 filterOn = true;
351             }
352         }
353         if (!addedDelegationCriteria && ( (StringUtils.isNotBlank(filter.getDelegationType()) && DelegationType.SECONDARY.getCode().equals(filter.getDelegationType()))
354                 || StringUtils.isNotBlank(filter.getDelegatorId()) )) {
355             // using a secondary delegation
356             crit.eq("principalId", principalId);
357             if (StringUtils.isBlank(filter.getDelegatorId())) {
358                 filter.setDelegationType(DelegationType.SECONDARY.getCode());
359                 // if isExcludeDelegationType() we want to show the default aciton list which is set up later in this method
360                 if (!filter.isExcludeDelegationType()) {
361                     crit.eq("delegationType", DelegationType.SECONDARY.getCode());
362                     addToFilterDescription(filteredByItems, "Secondary Delegator Id");
363                     addedDelegationCriteria = true;
364                     filterOn = true;
365                 }
366             } else if (filter.getDelegatorId().trim().equals(KewApiConstants.ALL_CODE)) {
367                 // user wishes to see all secondary delegations
368                 crit.eq("delegationType", DelegationType.SECONDARY.getCode());
369                 filter.setDelegationType(DelegationType.SECONDARY.getCode());
370                 filter.setExcludeDelegationType(false);
371                 addToFilterDescription(filteredByItems, "Secondary Delegator Id");
372                 addedDelegationCriteria = true;
373                 filterOn = true;
374             } else if (!filter.getDelegatorId().trim().equals(
375                     KewApiConstants.DELEGATION_DEFAULT)) {
376                 // user has specified an id to see for secondary delegation
377                 filter.setDelegationType(DelegationType.SECONDARY.getCode());
378                 filter.setExcludeDelegationType(false);
379                 Criteria userCrit = new Criteria(objectsToRetrieve.getName());
380                 Criteria groupCrit = new Criteria(objectsToRetrieve.getName());
381                 if (filter.isExcludeDelegatorId()) {
382                     Criteria userNull = new Criteria(objectsToRetrieve.getName());
383                     userCrit.ne("delegatorPrincipalId", filter.getDelegatorId());
384                     userNull.isNull("delegatorPrincipalId");
385                     userCrit.or(userNull);
386                     Criteria groupNull = new Criteria(objectsToRetrieve.getName());
387                     groupCrit.ne("delegatorGroupId", filter.getDelegatorId());
388                     groupNull.isNull("delegatorGroupId");
389                     groupCrit.or(groupNull);
390                     crit.and(userCrit);
391                     crit.and(groupCrit);
392                 } else {
393                     userCrit.eq("delegatorPrincipalId", filter.getDelegatorId());
394                     groupCrit.eq("delegatorGroupId", filter.getDelegatorId());
395                     userCrit.or(groupCrit);
396                     crit.and(userCrit);
397                 }
398                 addToFilterDescription(filteredByItems, "Secondary Delegator Id");
399                 addedDelegationCriteria = true;
400                 filterOn = true;
401             }
402         }
403         
404         // if we haven't added delegation criteria then use the default criteria below
405         if (!addedDelegationCriteria) {
406             crit.eq("principalId", principalId);
407             filter.setDelegationType(DelegationType.SECONDARY.getCode());
408             filter.setExcludeDelegationType(true);
409             Criteria critNotEqual = new Criteria(objectsToRetrieve.getName());
410             Criteria critNull = new Criteria(objectsToRetrieve.getName());
411             critNotEqual.ne("delegationType", DelegationType.SECONDARY.getCode());
412             critNull.isNull("delegationType");
413             critNotEqual.or(critNull);
414             crit.and(critNotEqual);
415         }
416 
417  
418         if (! "".equals(filteredByItems)) {
419             filteredByItems = "Filtered by " + filteredByItems;
420         }
421         filter.setFilterLegend(filteredByItems);
422         filter.setFilterOn(filterOn);
423 
424         LOG.debug("returning from Action List criteria");
425         return crit;
426     }
427     
428     private void constructDocumentTypeCriteria(String entityName, Criteria criteria, DocumentType documentType) {
429     	// search this document type plus it's children
430     	Criteria docTypeBaseCrit = new Criteria(entityName);
431     	docTypeBaseCrit.eq("docName", documentType.getName());
432     	criteria.or(docTypeBaseCrit);
433     	Collection children = documentType.getChildrenDocTypes();
434     	if (children != null) {
435     	    for (Iterator iterator = children.iterator(); iterator.hasNext();) {
436     	    	DocumentType childDocumentType = (DocumentType) iterator.next();
437     	    	constructDocumentTypeCriteria(entityName, criteria, childDocumentType);
438     	    }
439     	}
440     }
441     
442     private void addToFilterDescription(String filterDescription, String labelToAdd) {
443         filterDescription += filterDescription.length() > 0 ? ", " : "";
444         filterDescription += labelToAdd;
445     }
446 
447     private static final String ACTION_LIST_COUNT_QUERY = "select count(distinct(ai.doc_hdr_id)) from krew_actn_itm_t ai where ai.PRNCPL_ID = ? and (ai.dlgn_typ is null or ai.dlgn_typ = 'P')";
448 
449     public int getCount(final String workflowId) {
450 
451     	javax.persistence.Query q = entityManager.createNativeQuery(ACTION_LIST_COUNT_QUERY);
452     	q.setParameter(1, workflowId);
453     	Number result = (Number)q.getSingleResult();
454     	return result.intValue();
455     }
456 
457     private static final String ACTION_LIST_COUNT_AND_MAX_ACTION_ITEM_ID_QUERY = "select cast((max(actn_itm_id))as decimal) as max_id, count(distinct(doc_hdr_id)) as total_records"
458             + "  from ("
459             + "       select actn_itm_id,doc_hdr_id  "
460             + "         from KREW_ACTN_ITM_T   where    prncpl_id=? "
461             + "         group by  actn_itm_id,doc_hdr_id "
462             + "       ) T";
463      /**
464      * Gets the max action item id and count doe a given user.
465      *
466      * @return A List with the first value being the maxActionItemId and the second value being the count
467      */
468     public List<Integer> getMaxActionItemIdAndCountForUser(final String principalId) {
469         javax.persistence.Query q = entityManager.createNativeQuery(ACTION_LIST_COUNT_AND_MAX_ACTION_ITEM_ID_QUERY);
470         q.setParameter(1, principalId);
471         return q.getResultList();
472 
473     }
474 
475 
476 
477     /**
478      * Creates an Action List from the given collection of Action Items.  The Action List should
479      * contain only one action item per document.  The action item chosen should be the most "critical"
480      * or "important" one on the document.
481      *
482      * @return the Action List as a Collection of ActionItems
483      */
484     private <T extends ActionItem> Collection<T> createActionListForUser(Collection<T> actionItems) {
485         Map<String, T> actionItemMap = new HashMap<String, T>();
486         ActionListPriorityComparator comparator = new ActionListPriorityComparator();
487         for (T potentialActionItem: actionItems) {
488             T existingActionItem = actionItemMap.get(potentialActionItem.getDocumentId());
489             if (existingActionItem == null || comparator.compare(potentialActionItem, existingActionItem) > 0) {
490                 actionItemMap.put(potentialActionItem.getDocumentId(), potentialActionItem);
491             }
492         }
493         return actionItemMap.values();
494     }
495 
496     /**
497      * Creates an Action List from the given collection of Action Items.  The Action List should
498      * contain only one action item per user.  The action item chosen should be the most "critical"
499      * or "important" one on the document.
500      *
501      * @return the Action List as a Collection of ActionItems
502      */
503     private Collection<ActionItem> createActionListForRouteHeader(Collection<ActionItem> actionItems) {
504         Map<String, ActionItem> actionItemMap = new HashMap<String, ActionItem>();
505         ActionListPriorityComparator comparator = new ActionListPriorityComparator();
506         for (ActionItem potentialActionItem: actionItems) {
507             ActionItem existingActionItem = actionItemMap.get(potentialActionItem.getPrincipalId());
508             if (existingActionItem == null || comparator.compare(potentialActionItem, existingActionItem) > 0) {
509                 actionItemMap.put(potentialActionItem.getPrincipalId(), potentialActionItem);
510             }
511         }
512         return actionItemMap.values();
513     }
514     
515     private <T extends ActionItem> Collection<ActionItem> getActionItemsInActionList(Class<T> objectsToRetrieve, String principalId, ActionListFilter filter) {
516         LOG.debug("getting action list for user " + principalId);
517         Criteria crit = null;
518         if (filter == null) {
519             crit = new Criteria(objectsToRetrieve.getName());
520             crit.eq("principalId", principalId);
521         } else {
522             crit = setUpActionListCriteria(objectsToRetrieve, principalId, filter);
523         }
524         LOG.debug("running query to get action list for criteria " + crit);
525         Collection<ActionItem> collection = new QueryByCriteria(entityManager, crit).toQuery().getResultList();
526         LOG.debug("found " + collection.size() + " action items for user " + principalId);
527         return createActionListForUser(collection);
528     }
529 
530     public Collection<ActionItem> getOutbox(String principalId, ActionListFilter filter) {
531         return getActionItemsInActionList(OutboxItemActionListExtension.class, principalId, filter);
532     }
533 
534     /**
535      * Deletes all outbox items specified by the list of ids
536      * 
537      * @see org.kuali.rice.kew.actionlist.dao.ActionListDAO#removeOutboxItems(String, java.util.List)
538      */
539     public void removeOutboxItems(String principalId, List<String> outboxItems) {
540         Criteria crit = new Criteria(OutboxItemActionListExtension.class.getName());
541         crit.in("id", outboxItems);
542         for(Object entity:new QueryByCriteria(entityManager, crit).toQuery().getResultList()){
543         	entityManager.remove(entity);
544         }
545     }
546 
547     /**
548      * Saves an outbox item
549      * 
550      * @see org.kuali.rice.kew.actionlist.dao.ActionListDAO#saveOutboxItem(org.kuali.rice.kew.actionitem.OutboxItemActionListExtension)
551      */
552     public void saveOutboxItem(OutboxItemActionListExtension outboxItem) {
553     	if(outboxItem.getId()==null){
554     		entityManager.persist(outboxItem);
555     	}else{
556     	  //TODO, merge will not update the outboxitem pointer to the merged entity
557     		OrmUtils.merge(entityManager, outboxItem);
558     	}
559     	entityManager.flush();
560     }
561 
562     /**
563      * Gets the outbox item associated with the document id
564      * 
565      * @see org.kuali.rice.kew.actionlist.dao.ActionListDAO#getOutboxByDocumentId(java.lang.Long)
566      */
567     public OutboxItemActionListExtension getOutboxByDocumentId(String documentId) {
568         Criteria crit = new Criteria(OutboxItemActionListExtension.class.getName());
569         crit.eq("documentId", documentId);
570         return (OutboxItemActionListExtension) new QueryByCriteria(entityManager, crit).toQuery().getSingleResult();
571     }
572     
573     /**
574      * This overridden method ...
575      * 
576      * @see org.kuali.rice.kew.actionlist.dao.ActionListDAO#getOutboxByDocumentIdUserId(Long, String)
577      */
578     public OutboxItemActionListExtension getOutboxByDocumentIdUserId(String documentId, String userId) {
579         Criteria crit = new Criteria(OutboxItemActionListExtension.class.getName());
580         crit.eq("documentId", documentId);
581         crit.eq("principalId", userId);
582        	return (OutboxItemActionListExtension) new QueryByCriteria(entityManager, crit).toQuery().getSingleResult();
583     }
584     
585     private Date beginningOfDay(Date date) {
586         Calendar cal = Calendar.getInstance();
587         cal.setTime(date);
588         cal.set(Calendar.HOUR_OF_DAY, 0);
589         cal.set(Calendar.MINUTE, 0);
590         cal.set(Calendar.SECOND, 0);
591         return cal.getTime();
592     }
593     
594     private Date endOfDay(Date date) {
595         Calendar cal = Calendar.getInstance();
596         cal.setTime(date);
597         cal.set(Calendar.HOUR_OF_DAY, 23);
598         cal.set(Calendar.MINUTE, 59);
599         cal.set(Calendar.SECOND, 59);
600         return cal.getTime();        
601     }
602 
603     public EntityManager getEntityManager() {
604         return this.entityManager;
605     }
606 
607     public void setEntityManager(EntityManager entityManager) {
608         this.entityManager = entityManager;
609     }
610 
611 
612     
613 }