View Javadoc

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