View Javadoc

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