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.actionrequests;
018:
019: import java.sql.Timestamp;
020: import java.util.ArrayList;
021: import java.util.Collection;
022: import java.util.Iterator;
023: import java.util.List;
024:
025: import org.apache.log4j.Logger;
026:
027: import edu.iu.uis.eden.EdenConstants;
028: import edu.iu.uis.eden.Id;
029: import edu.iu.uis.eden.KEWServiceLocator;
030: import edu.iu.uis.eden.engine.node.RouteNodeInstance;
031: import edu.iu.uis.eden.exception.EdenUserNotFoundException;
032: import edu.iu.uis.eden.exception.WorkflowRuntimeException;
033: import edu.iu.uis.eden.routeheader.DocumentRouteHeaderValue;
034: import edu.iu.uis.eden.routetemplate.ResolvedQualifiedRole;
035: import edu.iu.uis.eden.user.Recipient;
036: import edu.iu.uis.eden.user.RoleRecipient;
037: import edu.iu.uis.eden.user.UserId;
038: import edu.iu.uis.eden.user.WorkflowUser;
039: import edu.iu.uis.eden.util.CodeTranslator;
040: import edu.iu.uis.eden.util.Utilities;
041: import edu.iu.uis.eden.workgroup.GroupId;
042: import edu.iu.uis.eden.workgroup.GroupNameId;
043: import edu.iu.uis.eden.workgroup.Workgroup;
044: import edu.iu.uis.eden.workgroup.WorkgroupService;
045:
046: /**
047: * A factory to aid in creating the ever-so-gnarly ActionRequestValue object.
048: *
049: * @author rkirkend
050: */
051: public class ActionRequestFactory {
052:
053: private static final Logger LOG = Logger
054: .getLogger(ActionRequestFactory.class);
055:
056: private DocumentRouteHeaderValue document;
057: private RouteNodeInstance routeNode;
058: private List<ActionRequestValue> requestGraphs = new ArrayList<ActionRequestValue>();
059:
060: public ActionRequestFactory() {
061: }
062:
063: public ActionRequestFactory(DocumentRouteHeaderValue document) {
064: this .document = document;
065: }
066:
067: public ActionRequestFactory(DocumentRouteHeaderValue document,
068: RouteNodeInstance routeNode) {
069: this .document = document;
070: this .routeNode = routeNode;
071: }
072:
073: /**
074: * Constructs ActionRequestValue using default priority and 0 as responsibility
075: *
076: * @param actionRequested
077: * @param recipient
078: * @param description
079: * @param ignorePrevious
080: *
081: * @return ActionRequestValue
082: */
083: public ActionRequestValue createActionRequest(
084: String actionRequested, Recipient recipient,
085: String description, Boolean ignorePrevious,
086: String annotation) {
087: return createActionRequest(actionRequested, new Integer(0),
088: recipient, description,
089: EdenConstants.MACHINE_GENERATED_RESPONSIBILITY_ID,
090: ignorePrevious, annotation);
091: }
092:
093: public ActionRequestValue createActionRequest(
094: String actionRequested, Integer priority,
095: Recipient recipient, String description,
096: Long responsibilityId, Boolean ignorePrevious,
097: String annotation) {
098: return createActionRequest(actionRequested, priority,
099: recipient, description, responsibilityId,
100: ignorePrevious, null, null, annotation);
101: }
102:
103: public ActionRequestValue createActionRequest(
104: String actionRequested, Integer priority,
105: Recipient recipient, String description,
106: Long responsibilityId, Boolean ignorePrevious,
107: String approvePolicy, Long ruleId, String annotation) {
108: ActionRequestValue actionRequest = new ActionRequestValue();
109: actionRequest.setActionRequested(actionRequested);
110: actionRequest.setDocVersion(document.getDocVersion());
111: actionRequest.setPriority(priority);
112: actionRequest.setRouteHeader(document);
113: actionRequest.setRouteHeaderId(document.getRouteHeaderId());
114: actionRequest.setRouteLevel(document.getDocRouteLevel());
115: actionRequest.setNodeInstance(routeNode);
116: actionRequest.setResponsibilityId(responsibilityId);
117: actionRequest.setResponsibilityDesc(description);
118: actionRequest.setApprovePolicy(approvePolicy);
119: actionRequest.setIgnorePrevAction(ignorePrevious);
120: actionRequest.setRuleBaseValuesId(ruleId);
121: actionRequest.setAnnotation(annotation);
122: setDefaultProperties(actionRequest);
123: resolveRecipient(actionRequest, recipient);
124: return actionRequest;
125: }
126:
127: public ActionRequestValue createBlankActionRequest() {
128: ActionRequestValue request = new ActionRequestValue();
129: request.setRouteHeader(document);
130: request.setNodeInstance(routeNode);
131: return request;
132: }
133:
134: public ActionRequestValue createNotificationRequest(
135: String actionRequestCode, WorkflowUser recipient,
136: String reasonActionCode, WorkflowUser reasonActionUser,
137: String responsibilityDesc) {
138: ActionRequestValue request = createActionRequest(
139: actionRequestCode, recipient, responsibilityDesc,
140: Boolean.TRUE, null);
141: String annotation = generateNotificationAnnotation(
142: reasonActionUser, actionRequestCode, reasonActionCode,
143: request);
144: request.setAnnotation(annotation);
145: return request;
146: }
147:
148: //unify these 2 methods if possible
149: public List generateNotifications(List requests, WorkflowUser user,
150: Recipient delegator, String notificationRequestCode,
151: String actionTakenCode) throws EdenUserNotFoundException {
152: Workgroup notifyExclusionWorkgroup = getWorkgroupService()
153: .getWorkgroup(
154: new GroupNameId(
155: Utilities
156: .getApplicationConstant(EdenConstants.NOTIFICATION_EXCLUDED_USERS_WORKGROUP_NAME)));
157: return generateNotifications(null, getActionRequestService()
158: .getRootRequests(requests), user, delegator,
159: notificationRequestCode, actionTakenCode,
160: notifyExclusionWorkgroup);
161: }
162:
163: private List<ActionRequestValue> generateNotifications(
164: ActionRequestValue parentRequest, List requests,
165: WorkflowUser user, Recipient delegator,
166: String notificationRequestCode, String actionTakenCode,
167: Workgroup notifyExclusionWorkgroup)
168: throws EdenUserNotFoundException {
169: List<ActionRequestValue> notificationRequests = new ArrayList<ActionRequestValue>();
170: for (Iterator iter = requests.iterator(); iter.hasNext();) {
171: ActionRequestValue actionRequest = (ActionRequestValue) iter
172: .next();
173: if (!(actionRequest.isRecipientRoutedRequest(user) || actionRequest
174: .isRecipientRoutedRequest(delegator))) {
175: // skip user requests to system users
176: if ((notifyExclusionWorkgroup != null)
177: && (notifyExclusionWorkgroup
178: .hasMember(actionRequest.getRecipient()))) {
179: continue;
180: }
181: ActionRequestValue notificationRequest = createNotificationRequest(
182: actionRequest, user, notificationRequestCode,
183: actionTakenCode);
184: notificationRequests.add(notificationRequest);
185: if (parentRequest != null) {
186: notificationRequest
187: .setParentActionRequest(parentRequest);
188: parentRequest.getChildrenRequests().add(
189: notificationRequest);
190: }
191: notificationRequests.addAll(generateNotifications(
192: notificationRequest, actionRequest
193: .getChildrenRequests(), user,
194: delegator, notificationRequestCode,
195: actionTakenCode, notifyExclusionWorkgroup));
196: }
197: }
198: return notificationRequests;
199: }
200:
201: private ActionRequestValue createNotificationRequest(
202: ActionRequestValue actionRequest, WorkflowUser reasonUser,
203: String notificationRequestCode, String actionTakenCode)
204: throws EdenUserNotFoundException {
205:
206: String annotation = generateNotificationAnnotation(reasonUser,
207: notificationRequestCode, actionTakenCode, actionRequest);
208: ActionRequestValue request = createActionRequest(
209: notificationRequestCode, actionRequest.getPriority(),
210: actionRequest.getRecipient(), actionRequest
211: .getResponsibilityDesc(),
212: EdenConstants.MACHINE_GENERATED_RESPONSIBILITY_ID,
213: Boolean.TRUE, annotation);
214:
215: request.setDocVersion(actionRequest.getDocVersion());
216: request.setApprovePolicy(actionRequest.getApprovePolicy());
217: request.setRoleName(actionRequest.getRoleName());
218: request.setQualifiedRoleName(actionRequest
219: .getQualifiedRoleName());
220: request.setQualifiedRoleNameLabel(actionRequest
221: .getQualifiedRoleNameLabel());
222: request.setDelegationType(actionRequest.getDelegationType());
223: return request;
224: }
225:
226: private void setDefaultProperties(ActionRequestValue actionRequest) {
227: if (actionRequest.getApprovePolicy() == null) {
228: actionRequest
229: .setApprovePolicy(EdenConstants.APPROVE_POLICY_FIRST_APPROVE);
230: }
231: actionRequest.setCreateDate(new Timestamp(System
232: .currentTimeMillis()));
233: actionRequest.setCurrentIndicator(Boolean.TRUE);
234: if (actionRequest.getIgnorePrevAction() == null) {
235: actionRequest.setIgnorePrevAction(Boolean.FALSE);
236: }
237: if (routeNode != null) {
238: actionRequest.setNodeInstance(routeNode);
239: }
240: actionRequest.setJrfVerNbr(new Integer(0));
241: actionRequest
242: .setStatus(EdenConstants.ACTION_REQUEST_INITIALIZED);
243: actionRequest.setRouteHeader(document);
244: }
245:
246: private static void resolveRecipient(
247: ActionRequestValue actionRequest, Recipient recipient) {
248: if (recipient instanceof WorkflowUser) {
249: actionRequest
250: .setRecipientTypeCd(EdenConstants.ACTION_REQUEST_USER_RECIPIENT_CD);
251: actionRequest.setWorkflowId(((WorkflowUser) recipient)
252: .getWorkflowId());
253: } else if (recipient instanceof Workgroup) {
254: actionRequest
255: .setRecipientTypeCd(EdenConstants.ACTION_REQUEST_WORKGROUP_RECIPIENT_CD);
256: actionRequest.setWorkgroupId(((Workgroup) recipient)
257: .getWorkflowGroupId().getGroupId());
258: } else {
259: RoleRecipient role = (RoleRecipient) recipient;
260: actionRequest
261: .setRecipientTypeCd(EdenConstants.ACTION_REQUEST_ROLE_RECIPIENT_CD);
262: actionRequest.setRoleName(role.getRoleName());
263: actionRequest.setQualifiedRoleName(role
264: .getQualifiedRoleName());
265: ResolvedQualifiedRole qualifiedRole = role
266: .getResolvedQualifiedRole();
267: if (qualifiedRole != null) {
268: actionRequest.setAnnotation(qualifiedRole
269: .getAnnotation() == null ? "" : qualifiedRole
270: .getAnnotation());
271: actionRequest.setQualifiedRoleNameLabel(qualifiedRole
272: .getQualifiedRoleLabel());
273: }
274: Recipient targetRecipient = role.getTarget();
275: if (role.getTarget() != null) {
276: if (targetRecipient instanceof RoleRecipient) {
277: throw new WorkflowRuntimeException(
278: "Role Cannot Target a role problem activating request for document "
279: + actionRequest.getRouteHeader()
280: .getRouteHeaderId());
281: }
282: resolveRecipient(actionRequest, role.getTarget());
283: }
284: }
285: }
286:
287: // public ActionRequestValue createControlRequest(ActionRequestValue parentRequest, Recipient recipient, String delegationType, String actionRequested, String approvePolicy, Integer priority, Long responsibilityId, Boolean ignorePrevious, String description) {
288: // ActionRequestValue actionRequest = createActionRequest(actionRequested, priority, recipient, description, responsibilityId, ignorePrevious);
289: // if (parentRequest != null) {
290: // actionRequest.setActionRequested(parentRequest.getActionRequested());
291: // actionRequest.setPriority(parentRequest.getPriority());
292: // actionRequest.setDelegationType(delegationType);
293: // }
294: // return actionRequest;
295: // }
296:
297: /**
298: * Creates a root Role Request
299: * @param role
300: * @param actionRequested
301: * @param approvePolicy
302: * @param priority
303: * @param responsibilityId
304: * @param ignorePrevious
305: * @param description
306: * @return the created root role request
307: * @throws EdenUserNotFoundException
308: */
309: public ActionRequestValue addRoleRequest(RoleRecipient role,
310: String actionRequested, String approvePolicy,
311: Integer priority, Long responsibilityId,
312: Boolean ignorePrevious, String description, Long ruleId)
313: throws EdenUserNotFoundException {
314:
315: ActionRequestValue requestGraph = createActionRequest(
316: actionRequested, priority, role, description,
317: responsibilityId, ignorePrevious, approvePolicy,
318: ruleId, null);
319: if (role != null
320: && role.getResolvedQualifiedRole() != null
321: && role.getResolvedQualifiedRole().getRecipients() != null) {
322: for (Iterator iter = role.getResolvedQualifiedRole()
323: .getRecipients().iterator(); iter.hasNext();) {
324: Id recipientId = (Id) iter.next();
325: if (recipientId.isEmpty()) {
326: throw new WorkflowRuntimeException(
327: "Failed to resolve id of type "
328: + recipientId.getClass().getName()
329: + " returned from role '"
330: + role.getRoleName()
331: + "'. Id returned contained a null or empty value.");
332: }
333: if (recipientId instanceof UserId) {
334: role.setTarget(KEWServiceLocator.getUserService()
335: .getWorkflowUser((UserId) recipientId));
336: } else {
337: role.setTarget(KEWServiceLocator
338: .getWorkgroupService().getWorkgroup(
339: (GroupId) recipientId));
340: }
341: ActionRequestValue request = createActionRequest(
342: actionRequested, priority, role, description,
343: responsibilityId, ignorePrevious, null, ruleId,
344: null);
345: request.setParentActionRequest(requestGraph);
346: requestGraph.getChildrenRequests().add(request);
347: }
348: } else {
349: LOG
350: .warn("Didn't create action requests for action request description '"
351: + description
352: + "' because of null role or null part of role object graph.");
353: }
354: requestGraphs.add(requestGraph);
355: return requestGraph;
356: }
357:
358: public ActionRequestValue addDelegationRoleRequest(
359: ActionRequestValue parentRequest, String approvePolicy,
360: RoleRecipient role, Long responsibilityId,
361: Boolean ignorePrevious, String delegationType,
362: String description, Long ruleId)
363: throws EdenUserNotFoundException {
364: Recipient parentRecipient = parentRequest.getRecipient();
365: if (parentRecipient instanceof RoleRecipient) {
366: throw new WorkflowRuntimeException(
367: "Cannot delegate on Role Request. It must be a request to a person or workgroup, although that request may be in a role");
368: }
369: if (!relatedToRoot(parentRequest)) {
370: throw new WorkflowRuntimeException(
371: "The parent request is not related to any request managed by this factory");
372: }
373: ActionRequestValue delegationRoleRequest = createActionRequest(
374: parentRequest.getActionRequested(), parentRequest
375: .getPriority(), role, description,
376: responsibilityId, ignorePrevious, approvePolicy,
377: ruleId, null);
378: delegationRoleRequest.setDelegationType(delegationType);
379: int count = 0;
380: for (Iterator iter = role.getResolvedQualifiedRole()
381: .getRecipients().iterator(); iter.hasNext(); count++) {
382: //repeat of createRoleRequest code
383: Id recipientId = (Id) iter.next();
384: if (recipientId.isEmpty()) {
385: throw new WorkflowRuntimeException(
386: "Failed to resolve id of type "
387: + recipientId.getClass().getName()
388: + " returned from role '"
389: + role.getRoleName()
390: + "'. Id returned contained a null or empty value.");
391: }
392: if (recipientId instanceof UserId) {
393: role.setTarget(KEWServiceLocator.getUserService()
394: .getWorkflowUser((UserId) recipientId));
395: } else {
396: role.setTarget(KEWServiceLocator.getWorkgroupService()
397: .getWorkgroup((GroupId) recipientId));
398: }
399: ActionRequestValue request = createActionRequest(
400: parentRequest.getActionRequested(), parentRequest
401: .getPriority(), role, description,
402: responsibilityId, ignorePrevious, null, ruleId,
403: null);
404: request.setDelegationType(delegationType);
405: //end repeat
406: request.setParentActionRequest(delegationRoleRequest);
407: delegationRoleRequest.getChildrenRequests().add(request);
408: }
409:
410: //put this mini graph in the larger graph
411: if (count > 0) {
412: parentRequest.getChildrenRequests().add(
413: delegationRoleRequest);
414: delegationRoleRequest.setParentActionRequest(parentRequest);
415: }
416:
417: return delegationRoleRequest;
418: }
419:
420: public ActionRequestValue addDelegationRequest(
421: ActionRequestValue parentRequest, Recipient recipient,
422: Long responsibilityId, Boolean ignorePrevious,
423: String delegationType, String description, Long ruleId)
424: throws EdenUserNotFoundException {
425: if (!relatedToRoot(parentRequest)) {
426: throw new WorkflowRuntimeException(
427: "The parent request is not related to any request managed by this factory");
428: }
429: ActionRequestValue delegationRequest = createActionRequest(
430: parentRequest.getActionRequested(), parentRequest
431: .getPriority(), recipient, description,
432: responsibilityId, ignorePrevious, null, ruleId, null);
433: delegationRequest.setDelegationType(delegationType);
434: parentRequest.getChildrenRequests().add(delegationRequest);
435: delegationRequest.setParentActionRequest(parentRequest);
436:
437: return delegationRequest;
438: }
439:
440: //could probably base behavior off of recipient type
441: public ActionRequestValue addRootActionRequest(
442: String actionRequested, Integer priority,
443: Recipient recipient, String description,
444: Long responsibilityId, Boolean ignorePrevious,
445: String approvePolicy, Long ruleId) {
446: ActionRequestValue requestGraph = createActionRequest(
447: actionRequested, priority, recipient, description,
448: responsibilityId, ignorePrevious, approvePolicy,
449: ruleId, null);
450: requestGraphs.add(requestGraph);
451: return requestGraph;
452: }
453:
454: //return true if requestGraph (root) is in this requests' parents
455: public boolean relatedToRoot(ActionRequestValue request) {
456: int i = 0;
457: while (i < 3) {
458: if (requestGraphs.contains(request)) {
459: return true;
460: } else if (request == null) {
461: return false;
462: }
463: i++;
464: request = request.getParentActionRequest();
465: }
466: return false;
467: }
468:
469: public List getRequestGraphs() {
470: //clean up all the trailing role requests with no children -
471: requestGraphs.removeAll(cleanUpChildren(requestGraphs));
472: return requestGraphs;
473: }
474:
475: private Collection cleanUpChildren(Collection children) {
476: Collection requestsToRemove = new ArrayList();
477: for (Iterator iter = children.iterator(); iter.hasNext();) {
478:
479: ActionRequestValue request = (ActionRequestValue) iter
480: .next();
481: if (request.isRoleRequest()) {
482: if (request.getChildrenRequests().isEmpty()) {
483: requestsToRemove.add(request);
484: } else {
485: Collection childRequestsToRemove = cleanUpChildren(request
486: .getChildrenRequests());
487: request.getChildrenRequests().removeAll(
488: childRequestsToRemove);
489: }
490: }
491: }
492: return requestsToRemove;
493: }
494:
495: private String generateNotificationAnnotation(WorkflowUser user,
496: String notificationRequestCode, String actionTakenCode,
497: ActionRequestValue request) {
498: String notification = "Action "
499: + CodeTranslator
500: .getActionRequestLabel(notificationRequestCode)
501: + " generated by Workflow because "
502: + user.getDisplayName() + " took action "
503: + CodeTranslator.getActionTakenLabel(actionTakenCode);
504: if (request.getResponsibilityId() != null
505: && request.getResponsibilityId().longValue() != 0) {
506: notification += " Responsibility "
507: + request.getResponsibilityId();
508: }
509: if (request.getRuleBaseValuesId() != null) {
510: notification += " Rule Id " + request.getRuleBaseValuesId();
511: }
512: return notification;
513: }
514:
515: public ActionRequestService getActionRequestService() {
516: return (ActionRequestService) KEWServiceLocator
517: .getService(KEWServiceLocator.ACTION_REQUEST_SRV);
518: }
519:
520: public WorkgroupService getWorkgroupService() {
521: return (WorkgroupService) KEWServiceLocator
522: .getService(KEWServiceLocator.WORKGROUP_SRV);
523: }
524: }
|