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.routetemplate;
018:
019: import java.sql.Timestamp;
020: import java.util.ArrayList;
021: import java.util.Date;
022: import java.util.HashSet;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Set;
026:
027: import org.apache.commons.lang.ObjectUtils;
028:
029: import edu.iu.uis.eden.EdenConstants;
030: import edu.iu.uis.eden.KEWServiceLocator;
031: import edu.iu.uis.eden.actionrequests.ActionRequestFactory;
032: import edu.iu.uis.eden.actionrequests.ActionRequestService;
033: import edu.iu.uis.eden.actionrequests.ActionRequestValue;
034: import edu.iu.uis.eden.engine.RouteContext;
035: import edu.iu.uis.eden.engine.node.RouteNodeInstance;
036: import edu.iu.uis.eden.exception.EdenUserNotFoundException;
037: import edu.iu.uis.eden.exception.WorkflowException;
038: import edu.iu.uis.eden.exception.WorkflowRuntimeException;
039: import edu.iu.uis.eden.plugin.attributes.MassRuleAttribute;
040: import edu.iu.uis.eden.plugin.attributes.RoleAttribute;
041: import edu.iu.uis.eden.plugin.attributes.WorkflowAttribute;
042: import edu.iu.uis.eden.routeheader.DocumentContent;
043: import edu.iu.uis.eden.routeheader.DocumentRouteHeaderValue;
044: import edu.iu.uis.eden.user.Recipient;
045: import edu.iu.uis.eden.user.RoleRecipient;
046: import edu.iu.uis.eden.user.WorkflowUserId;
047: import edu.iu.uis.eden.util.PerformanceLogger;
048: import edu.iu.uis.eden.util.ResponsibleParty;
049: import edu.iu.uis.eden.workgroup.WorkflowGroupId;
050:
051: /**
052: * Generates Action Requests for a Document using the rule system and the specified
053: * {@link RuleTemplate}.
054: *
055: * @see ActionRequestValue
056: * @see RuleTemplate
057: * @see RuleBaseValues
058: *
059: * @author rkirkend
060: * @author bmcgough
061: * @author ewestfal
062: * @author jhopf
063: */
064: public class FlexRM {
065:
066: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
067: .getLogger(FlexRM.class);
068:
069: private Timestamp effectiveDate;
070: private int numberOfMatchingRules;
071: private ActionRequestFactory arFactory;
072:
073: public FlexRM() {
074: }
075:
076: public FlexRM(Timestamp effectiveDate) {
077: this .effectiveDate = effectiveDate;
078: }
079:
080: public List getActionRequests(DocumentRouteHeaderValue routeHeader,
081: String ruleTemplateName) throws EdenUserNotFoundException,
082: WorkflowException {
083: return getActionRequests(routeHeader, null, ruleTemplateName);
084: }
085:
086: public List getActionRequests(DocumentRouteHeaderValue routeHeader,
087: RouteNodeInstance nodeInstance, String ruleTemplateName)
088: throws EdenUserNotFoundException, WorkflowException {
089:
090: LOG.debug("Making action requests for document "
091: + routeHeader.getRouteHeaderId());
092: Set massRules = new HashSet();
093: RuleTemplate template = getRuleTemplateService()
094: .findByRuleTemplateName(ruleTemplateName);
095: if (template == null) {
096: throw new WorkflowRuntimeException(
097: "Could not locate the rule template with name "
098: + ruleTemplateName + " on document "
099: + routeHeader.getRouteHeaderId());
100: }
101: for (Iterator iter = template.getRuleTemplateAttributes()
102: .iterator(); iter.hasNext();) {
103:
104: RuleTemplateAttribute templateAttribute = (RuleTemplateAttribute) iter
105: .next();
106: if (!templateAttribute.isWorkflowAttribute()) {
107: continue;
108: }
109: WorkflowAttribute attribute = templateAttribute
110: .getWorkflowAttribute();
111: if (attribute instanceof MassRuleAttribute) {
112: massRules.add(attribute);
113: }
114:
115: }
116:
117: List rules = null;
118: if (effectiveDate != null) {
119: rules = getRuleService()
120: .fetchAllCurrentRulesForTemplateDocCombination(
121: ruleTemplateName,
122: routeHeader.getDocumentType().getName(),
123: effectiveDate);
124: } else {
125: rules = getRuleService()
126: .fetchAllCurrentRulesForTemplateDocCombination(
127: ruleTemplateName,
128: routeHeader.getDocumentType().getName());
129: }
130: numberOfMatchingRules = rules.size();
131:
132: RouteContext context = RouteContext.getCurrentRouteContext();
133: // TODO really the route context just needs to be able to support nested create and clears
134: // (i.e. a Stack model similar to transaction intercepting in Spring) and we wouldn't have to do this
135: if (context.getDocument() == null) {
136: context.setDocument(routeHeader);
137: }
138: if (context.getNodeInstance() == null) {
139: context.setNodeInstance(nodeInstance);
140: }
141: DocumentContent documentContent = context.getDocumentContent();
142: PerformanceLogger performanceLogger = new PerformanceLogger();
143: // have all mass rule attributes filter the list of non applicable rules
144: for (Iterator iter = massRules.iterator(); iter.hasNext();) {
145: MassRuleAttribute massRuleAttribute = (MassRuleAttribute) iter
146: .next();
147: rules = massRuleAttribute.filterNonMatchingRules(context,
148: rules);
149: }
150: performanceLogger.log("Time to filter massRules for template "
151: + template.getName());
152:
153: arFactory = new ActionRequestFactory(routeHeader, context
154: .getNodeInstance());
155: performanceLogger = new PerformanceLogger();
156: List actionRequests = new ArrayList();
157: for (Iterator iter = rules.iterator(); iter.hasNext();) {
158: RuleBaseValues rule = (RuleBaseValues) iter.next();
159: if (rule.isMatch(documentContent)) {
160: // actionRequests.addAll(makeActionRequests(context, rule, routeHeader, null, null));
161: makeActionRequests(context, rule, routeHeader, null,
162: null);
163: }
164: }
165: actionRequests = new ArrayList(arFactory.getRequestGraphs());
166: performanceLogger
167: .log("Time to make action request for template "
168: + template.getName());
169:
170: return actionRequests;
171: }
172:
173: public ResponsibleParty resolveResponsibilityId(
174: Long responsibilityId) {
175: RuleResponsibility resp = getRuleService()
176: .findRuleResponsibility(responsibilityId);
177: if (resp.isUsingRole()) {
178: return new ResponsibleParty(resp.getResolvedRoleName());
179: } else if (resp.isUsingWorkflowUser()) {
180: return new ResponsibleParty(new WorkflowUserId(resp
181: .getRuleResponsibilityName()));
182: } else {
183: return new ResponsibleParty(new WorkflowGroupId(new Long(
184: resp.getRuleResponsibilityName())));
185: }
186: }
187:
188: private void makeActionRequests(RouteContext context,
189: RuleBaseValues rule, DocumentRouteHeaderValue routeHeader,
190: ActionRequestValue parentRequest,
191: RuleDelegation ruleDelegation)
192: throws EdenUserNotFoundException, WorkflowException {
193:
194: // Set actionRequests = new HashSet();
195: List responsibilities = rule.getResponsibilities();
196: for (Iterator iter = responsibilities.iterator(); iter
197: .hasNext();) {
198: RuleResponsibility resp = (RuleResponsibility) iter.next();
199: // arFactory = new ActionRequestFactory(routeHeader);
200:
201: if (resp.isUsingRole()) {
202: makeRoleActionRequests(context, rule, resp,
203: routeHeader, parentRequest, ruleDelegation);
204: } else {
205: makeActionRequest(context, rule, routeHeader, resp,
206: parentRequest, ruleDelegation);
207: }
208: // if (arFactory.getRequestGraph() != null) {
209: // actionRequests.add(arFactory.getRequestGraph());
210: // }
211: }
212: // return new ArrayList(actionRequests);
213: }
214:
215: private void buildDelegationGraph(RouteContext context,
216: RuleBaseValues delegationRule,
217: DocumentRouteHeaderValue routeHeaderValue,
218: ActionRequestValue parentRequest,
219: RuleDelegation ruleDelegation)
220: throws EdenUserNotFoundException, WorkflowException {
221: context.setActionRequest(parentRequest);
222: if (delegationRule.getActiveInd().booleanValue()
223: && delegationRule.getToDate().after(new Date())
224: && delegationRule.getFromDate().before(new Date())) {
225: for (Iterator iter = delegationRule.getResponsibilities()
226: .iterator(); iter.hasNext();) {
227: RuleResponsibility delegationResp = (RuleResponsibility) iter
228: .next();
229: if (delegationResp.isUsingRole()) {
230: makeRoleActionRequests(context, delegationRule,
231: delegationResp, routeHeaderValue,
232: parentRequest, ruleDelegation);
233: } else if (delegationRule.isMatch(context
234: .getDocumentContent())) {
235: makeActionRequest(context, delegationRule,
236: routeHeaderValue, delegationResp,
237: parentRequest, ruleDelegation);
238: }
239: }
240: }
241: }
242:
243: private void makeRoleActionRequests(RouteContext context,
244: RuleBaseValues rule, RuleResponsibility resp,
245: DocumentRouteHeaderValue routeHeader,
246: ActionRequestValue parentRequest,
247: RuleDelegation ruleDelegation)
248: throws EdenUserNotFoundException, WorkflowException {
249:
250: String roleName = resp.getResolvedRoleName();
251: RoleAttribute roleAttribute = resp.resolveRoleAttribute();
252: List<String> qualifiedRoleNames = new ArrayList<String>();
253: if (parentRequest != null
254: && parentRequest.getQualifiedRoleName() != null) {
255: qualifiedRoleNames
256: .add(parentRequest.getQualifiedRoleName());
257: } else {
258: qualifiedRoleNames.addAll(roleAttribute
259: .getQualifiedRoleNames(roleName, context
260: .getDocumentContent()));
261: }
262: for (Iterator iter = qualifiedRoleNames.iterator(); iter
263: .hasNext();) {
264: String qualifiedRoleName = (String) iter.next();
265: if (parentRequest == null
266: && isDuplicateActionRequestDetected(rule,
267: routeHeader, context.getNodeInstance(),
268: resp, qualifiedRoleName)) {
269: continue;
270: }
271:
272: ResolvedQualifiedRole resolvedRole = roleAttribute
273: .resolveQualifiedRole(context, roleName,
274: qualifiedRoleName);
275: RoleRecipient recipient = new RoleRecipient(roleName,
276: qualifiedRoleName, resolvedRole);
277: if (parentRequest == null) {
278: ActionRequestValue roleRequest = arFactory
279: .addRoleRequest(recipient, resp
280: .getActionRequestedCd(), resp
281: .getApprovePolicy(),
282: resp.getPriority(), resp
283: .getResponsibilityId(), rule
284: .getIgnorePrevious(), rule
285: .getDescription(), rule
286: .getRuleBaseValuesId());
287: if (resp.isDelegating()) {
288: // create delegations for all the children
289: for (Iterator iterator = roleRequest
290: .getChildrenRequests().iterator(); iterator
291: .hasNext();) {
292: ActionRequestValue request = (ActionRequestValue) iterator
293: .next();
294: for (Iterator ruleDelegationIterator = resp
295: .getDelegationRules().iterator(); ruleDelegationIterator
296: .hasNext();) {
297: RuleDelegation childRuleDelegation = (RuleDelegation) ruleDelegationIterator
298: .next();
299: buildDelegationGraph(
300: context,
301: childRuleDelegation
302: .getDelegationRuleBaseValues(),
303: routeHeader, request,
304: childRuleDelegation);
305: }
306: }
307: }
308: } else {
309: arFactory.addDelegationRoleRequest(parentRequest, resp
310: .getApprovePolicy(), recipient, resp
311: .getResponsibilityId(), rule
312: .getIgnorePrevious(), ruleDelegation
313: .getDelegationType(), rule.getDescription(),
314: rule.getRuleBaseValuesId());
315: }
316: }
317: }
318:
319: private void makeActionRequest(RouteContext context,
320: RuleBaseValues rule, DocumentRouteHeaderValue routeHeader,
321: RuleResponsibility resp, ActionRequestValue parentRequest,
322: RuleDelegation ruleDelegation)
323: throws EdenUserNotFoundException, WorkflowException {
324: if (parentRequest == null
325: && isDuplicateActionRequestDetected(rule, routeHeader,
326: context.getNodeInstance(), resp, null)) {
327: return;
328: }
329: Recipient recipient;
330: if (resp.isUsingWorkflowUser()) {
331: recipient = KEWServiceLocator.getUserService()
332: .getWorkflowUser(
333: new WorkflowUserId(resp
334: .getRuleResponsibilityName()));
335: } else {
336: recipient = KEWServiceLocator.getWorkgroupService()
337: .getWorkgroup(
338: new WorkflowGroupId(new Long(resp
339: .getRuleResponsibilityName())));
340: }
341: ActionRequestValue actionRequest;
342: if (parentRequest == null) {
343: actionRequest = arFactory.addRootActionRequest(resp
344: .getActionRequestedCd(), resp.getPriority(),
345: recipient, rule.getDescription(), resp
346: .getResponsibilityId(), rule
347: .getIgnorePrevious(), resp
348: .getApprovePolicy(), rule
349: .getRuleBaseValuesId());
350: if (resp.isDelegating()) {
351: for (Iterator iterator = resp.getDelegationRules()
352: .iterator(); iterator.hasNext();) {
353: RuleDelegation childRuleDelegation = (RuleDelegation) iterator
354: .next();
355: buildDelegationGraph(context, childRuleDelegation
356: .getDelegationRuleBaseValues(),
357: routeHeader, actionRequest,
358: childRuleDelegation);
359: }
360: }
361: } else {
362: arFactory.addDelegationRequest(parentRequest, recipient,
363: resp.getResponsibilityId(), rule
364: .getIgnorePrevious(), ruleDelegation
365: .getDelegationType(),
366: rule.getDescription(), rule.getRuleBaseValuesId());
367: }
368: }
369:
370: private boolean isDuplicateActionRequestDetected(
371: RuleBaseValues rule, DocumentRouteHeaderValue routeHeader,
372: RouteNodeInstance nodeInstance, RuleResponsibility resp,
373: String qualifiedRoleName) {
374: List requests = getActionRequestService().findByStatusAndDocId(
375: EdenConstants.ACTION_REQUEST_DONE_STATE,
376: routeHeader.getRouteHeaderId());
377: for (Iterator iterator = requests.iterator(); iterator
378: .hasNext();) {
379: ActionRequestValue request = (ActionRequestValue) iterator
380: .next();
381: if (((nodeInstance != null
382: && request.getNodeInstance() != null && request
383: .getNodeInstance().getRouteNodeInstanceId().equals(
384: nodeInstance.getRouteNodeInstanceId())) || request
385: .getRouteLevel().equals(
386: routeHeader.getDocRouteLevel()))
387: && request.getResponsibilityId().equals(
388: resp.getResponsibilityId())
389: && ObjectUtils.equals(request
390: .getQualifiedRoleName(), qualifiedRoleName)) {
391: return true;
392: }
393: }
394: return false;
395: }
396:
397: public RuleService getRuleService() {
398: return (RuleService) KEWServiceLocator
399: .getService(KEWServiceLocator.RULE_SERVICE);
400: }
401:
402: private ActionRequestService getActionRequestService() {
403: return (ActionRequestService) KEWServiceLocator
404: .getService(KEWServiceLocator.ACTION_REQUEST_SRV);
405: }
406:
407: private RuleTemplateService getRuleTemplateService() {
408: return (RuleTemplateService) KEWServiceLocator
409: .getService(KEWServiceLocator.RULE_TEMPLATE_SERVICE);
410: }
411:
412: public int getNumberOfMatchingRules() {
413: return numberOfMatchingRules;
414: }
415: //
416: // private DocumentContent parseDocumentContent(RouteContext context) throws WorkflowException {
417: // try {
418: // return new StandardDocumentContent(context.getDocument().getDocContent(), context);
419: // } catch (Exception e) {
420: // throw new WorkflowException("Error parsing doc content for document " + context.getDocument().getRouteHeaderId());
421: // }
422: // }
423: }
|