001: /*
002: * Copyright 2005-2006 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package edu.iu.uis.eden.actionlist;
018:
019: import java.sql.Timestamp;
020: import java.util.ArrayList;
021: import java.util.Collection;
022: import java.util.Date;
023: import java.util.HashMap;
024: import java.util.HashSet;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.Set;
029:
030: import javax.xml.namespace.QName;
031:
032: import org.apache.commons.collections.CollectionUtils;
033: import org.kuali.bus.services.KSBServiceLocator;
034:
035: import edu.iu.uis.eden.EdenConstants;
036: import edu.iu.uis.eden.KEWServiceLocator;
037: import edu.iu.uis.eden.WorkflowServiceErrorException;
038: import edu.iu.uis.eden.WorkflowServiceErrorImpl;
039: import edu.iu.uis.eden.actionitem.ActionItem;
040: import edu.iu.uis.eden.actionitem.dao.ActionItemDAO;
041: import edu.iu.uis.eden.actionlist.dao.ActionListDAO;
042: import edu.iu.uis.eden.actionrequests.ActionRequestService;
043: import edu.iu.uis.eden.actionrequests.ActionRequestValue;
044: import edu.iu.uis.eden.doctype.DocumentType;
045: import edu.iu.uis.eden.exception.EdenUserNotFoundException;
046: import edu.iu.uis.eden.exception.WorkflowRuntimeException;
047: import edu.iu.uis.eden.messaging.KEWXMLService;
048: import edu.iu.uis.eden.messaging.MessageServiceNames;
049: import edu.iu.uis.eden.routeheader.DocumentRouteHeaderValue;
050: import edu.iu.uis.eden.user.UserService;
051: import edu.iu.uis.eden.user.WorkflowUser;
052: import edu.iu.uis.eden.user.WorkflowUserId;
053: import edu.iu.uis.eden.workgroup.WorkflowGroupId;
054: import edu.iu.uis.eden.workgroup.Workgroup;
055: import edu.iu.uis.eden.workgroup.WorkgroupMembershipChangeProcessor;
056: import edu.iu.uis.eden.workgroup.WorkgroupService;
057:
058: /**
059: * Default implementation of the {@link ActionListService}.
060: *
061: * @author rkirkend
062: * @author ewestfal
063: * @author temay
064: */
065: public class ActionListServiceImpl implements ActionListService {
066:
067: protected final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
068: .getLogger(getClass());
069:
070: private ActionListDAO actionListDAO;
071:
072: private ActionItemDAO actionItemDAO;
073:
074: public Collection findUserDelegators(WorkflowUser workflowUser,
075: String delegationType) throws EdenUserNotFoundException {
076: return findDelegators(workflowUser, delegationType);
077: }
078:
079: public Collection getActionList(WorkflowUser workflowUser,
080: ActionListFilter filter) {
081: return getActionListDAO().getActionList(workflowUser, filter);
082: }
083:
084: public void setActionListDAO(ActionListDAO actionListDAO) {
085: this .actionListDAO = actionListDAO;
086: }
087:
088: public ActionListDAO getActionListDAO() {
089: return actionListDAO;
090: }
091:
092: public boolean refreshActionList(WorkflowUser user) {
093: return KEWServiceLocator.getUserOptionsService()
094: .refreshActionList(user);
095: }
096:
097: public void deleteActionItem(ActionItem actionItem) {
098: try {
099: KEWServiceLocator.getUserOptionsService()
100: .saveRefreshUserOption(actionItem.getUser());
101: } catch (EdenUserNotFoundException e) {
102: LOG.error("error saving refreshUserOption", e);
103: }
104: getActionItemDAO().deleteActionItem(actionItem);
105: }
106:
107: public void deleteActionItems(Long actionRequestId) {
108: Collection actionItems = findByActionRequestId(actionRequestId);
109: for (Iterator iter = actionItems.iterator(); iter.hasNext();) {
110: ActionItem actionItem = (ActionItem) iter.next();
111: try {
112: KEWServiceLocator.getUserOptionsService()
113: .saveRefreshUserOption(actionItem.getUser());
114: } catch (EdenUserNotFoundException e) {
115: LOG.error("error saving refreshUserOption", e);
116: }
117: }
118: getActionItemDAO().deleteActionItems(actionRequestId);
119: }
120:
121: public void deleteByRouteHeaderId(Long routeHeaderId) {
122: Collection actionItems = findByRouteHeaderId(routeHeaderId);
123: for (Iterator iter = actionItems.iterator(); iter.hasNext();) {
124: ActionItem actionItem = (ActionItem) iter.next();
125: try {
126: KEWServiceLocator.getUserOptionsService()
127: .saveRefreshUserOption(actionItem.getUser());
128: } catch (EdenUserNotFoundException e) {
129: LOG.error("error saving refreshUserOption", e);
130: }
131: }
132: getActionItemDAO().deleteByRouteHeaderId(routeHeaderId);
133: }
134:
135: // public Collection findByWorkgroupId(Long workgroupId) {
136: // return getActionItemDAO().findByWorkgroupId(workgroupId);
137: // }
138:
139: public Collection findByRouteHeaderId(Long routeHeaderId) {
140: return getActionItemDAO().findByRouteHeaderId(routeHeaderId);
141: }
142:
143: public Collection findByActionRequestId(Long actionRequestId) {
144: return getActionItemDAO()
145: .findByActionRequestId(actionRequestId);
146: }
147:
148: public Collection findByWorkflowUser(WorkflowUser workflowUser) {
149: return getActionItemDAO().findByWorkflowUser(workflowUser);
150: }
151:
152: public Collection findByWorkflowUserRouteHeaderId(
153: String workflowUserId, Long routeHeaderId) {
154: return getActionItemDAO().findByWorkflowUserRouteHeaderId(
155: workflowUserId, routeHeaderId);
156: }
157:
158: private void loadActionItemFromActionRequest(
159: ActionRequestValue actionRequest, ActionItem actionItem) {
160:
161: DocumentRouteHeaderValue routeHeader = KEWServiceLocator
162: .getRouteHeaderService().getRouteHeader(
163: actionRequest.getRouteHeaderId());
164: DocumentType docType = routeHeader.getDocumentType();
165:
166: actionItem.setActionRequestCd(actionRequest
167: .getActionRequested());
168: actionItem.setActionRequestId(actionRequest
169: .getActionRequestId());
170: actionItem.setDocName(docType.getName());
171: actionItem.setRoleName(actionRequest.getQualifiedRoleName());
172: actionItem.setWorkflowId(actionRequest.getWorkflowId());
173: actionItem.setRouteHeaderId(actionRequest.getRouteHeaderId());
174: actionItem.setRouteHeader(routeHeader);
175: actionItem.setDateAssigned(new Timestamp(new Date().getTime()));
176: actionItem.setDocHandlerURL(docType.getDocHandlerUrl());
177: actionItem.setDocLabel(docType.getLabel());
178: actionItem.setDocTitle(routeHeader.getDocTitle());
179: actionItem.setWorkgroupId(actionRequest.getWorkgroupId());
180: actionItem.setResponsibilityId(actionRequest
181: .getResponsibilityId());
182: actionItem.setDelegationType(actionRequest.getDelegationType());
183:
184: ActionRequestValue delegatorActionRequest = getActionRequestService()
185: .findDelegatorRequest(actionRequest);
186: if (delegatorActionRequest != null) {
187: actionItem.setDelegatorWorkflowId(delegatorActionRequest
188: .getWorkflowId());
189: actionItem.setDelegatorWorkgroupId(delegatorActionRequest
190: .getWorkgroupId());
191: }
192: }
193:
194: /**
195: * Generates ActionItems for the given ActionRequest and returns the List of
196: * generated Action Items.
197: *
198: * @return the List of generated ActionItems
199: */
200: public List generateActionItems(ActionRequestValue actionRequest,
201: boolean simulate) throws EdenUserNotFoundException {
202: LOG.debug("generating the action items for request "
203: + actionRequest.getActionRequestId());
204: List actionItems = new ArrayList();
205: if (!actionRequest.isPrimaryDelegator()) {
206: if (EdenConstants.ACTION_REQUEST_WORKGROUP_RECIPIENT_CD
207: .equals(actionRequest.getRecipientTypeCd())) {
208: List users = getWorkgroupService().getWorkgroup(
209: new WorkflowGroupId(actionRequest
210: .getWorkgroupId())).getUsers();
211: actionItems.addAll(getActionItemsFromUserList(
212: actionRequest, users));
213: } else if (EdenConstants.ACTION_REQUEST_USER_RECIPIENT_CD
214: .equals(actionRequest.getRecipientTypeCd())) {
215: ActionItem actionItem = new ActionItem();
216: loadActionItemFromActionRequest(actionRequest,
217: actionItem);
218: actionItems.add(actionItem);
219: }
220: }
221: if (!simulate) {
222: for (Iterator iterator = actionItems.iterator(); iterator
223: .hasNext();) {
224: ActionItem actionItem = (ActionItem) iterator.next();
225: saveActionItem(actionItem);
226: }
227: }
228: return actionItems;
229: }
230:
231: private List getActionItemsFromUserList(
232: ActionRequestValue actionRequest, List users) {
233: List actionItems = new ArrayList();
234: for (Iterator iterator = users.iterator(); iterator.hasNext();) {
235: WorkflowUser user = (WorkflowUser) iterator.next();
236: ActionItem actionItem = new ActionItem();
237: loadActionItemFromActionRequest(actionRequest, actionItem);
238: actionItem.setWorkflowId(user.getWorkflowUserId()
239: .getWorkflowId());
240: actionItem
241: .setRoleName(actionRequest.getQualifiedRoleName());
242: actionItems.add(actionItem);
243: }
244: return actionItems;
245: }
246:
247: /**
248: * Determines the difference between the current workgroup membership and
249: * the new workgroup membership. It then schedules the action item updates
250: * to happen asynchronously.
251: */
252: public void updateActionItemsForWorkgroupChange(
253: Workgroup oldWorkgroup, Workgroup newWorkgroup)
254: throws EdenUserNotFoundException {
255: List oldMembers = oldWorkgroup.getUsers();
256: List newMembers = newWorkgroup.getUsers();
257: MembersDiff membersDiff = getMembersDiff(oldMembers, newMembers);
258: for (Iterator iterator = membersDiff.getRemovedMembers()
259: .iterator(); iterator.hasNext();) {
260: WorkflowUser removedMember = (WorkflowUser) iterator.next();
261: KEWXMLService workgroupMembershipChangeProcessor = (KEWXMLService) KSBServiceLocator
262: .getMessageHelper()
263: .getServiceAsynchronously(
264: new QName(
265: MessageServiceNames.WORKGROUP_MEMBERSHIP_CHANGE_SERVICE));
266: try {
267: workgroupMembershipChangeProcessor
268: .invoke(WorkgroupMembershipChangeProcessor
269: .getMemberRemovedMessageContents(
270: removedMember, newWorkgroup));
271: } catch (Exception e) {
272: throw new WorkflowRuntimeException(e);
273: }
274: }
275: for (Iterator iterator = membersDiff.getAddedMembers()
276: .iterator(); iterator.hasNext();) {
277: WorkflowUser addedMember = (WorkflowUser) iterator.next();
278: KEWXMLService workgroupMembershipChangeProcessor = (KEWXMLService) KSBServiceLocator
279: .getMessageHelper()
280: .getServiceAsynchronously(
281: new QName(
282: MessageServiceNames.WORKGROUP_MEMBERSHIP_CHANGE_SERVICE));
283: try {
284: workgroupMembershipChangeProcessor
285: .invoke(WorkgroupMembershipChangeProcessor
286: .getMemberAddedMessageContents(
287: addedMember, oldWorkgroup));
288: } catch (Exception e) {
289: throw new WorkflowRuntimeException(e);
290: }
291:
292: }
293: }
294:
295: /**
296: * Update the user's Action List to reflect their addition to the given
297: * Workgroup.
298: */
299: public void updateActionListForUserAddedToWorkgroup(
300: WorkflowUser user, Workgroup workgroup)
301: throws EdenUserNotFoundException {
302: // first verify that the user is still a member of the workgroup
303: if (workgroup.hasMember(user)) {
304: List<ActionRequestValue> actionRequests = new ArrayList<ActionRequestValue>();
305: List<Workgroup> allWorkgroupsToCheck = KEWServiceLocator
306: .getWorkgroupService().getWorkgroupsGroups(
307: workgroup);
308: allWorkgroupsToCheck.add(0, workgroup);
309: for (Workgroup workgroupToCheck : allWorkgroupsToCheck) {
310: actionRequests.addAll(getActionRequestService()
311: .findActivatedByWorkgroup(workgroupToCheck));
312: }
313: for (Iterator requestIt = actionRequests.iterator(); requestIt
314: .hasNext();) {
315: ActionRequestValue request = (ActionRequestValue) requestIt
316: .next();
317: ActionItem item = new ActionItem();
318: loadActionItemFromActionRequest(request, item);
319: item.setWorkflowId(user.getWorkflowUserId()
320: .getWorkflowId());
321: saveActionItem(item);
322: }
323: }
324: }
325:
326: /**
327: * Update the user's Action List to reflect their removal from the given
328: * Workgroup.
329: */
330: public void updateActionListForUserRemovedFromWorkgroup(
331: WorkflowUser user, Workgroup workgroup)
332: throws EdenUserNotFoundException {
333: // first verify that the user is no longer a member of the workgroup
334: if (!workgroup.hasMember(user)) {
335: List<Workgroup> allWorkgroupsToCheck = KEWServiceLocator
336: .getWorkgroupService().getWorkgroupsGroups(
337: workgroup);
338: allWorkgroupsToCheck.add(0, workgroup);
339: Collection actionItems = findByWorkflowUser(user);
340: for (Iterator itemIt = actionItems.iterator(); itemIt
341: .hasNext();) {
342: ActionItem item = (ActionItem) itemIt.next();
343: if (item.isWorkgroupItem()) {
344: for (Workgroup workgroupToCheck : allWorkgroupsToCheck) {
345: if (item.getWorkgroupId().equals(
346: workgroupToCheck.getWorkflowGroupId()
347: .getGroupId())) {
348: deleteActionItem(item);
349: }
350: }
351: }
352: }
353: }
354: }
355:
356: public void updateActionItemsForTitleChange(Long routeHeaderId,
357: String newTitle) throws EdenUserNotFoundException {
358: Collection items = getActionItemDAO().findByRouteHeaderId(
359: routeHeaderId);
360: for (Iterator iterator = items.iterator(); iterator.hasNext();) {
361: ActionItem item = (ActionItem) iterator.next();
362: item.setDocTitle(newTitle);
363: saveActionItem(item);
364: }
365: }
366:
367: private MembersDiff getMembersDiff(Collection oldMembers,
368: Collection newMembers) {
369: Map currentMembersMap = createUsersMap(oldMembers);
370: Map newMembersMap = createUsersMap(newMembers);
371: Map allMembers = mergeMaps(currentMembersMap, newMembersMap);
372: Collection addedKeys = CollectionUtils.subtract(newMembersMap
373: .keySet(), currentMembersMap.keySet());
374: Collection removedKeys = CollectionUtils.subtract(
375: currentMembersMap.keySet(), newMembersMap.keySet());
376: Set addedMembers = getUsersSet(addedKeys, allMembers);
377: Set removedMembers = getUsersSet(removedKeys, allMembers);
378: return new MembersDiff(addedMembers, removedMembers);
379: }
380:
381: private Map mergeMaps(Map map1, Map map2) {
382: Map newMap = new HashMap();
383: newMap.putAll(map1);
384: newMap.putAll(map2);
385: return newMap;
386: }
387:
388: private Set getUsersSet(Collection userKeys, Map memberMap) {
389: Set resultSet = new HashSet();
390: for (Iterator iterator = userKeys.iterator(); iterator
391: .hasNext();) {
392: String workflowId = (String) iterator.next();
393: WorkflowUser user = (WorkflowUser) memberMap
394: .get(workflowId);
395: resultSet.add(user);
396: }
397: return resultSet;
398: }
399:
400: private Map createUsersMap(Collection members) {
401: Map map = new HashMap();
402: for (Iterator iterator = members.iterator(); iterator.hasNext();) {
403: WorkflowUser user = (WorkflowUser) iterator.next();
404: map.put(user.getWorkflowUserId().getWorkflowId(), user);
405: }
406: return map;
407: }
408:
409: public Collection findDelegators(WorkflowUser user,
410: String delegationType) throws EdenUserNotFoundException {
411: return getActionItemDAO().findDelegators(user, delegationType);
412: }
413:
414: public void saveActionItem(ActionItem actionItem)
415: throws EdenUserNotFoundException {
416: KEWServiceLocator.getUserOptionsService()
417: .saveRefreshUserOption(actionItem.getUser());
418: getActionItemDAO().saveActionItem(actionItem);
419: }
420:
421: public ActionItemDAO getActionItemDAO() {
422: return actionItemDAO;
423: }
424:
425: public ActionRequestService getActionRequestService() {
426: return (ActionRequestService) KEWServiceLocator
427: .getActionRequestService();
428: }
429:
430: public WorkgroupService getWorkgroupService() {
431: return (WorkgroupService) KEWServiceLocator
432: .getWorkgroupService();
433: }
434:
435: public void setActionItemDAO(ActionItemDAO actionItemDAO) {
436: this .actionItemDAO = actionItemDAO;
437: }
438:
439: public UserService getUserService() {
440: return (UserService) KEWServiceLocator.getUserService();
441: }
442:
443: // public ActionListEmailService getActionListEmailService() {
444: // return (ActionListEmailService)
445: // SpringServiceLocator.getActionListEmailService();
446: // }
447:
448: private class MembersDiff {
449: private final Set addedMembers;
450:
451: private final Set removedMembers;
452:
453: public MembersDiff(Set addedMembers, Set removedMembers) {
454: this .addedMembers = addedMembers;
455: this .removedMembers = removedMembers;
456: }
457:
458: public Set getAddedMembers() {
459: return addedMembers;
460: }
461:
462: public Set getRemovedMembers() {
463: return removedMembers;
464: }
465: }
466:
467: public void validateActionItem(ActionItem actionItem) {
468: List errors = new ArrayList();
469: String workflowId = actionItem.getWorkflowId();
470: if (workflowId == null || workflowId.trim().equals("")) {
471: errors.add(new WorkflowServiceErrorImpl(
472: "ActionItem person null.",
473: "actionitem.personid.empty", actionItem
474: .getActionItemId().toString()));
475: } else {
476: try {
477: getUserService().getWorkflowUser(
478: new WorkflowUserId(workflowId));
479: } catch (EdenUserNotFoundException e) {
480: errors.add(new WorkflowServiceErrorImpl(
481: "ActionItem person invalid.",
482: "actionitem.personid.invalid", actionItem
483: .getActionItemId().toString()));
484: }
485: }
486:
487: if (actionItem.getDateAssigned() == null) {
488: errors.add(new WorkflowServiceErrorImpl(
489: "ActionItem date assigned empty.",
490: "actionitem.dateassigned.empty", actionItem
491: .getActionItemId().toString()));
492: }
493:
494: String actionRequestCd = actionItem.getActionRequestCd();
495: if (actionRequestCd == null
496: || actionRequestCd.trim().equals("")) {
497: errors.add(new WorkflowServiceErrorImpl(
498: "ActionItem action request cd empty.",
499: "actionitem.actionrequestcd.empty", actionItem
500: .getActionItemId().toString()));
501: } else if (!EdenConstants.ACTION_REQUEST_CD
502: .containsKey(actionRequestCd)) {
503: errors.add(new WorkflowServiceErrorImpl(
504: "ActionItem action request cd invalid.",
505: "actionitem.actionrequestcd.invalid", actionItem
506: .getActionItemId().toString()));
507: }
508:
509: if (actionItem.getActionRequestId() == null) {
510: errors.add(new WorkflowServiceErrorImpl(
511: "ActionItem action request id empty.",
512: "actionitem.actionrequestid.empty", actionItem
513: .getActionItemId().toString()));
514: }
515:
516: if (actionItem.getRouteHeaderId() == null) {
517: errors.add(new WorkflowServiceErrorImpl(
518: "ActionItem Document id empty.",
519: "actionitem.routeheaderid.empty", actionItem
520: .getActionItemId().toString()));
521: } else if (KEWServiceLocator.getRouteHeaderService()
522: .getRouteHeader(actionItem.getRouteHeaderId()) == null) {
523: errors.add(new WorkflowServiceErrorImpl(
524: "ActionItem Document id invalid.",
525: "actionitem.routeheaderid.invalid", actionItem
526: .getActionItemId().toString()));
527: }
528:
529: String docTypeName = actionItem.getDocName();
530: DocumentType docType = null;
531: if (docTypeName == null || docTypeName.trim().equals("")) {
532: errors.add(new WorkflowServiceErrorImpl(
533: "ActionItem doctypename empty.",
534: "actionitem.doctypename.empty", actionItem
535: .getActionItemId().toString()));
536: } else {
537: docType = KEWServiceLocator.getDocumentTypeService()
538: .findByName(actionItem.getDocName());
539: if (docType == null) {
540: errors.add(new WorkflowServiceErrorImpl(
541: "ActionItem doctypename invalid.",
542: "actionitem.doctypename.invalid", actionItem
543: .getActionItemId().toString()));
544: }
545: }
546:
547: if (actionItem.getDocLabel() == null
548: || actionItem.getDocLabel().trim().equals("")) {
549: errors.add(new WorkflowServiceErrorImpl(
550: "ActionItem doctypelabel empty.",
551: "actionitem.doctypelabel.empty", actionItem
552: .getActionItemId().toString()));
553: } else if (docType != null
554: && !docType.getLabel().equals(actionItem.getDocLabel())) {
555: errors.add(new WorkflowServiceErrorImpl(
556: "ActionItem doctypelabel no match.",
557: "actionitem.doctypelabel.nomatch", actionItem
558: .getActionItemId().toString()));
559: }
560:
561: if (actionItem.getDocHandlerURL() == null
562: || actionItem.getDocHandlerURL().trim().equals("")) {
563: errors.add(new WorkflowServiceErrorImpl(
564: "ActionItem doc handler url empty.",
565: "actionitem.dochdrurl.empty", actionItem
566: .getActionItemId().toString()));
567: } else if (docType != null
568: && !docType.getDocHandlerUrl().equals(
569: actionItem.getDocHandlerURL())) {
570: errors.add(new WorkflowServiceErrorImpl(
571: "ActionItem doc handler url no match.",
572: "actionitem.dochdrurl.nomatch", actionItem
573: .getActionItemId().toString()));
574: }
575:
576: if (!errors.isEmpty()) {
577: throw new WorkflowServiceErrorException(
578: "ActionItem Validation Error", errors);
579: }
580: }
581:
582: public ActionItem findByActionItemId(Long actionItemId) {
583: return getActionItemDAO().findByActionItemId(actionItemId);
584: }
585:
586: }
|