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.service.impl;
17  
18  import java.sql.Timestamp;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.Collections;
22  import java.util.Date;
23  import java.util.Iterator;
24  import java.util.List;
25  
26  import org.apache.commons.lang.StringUtils;
27  import org.kuali.rice.core.api.config.property.ConfigContext;
28  import org.kuali.rice.kew.actionitem.ActionItem;
29  import org.kuali.rice.kew.actionitem.OutboxItemActionListExtension;
30  import org.kuali.rice.kew.actionitem.dao.ActionItemDAO;
31  import org.kuali.rice.kew.actionlist.ActionListFilter;
32  import org.kuali.rice.kew.actionlist.dao.ActionListDAO;
33  import org.kuali.rice.kew.actionlist.service.ActionListService;
34  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
35  import org.kuali.rice.kew.actionrequest.Recipient;
36  import org.kuali.rice.kew.actionrequest.service.ActionRequestService;
37  import org.kuali.rice.kew.actiontaken.ActionTakenValue;
38  import org.kuali.rice.kew.doctype.bo.DocumentType;
39  import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
40  import org.kuali.rice.kew.exception.WorkflowServiceErrorImpl;
41  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
42  import org.kuali.rice.kew.service.KEWServiceLocator;
43  import org.kuali.rice.kew.useroptions.UserOptions;
44  import org.kuali.rice.kew.useroptions.UserOptionsService;
45  import org.kuali.rice.kew.api.KewApiConstants;
46  import org.kuali.rice.kim.api.group.GroupService;
47  import org.kuali.rice.kim.api.identity.principal.Principal;
48  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
49  
50  /**
51   * Default implementation of the {@link ActionListService}.
52   *
53   * @author Kuali Rice Team (rice.collab@kuali.org)
54   */
55  public class ActionListServiceImpl implements ActionListService {
56  
57      protected final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(getClass());
58  
59      private ActionListDAO actionListDAO;
60  
61      private ActionItemDAO actionItemDAO;
62  
63      public Collection<Recipient> findUserSecondaryDelegators(String principalId) {
64          return getActionItemDAO().findSecondaryDelegators(principalId);
65      }
66  
67      public Collection<Recipient> findUserPrimaryDelegations(String principalId) {
68          return getActionItemDAO().findPrimaryDelegationRecipients(principalId);
69      }
70  
71      public Collection<ActionItem> getActionList(String principalId, ActionListFilter filter) {
72           return getActionListDAO().getActionList(principalId, filter);
73      }
74  
75      public Collection<ActionItem> getActionListForSingleDocument(String documentId) {
76           return getActionListDAO().getActionListForSingleDocument(documentId);
77      }
78  
79      public void setActionListDAO(ActionListDAO actionListDAO) {
80          this.actionListDAO = actionListDAO;
81      }
82  
83      public ActionListDAO getActionListDAO() {
84          return actionListDAO;
85      }
86  
87      public boolean refreshActionList(String principalId) {
88          return KEWServiceLocator.getUserOptionsService().refreshActionList(principalId);
89      }
90  
91      public void deleteActionItem(ActionItem actionItem) {
92      	deleteActionItem(actionItem, false);
93      }
94      
95      public void deleteActionItem(ActionItem actionItem, boolean forceIntoOutbox) {
96          try {
97              KEWServiceLocator.getUserOptionsService().saveRefreshUserOption(actionItem.getPrincipalId());
98          } catch (Exception e) {
99              LOG.error("error saving refreshUserOption", e);
100         }
101         getActionItemDAO().deleteActionItem(actionItem);
102         // remove notification from KCB
103         KEWServiceLocator.getNotificationService().removeNotification(Collections.singletonList(ActionItem.to(actionItem)));
104         this.saveOutboxItem(actionItem, forceIntoOutbox);
105     }
106 
107     public void deleteByDocumentId(String documentId) {
108         Collection<ActionItem> actionItems = findByDocumentId(documentId);
109         for (Iterator<ActionItem> iter = actionItems.iterator(); iter.hasNext();) {
110             ActionItem actionItem = iter.next();
111             try {
112                 KEWServiceLocator.getUserOptionsService().saveRefreshUserOption(actionItem.getPrincipalId());
113             } catch (Exception e) {
114                 LOG.error("error saving refreshUserOption", e);
115             }
116         }
117         getActionItemDAO().deleteByDocumentId(documentId);
118     }
119 
120     public Collection<ActionItem> findByDocumentId(String documentId) {
121         return getActionItemDAO().findByDocumentId(documentId);
122     }
123 
124     public Collection<ActionItem> findByActionRequestId(String actionRequestId) {
125         return getActionItemDAO().findByActionRequestId(actionRequestId);
126     }
127 
128     public Collection<ActionItem> findByWorkflowUserDocumentId(String workflowUserId, String documentId) {
129         return getActionItemDAO().findByWorkflowUserDocumentId(workflowUserId, documentId);
130     }
131 
132     public Collection<ActionItem> findByDocumentTypeName(String documentTypeName) {
133         return getActionItemDAO().findByDocumentTypeName(documentTypeName);
134     }
135 
136     public ActionItem createActionItemForActionRequest(ActionRequestValue actionRequest) {
137         ActionItem actionItem = new ActionItem();
138 
139         DocumentRouteHeaderValue routeHeader = actionRequest.getRouteHeader();
140         DocumentType docType = routeHeader.getDocumentType();
141 
142         actionItem.setActionRequestCd(actionRequest.getActionRequested());
143         actionItem.setActionRequestId(actionRequest.getActionRequestId());
144         actionItem.setDocName(docType.getName());
145         actionItem.setRoleName(actionRequest.getQualifiedRoleName());
146         actionItem.setPrincipalId(actionRequest.getPrincipalId());
147         actionItem.setDocumentId(actionRequest.getDocumentId());
148         actionItem.setDateAssigned(new Timestamp(new Date().getTime()));
149         actionItem.setDocHandlerURL(docType.getResolvedDocumentHandlerUrl());
150         actionItem.setDocLabel(docType.getLabel());
151         actionItem.setDocTitle(routeHeader.getDocTitle());
152         actionItem.setGroupId(actionRequest.getGroupId());
153         actionItem.setResponsibilityId(actionRequest.getResponsibilityId());
154         actionItem.setDelegationType(actionRequest.getDelegationType());
155         actionItem.setRequestLabel(actionRequest.getRequestLabel());
156 
157         ActionRequestValue delegatorActionRequest = getActionRequestService().findDelegatorRequest(actionRequest);
158         if (delegatorActionRequest != null) {
159             actionItem.setDelegatorPrincipalId(delegatorActionRequest.getPrincipalId());
160             actionItem.setDelegatorGroupId(delegatorActionRequest.getGroupId());
161         }
162 
163         return actionItem;
164     }
165 
166 
167     public void updateActionItemsForTitleChange(String documentId, String newTitle) {
168         Collection<ActionItem> items = getActionItemDAO().findByDocumentId(documentId);
169         for (Iterator<ActionItem> iterator = items.iterator(); iterator.hasNext();) {
170             ActionItem item = iterator.next();
171             item.setDocTitle(newTitle);
172             saveActionItem(item);
173         }
174     }
175 
176     public void saveActionItem(ActionItem actionItem) {
177         KEWServiceLocator.getUserOptionsService().saveRefreshUserOption(actionItem.getPrincipalId());
178         getActionItemDAO().saveActionItem(actionItem);
179     }
180 
181     public ActionItemDAO getActionItemDAO() {
182         return actionItemDAO;
183     }
184 
185     public ActionRequestService getActionRequestService() {
186         return (ActionRequestService) KEWServiceLocator.getActionRequestService();
187     }
188 
189     public GroupService getGroupService(){
190     	return KimApiServiceLocator.getGroupService();
191     }
192 
193     public void setActionItemDAO(ActionItemDAO actionItemDAO) {
194         this.actionItemDAO = actionItemDAO;
195     }
196 
197 
198     public void validateActionItem(ActionItem actionItem) {
199         List<WorkflowServiceErrorImpl> errors = new ArrayList<WorkflowServiceErrorImpl>();
200         String principalId = actionItem.getPrincipalId();
201         if (principalId == null || principalId.trim().equals("")) {
202             errors.add(new WorkflowServiceErrorImpl("ActionItem person null.", "actionitem.personid.empty", actionItem
203                     .getId().toString()));
204         } else {
205         	Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(principalId);
206         	if (principal == null) {
207                 errors.add(new WorkflowServiceErrorImpl("ActionItem person invalid.", "actionitem.personid.invalid",
208                         actionItem.getId().toString()));
209             }
210         }
211 
212         if (actionItem.getDateAssigned() == null) {
213             errors.add(new WorkflowServiceErrorImpl("ActionItem date assigned empty.", "actionitem.dateassigned.empty",
214                     actionItem.getId().toString()));
215         }
216 
217         String actionRequestCd = actionItem.getActionRequestCd();
218         if (actionRequestCd == null || actionRequestCd.trim().equals("")) {
219             errors.add(new WorkflowServiceErrorImpl("ActionItem action request cd empty.",
220                     "actionitem.actionrequestcd.empty", actionItem.getId().toString()));
221         } else if (!KewApiConstants.ACTION_REQUEST_CD.containsKey(actionRequestCd)) {
222             errors.add(new WorkflowServiceErrorImpl("ActionItem action request cd invalid.",
223                     "actionitem.actionrequestcd.invalid", actionItem.getId().toString()));
224         }
225 
226         if (actionItem.getActionRequestId() == null) {
227             errors.add(new WorkflowServiceErrorImpl("ActionItem action request id empty.",
228                     "actionitem.actionrequestid.empty", actionItem.getId().toString()));
229         }
230 
231         if (actionItem.getDocumentId() == null) {
232             errors.add(new WorkflowServiceErrorImpl("ActionItem Document id empty.", "actionitem.documentid.empty",
233                     actionItem.getId().toString()));
234         } else if (KEWServiceLocator.getRouteHeaderService().getRouteHeader(actionItem.getDocumentId()) == null) {
235             errors.add(new WorkflowServiceErrorImpl("ActionItem Document id invalid.", "actionitem.documentid.invalid",
236                     actionItem.getId().toString()));
237         }
238 
239         String docTypeName = actionItem.getDocName();
240         DocumentType docType = null;
241         if (docTypeName == null || docTypeName.trim().equals("")) {
242             errors.add(new WorkflowServiceErrorImpl("ActionItem doctypename empty.", "actionitem.doctypename.empty",
243                     actionItem.getId().toString()));
244         } else {
245             docType = KEWServiceLocator.getDocumentTypeService().findByName(actionItem.getDocName());
246             if (docType == null) {
247                 errors.add(new WorkflowServiceErrorImpl("ActionItem doctypename invalid.", "actionitem.doctypename.invalid",
248                         actionItem.getId().toString()));
249             }
250         }
251 
252         if (actionItem.getDocLabel() == null || actionItem.getDocLabel().trim().equals("")) {
253             errors.add(new WorkflowServiceErrorImpl("ActionItem doctypelabel empty.", "actionitem.doctypelabel.empty",
254                     actionItem.getId().toString()));
255         } else if (docType != null && !docType.getLabel().equals(actionItem.getDocLabel())) {
256             errors.add(new WorkflowServiceErrorImpl("ActionItem doctypelabel no match.", "actionitem.doctypelabel.nomatch",
257                     actionItem.getId().toString()));
258         }
259 
260         // first check to see if the document type has an empty document handler url
261         if (StringUtils.isNotBlank(docType.getResolvedDocumentHandlerUrl())) {
262             if (actionItem.getDocHandlerURL() == null || actionItem.getDocHandlerURL().trim().equals("")) {
263                 errors.add(new WorkflowServiceErrorImpl("ActionItem doc handler url empty.", "actionitem.dochdrurl.empty",
264                         actionItem.getId().toString()));
265             } else if (docType != null && !docType.getResolvedDocumentHandlerUrl().equals(actionItem.getDocHandlerURL())) {
266                 errors.add(new WorkflowServiceErrorImpl("ActionItem doc handler url no match.", "actionitem.dochdrurl.nomatch",
267                         actionItem.getId().toString()));
268             }
269         } else {
270             // if the doc type doc handler url is blank, verify that the action item doc handler url is also blank
271             if (StringUtils.isNotBlank(actionItem.getDocHandlerURL())) {
272                 errors.add(new WorkflowServiceErrorImpl("ActionItem doc handler url not empty.", "actionitem.dochdrurl.not.empty", 
273                         actionItem.getId().toString()));
274             }
275         }
276 
277         if (!errors.isEmpty()) {
278             throw new WorkflowServiceErrorException("ActionItem Validation Error", errors);
279         }
280     }
281 
282     public ActionItem findByActionItemId(String actionItemId) {
283         return getActionItemDAO().findByActionItemId(actionItemId);
284     }
285 
286     public int getCount(String principalId) {
287         return getActionListDAO().getCount(principalId);
288     }
289 
290     public void saveRefreshUserOption(String principalId) {
291         KEWServiceLocator.getUserOptionsService().saveRefreshUserOption(principalId);
292     }
293 
294     /**
295      *
296      * This overridden method ...
297      *
298      * @see org.kuali.rice.kew.actionlist.service.ActionListService#getOutbox(java.lang.String, org.kuali.rice.kew.actionlist.ActionListFilter)
299      */
300     public Collection<ActionItem> getOutbox(String principalId, ActionListFilter filter) {
301         return this.getActionListDAO().getOutbox(principalId, filter);
302     }
303 
304     public Collection<ActionItem> getOutboxItemsByDocumentType(String documentTypeName) {
305         return this.getActionItemDAO().getOutboxItemsByDocumentType(documentTypeName);
306     }
307 
308     /**
309      * This overridden method ...
310      *
311      * @see org.kuali.rice.kew.actionlist.service.ActionListService#removeOutboxItems(String, java.util.List)
312      */
313     public void removeOutboxItems(String principalId, List<String> outboxItems) {
314         this.getActionListDAO().removeOutboxItems(principalId, outboxItems);
315     }
316 
317     public void saveOutboxItem(ActionItem actionItem) {
318     	saveOutboxItem(actionItem, false);
319     }
320     
321     /**
322      *
323      * save the ouboxitem unless the document is saved or the user already has the item in their outbox.
324      *
325      * @see org.kuali.rice.kew.actionlist.service.ActionListService#saveOutboxItem(org.kuali.rice.kew.actionitem.ActionItem, boolean)
326      */
327     public void saveOutboxItem(ActionItem actionItem, boolean forceIntoOutbox) {
328     	UserOptionsService userOptionsService = KEWServiceLocator.getUserOptionsService();
329     	Boolean isUsingOutBox = true;
330     	List<UserOptions> options = userOptionsService.findByUserQualified(actionItem.getPrincipalId(), KewApiConstants.USE_OUT_BOX);
331     	if (options == null || options.isEmpty()){
332     		isUsingOutBox = true;
333     	} else {
334 			for (Iterator iter = options.iterator(); iter.hasNext();) {
335 				UserOptions u = (UserOptions) iter.next();
336 				if (u.getOptionVal() == null || !(u.getOptionVal().equals("yes"))){
337 					isUsingOutBox = false;
338 				}
339 			}
340     	}
341     	
342     	if (isUsingOutBox
343             && ConfigContext.getCurrentContextConfig().getOutBoxOn()
344             && getActionListDAO().getOutboxByDocumentIdUserId(actionItem.getDocumentId(), actionItem.getPrincipalId()) == null
345             && !KEWServiceLocator.getRouteHeaderService().getRouteHeader(actionItem.getDocumentId()).getDocRouteStatus().equals(
346                     		KewApiConstants.ROUTE_HEADER_SAVED_CD)) {
347 
348     		// only create an outbox item if this user has taken action on the document
349     		ActionRequestValue actionRequest = KEWServiceLocator.getActionRequestService().findByActionRequestId(
350     				actionItem.getActionRequestId());
351     		ActionTakenValue actionTaken = actionRequest.getActionTaken();
352     		// if an action was taken...
353     		if (forceIntoOutbox || (actionTaken != null && actionTaken.getPrincipalId().equals(actionItem.getPrincipalId()))) {
354     			this.getActionListDAO().saveOutboxItem(new OutboxItemActionListExtension(actionItem));
355     		}
356        
357     	}
358     }
359     
360 	public Collection<ActionItem> findByPrincipalId(String principalId) {
361 		return getActionItemDAO().findByPrincipalId(principalId);
362 	}
363 
364 }