0001: /*
0002: * Copyright 2005-2007 The Kuali Foundation.
0003: *
0004: *
0005: * Licensed under the Educational Community License, Version 1.0 (the "License");
0006: * you may not use this file except in compliance with the License.
0007: * You may obtain a copy of the License at
0008: *
0009: * http://www.opensource.org/licenses/ecl1.php
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017: package edu.iu.uis.eden.routetemplate;
0018:
0019: import java.io.InputStream;
0020: import java.sql.Timestamp;
0021: import java.text.ParseException;
0022: import java.util.ArrayList;
0023: import java.util.Collection;
0024: import java.util.Collections;
0025: import java.util.Comparator;
0026: import java.util.HashMap;
0027: import java.util.HashSet;
0028: import java.util.Iterator;
0029: import java.util.List;
0030: import java.util.Map;
0031: import java.util.Set;
0032:
0033: import org.apache.commons.lang.StringUtils;
0034: import org.jdom.Element;
0035:
0036: import edu.iu.uis.eden.EdenConstants;
0037: import edu.iu.uis.eden.KEWServiceLocator;
0038: import edu.iu.uis.eden.WorkflowServiceErrorException;
0039: import edu.iu.uis.eden.WorkflowServiceErrorImpl;
0040: import edu.iu.uis.eden.actionrequests.ActionRequestService;
0041: import edu.iu.uis.eden.applicationconstants.ApplicationConstantsService;
0042: import edu.iu.uis.eden.clientapp.WorkflowDocument;
0043: import edu.iu.uis.eden.clientapp.vo.WorkflowIdVO;
0044: import edu.iu.uis.eden.doctype.DocumentType;
0045: import edu.iu.uis.eden.doctype.DocumentTypeService;
0046: import edu.iu.uis.eden.exception.EdenUserNotFoundException;
0047: import edu.iu.uis.eden.export.ExportDataSet;
0048: import edu.iu.uis.eden.messaging.MessageServiceNames;
0049: import edu.iu.uis.eden.responsibility.ResponsibilityIdService;
0050: import edu.iu.uis.eden.routeheader.DocumentRouteHeaderValue;
0051: import edu.iu.uis.eden.routeheader.RouteHeaderService;
0052: import edu.iu.uis.eden.routetemplate.dao.RuleDAO;
0053: import edu.iu.uis.eden.routetemplate.dao.RuleResponsibilityDAO;
0054: import edu.iu.uis.eden.user.UserId;
0055: import edu.iu.uis.eden.user.UserService;
0056: import edu.iu.uis.eden.user.WorkflowUser;
0057: import edu.iu.uis.eden.util.PerformanceLogger;
0058: import edu.iu.uis.eden.util.Utilities;
0059: import edu.iu.uis.eden.validation.RuleValidationContext;
0060: import edu.iu.uis.eden.validation.ValidationResults;
0061: import edu.iu.uis.eden.web.session.UserSession;
0062: import edu.iu.uis.eden.workgroup.GroupId;
0063: import edu.iu.uis.eden.workgroup.WorkflowGroupId;
0064: import edu.iu.uis.eden.workgroup.Workgroup;
0065: import edu.iu.uis.eden.workgroup.WorkgroupService;
0066: import edu.iu.uis.eden.xml.RuleXmlParser;
0067: import edu.iu.uis.eden.xml.export.RuleXmlExporter;
0068:
0069: public class RuleServiceImpl implements RuleService {
0070:
0071: private static final String USING_RULE_CACHE_KEY = "RuleService.IsCaching";
0072: private static final String XML_PARSE_ERROR = "general.error.parsexml";
0073:
0074: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
0075: .getLogger(RuleServiceImpl.class);
0076:
0077: private RuleDAO ruleDAO;
0078: private RuleResponsibilityDAO ruleResponsibilityDAO;
0079:
0080: public RuleResponsibilityDAO getRuleResponsibilityDAO() {
0081: return ruleResponsibilityDAO;
0082: }
0083:
0084: public RuleBaseValues findDefaultRuleByRuleTemplateId(
0085: Long ruleTemplateId) {
0086: return this .ruleDAO
0087: .findDefaultRuleByRuleTemplateId(ruleTemplateId);
0088: }
0089:
0090: public void setRuleResponsibilityDAO(
0091: RuleResponsibilityDAO ruleResponsibilityDAO) {
0092: this .ruleResponsibilityDAO = ruleResponsibilityDAO;
0093: }
0094:
0095: public void save2(RuleBaseValues ruleBaseValues) throws Exception {
0096: save2(ruleBaseValues, null, true);
0097: }
0098:
0099: public void save2(RuleBaseValues ruleBaseValues,
0100: RuleDelegation ruleDelegation, boolean saveDelegations)
0101: throws Exception {
0102: if (ruleBaseValues.getPreviousVersionId() != null) {
0103: RuleBaseValues oldRule = findRuleBaseValuesById(ruleBaseValues
0104: .getPreviousVersionId());
0105: ruleBaseValues.setPreviousVersion(oldRule);
0106: ruleBaseValues.setCurrentInd(new Boolean(false));
0107: ruleBaseValues.setVersionNbr(getNextVersionNumber(oldRule));
0108: }
0109: if (ruleBaseValues.getVersionNbr() == null) {
0110: ruleBaseValues.setVersionNbr(new Integer(0));
0111: }
0112: if (ruleBaseValues.getCurrentInd() == null) {
0113: ruleBaseValues.setCurrentInd(new Boolean(false));
0114: }
0115: // iterate through all associated responsibilities, and if they are unsaved (responsibilityId is null)
0116: // set a new id on them, and recursively save any associated delegation rules
0117: for (Iterator iterator = ruleBaseValues.getResponsibilities()
0118: .iterator(); iterator.hasNext();) {
0119: RuleResponsibility responsibility = (RuleResponsibility) iterator
0120: .next();
0121: if (responsibility.getResponsibilityId() == null) {
0122: responsibility
0123: .setResponsibilityId(getResponsibilityIdService()
0124: .getNewResponsibilityId());
0125: }
0126: if (saveDelegations) {
0127: for (Iterator iter = responsibility
0128: .getDelegationRules().iterator(); iter
0129: .hasNext();) {
0130: RuleDelegation localRuleDelegation = (RuleDelegation) iter
0131: .next();
0132: save2(localRuleDelegation
0133: .getDelegationRuleBaseValues(),
0134: localRuleDelegation, true);
0135: }
0136: }
0137: }
0138: validate2(ruleBaseValues, ruleDelegation, null);
0139: getRuleDAO().save(ruleBaseValues);
0140: }
0141:
0142: public void makeCurrent(Long routeHeaderId)
0143: throws EdenUserNotFoundException {
0144: PerformanceLogger performanceLogger = new PerformanceLogger();
0145: List rules = findByRouteHeaderId(routeHeaderId);
0146: boolean isGenerateRuleArs = EdenConstants.YES_RULE_CHANGE_AR_GENERATION_VALUE
0147: .equalsIgnoreCase(getApplicationConstantsService()
0148: .findByName(
0149: EdenConstants.RULE_CHANGE_AR_GENERATION_KEY)
0150: .getApplicationConstantValue());
0151: boolean isGenerateDelegateArs = EdenConstants.YES_DELEGATE_CHANGE_AR_GENERATION_VALUE
0152: .equalsIgnoreCase(getApplicationConstantsService()
0153: .findByName(
0154: EdenConstants.DELEGATE_CHANGE_AR_GENERATION_KEY)
0155: .getApplicationConstantValue());
0156: Set responsibilityIds = new HashSet();
0157: HashMap rulesToSave = new HashMap();
0158:
0159: Collections.sort(rules, new RuleDelegationSorter());
0160: boolean delegateFirst = false;
0161: for (Iterator iter = rules.iterator(); iter.hasNext();) {
0162: RuleBaseValues rule = (RuleBaseValues) iter.next();
0163:
0164: performanceLogger.log("Preparing rule: "
0165: + rule.getDescription());
0166:
0167: rule.setCurrentInd(Boolean.TRUE);
0168: Timestamp date = new Timestamp(System.currentTimeMillis());
0169: rule.setActivationDate(date);
0170: try {
0171: rule.setDeactivationDate(new Timestamp(EdenConstants
0172: .getDefaultDateFormat().parse("01/01/2100")
0173: .getTime()));
0174: } catch (Exception e) {
0175: LOG.error("Parse Exception", e);
0176: }
0177: rulesToSave.put(rule.getRuleBaseValuesId(), rule);
0178: RuleBaseValues oldRule = rule.getPreviousVersion();
0179: if (oldRule != null) {
0180: performanceLogger.log("Setting previous rule: "
0181: + oldRule.getRuleBaseValuesId()
0182: + " to non current.");
0183:
0184: oldRule.setCurrentInd(Boolean.FALSE);
0185: oldRule.setDeactivationDate(date);
0186: rulesToSave.put(oldRule.getRuleBaseValuesId(), oldRule);
0187: if (!delegateFirst) {
0188: responsibilityIds
0189: .addAll(getResponsibilityIdsFromGraph(
0190: oldRule, isGenerateRuleArs,
0191: isGenerateDelegateArs));
0192: }
0193: //TODO if more than one delegate is edited from the create delegation screen (which currently can not happen), then this logic will not work.
0194: if (rule.getDelegateRule().booleanValue()
0195: && rule.getPreviousVersionId() != null) {
0196: delegateFirst = true;
0197: }
0198:
0199: List oldDelegationRules = findOldDelegationRules(
0200: oldRule, rule, performanceLogger);
0201: for (Iterator iterator = oldDelegationRules.iterator(); iterator
0202: .hasNext();) {
0203: RuleBaseValues delegationRule = (RuleBaseValues) iterator
0204: .next();
0205:
0206: performanceLogger
0207: .log("Setting previous delegation rule: "
0208: + delegationRule
0209: .getRuleBaseValuesId()
0210: + "to non current.");
0211:
0212: delegationRule.setCurrentInd(Boolean.FALSE);
0213: rulesToSave.put(delegationRule
0214: .getRuleBaseValuesId(), delegationRule);
0215: responsibilityIds
0216: .addAll(getResponsibilityIdsFromGraph(
0217: delegationRule, isGenerateRuleArs,
0218: isGenerateDelegateArs));
0219: }
0220: }
0221: for (Iterator iterator = rule.getResponsibilities()
0222: .iterator(); iterator.hasNext();) {
0223: RuleResponsibility responsibility = (RuleResponsibility) iterator
0224: .next();
0225: for (Iterator delIterator = responsibility
0226: .getDelegationRules().iterator(); delIterator
0227: .hasNext();) {
0228: RuleDelegation delegation = (RuleDelegation) delIterator
0229: .next();
0230:
0231: delegation.getDelegationRuleBaseValues()
0232: .setCurrentInd(Boolean.TRUE);
0233: RuleBaseValues delegatorRule = delegation
0234: .getDelegationRuleBaseValues();
0235:
0236: performanceLogger.log("Setting delegate rule: "
0237: + delegatorRule.getDescription()
0238: + " to current.");
0239: if (delegatorRule.getActivationDate() == null) {
0240: delegatorRule.setActivationDate(date);
0241: }
0242: try {
0243: delegatorRule
0244: .setDeactivationDate(new Timestamp(
0245: EdenConstants
0246: .getDefaultDateFormat()
0247: .parse("01/01/2100")
0248: .getTime()));
0249: } catch (Exception e) {
0250: LOG.error("Parse Exception", e);
0251: }
0252: rulesToSave.put(
0253: delegatorRule.getRuleBaseValuesId(),
0254: delegatorRule);
0255: }
0256: }
0257: }
0258: Map<String, Long> notifyMap = new HashMap<String, Long>();
0259: for (Iterator iterator = rulesToSave.values().iterator(); iterator
0260: .hasNext();) {
0261: RuleBaseValues rule = (RuleBaseValues) iterator.next();
0262: getRuleDAO().save(rule);
0263: performanceLogger.log("Saved rule: "
0264: + rule.getRuleBaseValuesId());
0265: installNotification(rule, notifyMap);
0266: }
0267: LOG.info("Notifying rule cache of " + notifyMap.size()
0268: + " cache changes.");
0269: for (Iterator iterator = notifyMap.values().iterator(); iterator
0270: .hasNext();) {
0271: queueRuleCache((Long) iterator.next());
0272: }
0273:
0274: getActionRequestService()
0275: .updateActionRequestsForResponsibilityChange(
0276: responsibilityIds);
0277: performanceLogger.log("Time to make current");
0278: }
0279:
0280: private void queueRuleCache(Long ruleId) {
0281: // PersistedMessage ruleCache = new PersistedMessage();
0282: // ruleCache.setQueuePriority(EdenConstants.ROUTE_QUEUE_RULE_CACHE_PRIORITY);
0283: // ruleCache.setQueueDate(new Timestamp(new Date().getTime()));
0284: // ruleCache.setQueueStatus(EdenConstants.ROUTE_QUEUE_QUEUED);
0285: // ruleCache.setRetryCount(new Integer(0));
0286: // ruleCache.setPayload("" + ruleId);
0287: // ruleCache.setProcessorClassName("edu.iu.uis.eden.cache.RuleCacheProcessor");
0288: // getRouteQueueService().requeueDocument(ruleCache);
0289:
0290: RuleCacheProcessor ruleCacheProcessor = MessageServiceNames
0291: .getRuleCacheProcessor();
0292: ruleCacheProcessor.clearRuleFromCache(ruleId);
0293:
0294: }
0295:
0296: // private RouteQueueService getRouteQueueService() {
0297: // return (RouteQueueService)SpringServiceLocator.getService(SpringServiceLocator.ROUTE_QUEUE_SRV);
0298: // }
0299:
0300: /**
0301: * Ensure that we don't have any notification duplication.
0302: */
0303: private void installNotification(RuleBaseValues rule,
0304: Map<String, Long> notifyMap) {
0305: String key = getRuleCacheKey(rule.getRuleTemplateName(), rule
0306: .getDocTypeName());
0307: if (!notifyMap.containsKey(key)) {
0308: notifyMap.put(key, rule.getRuleBaseValuesId());
0309: }
0310: }
0311:
0312: public RuleBaseValues getParentRule(Long ruleBaseValuesId) {
0313: return getRuleDAO().getParentRule(ruleBaseValuesId);
0314: }
0315:
0316: public void notifyCacheOfDocumentTypeChange(
0317: DocumentType documentType) {
0318: DocumentType rootDocumentType = KEWServiceLocator
0319: .getDocumentTypeService().findRootDocumentType(
0320: documentType);
0321: notifyCacheOfDocumentTypeChangeFromRoot(rootDocumentType,
0322: documentType);
0323: notifyCacheOfDocumentTypeChangeFromParent(documentType);
0324: }
0325:
0326: /**
0327: * Flushes rules cached for the given DocumentType and then recursivley flushes rules cached
0328: * for all children DocumentTypes.
0329: */
0330: protected void notifyCacheOfDocumentTypeChangeFromParent(
0331: DocumentType documentType) {
0332: flushDocumentTypeFromCache(documentType.getName());
0333: for (Iterator iter = documentType.getChildrenDocTypes()
0334: .iterator(); iter.hasNext();) {
0335: notifyCacheOfDocumentTypeChangeFromParent((DocumentType) iter
0336: .next());
0337: }
0338: }
0339:
0340: /**
0341: * Flushes rules cached from the root of the DocumentType hierarchy (at the given root DocumentType). Stops
0342: * when it hits the given DocumentType. This method exists because of the nature of
0343: * DocumentTypeService.findRootDocumentType(...). Whenever we have a modification to child document type
0344: * and we call findRootDocumentType(...) on it, we end up getting back a version of the root document type
0345: * which is cached in the OJB transaction cache and doesn't have the appropriate child document type attached.
0346: * A better way to handle this would be to go into the DocumentType service and fix how it versions document
0347: * types in versionAndSave to prevent this issue from occurring.
0348: *
0349: * <p>If such a fix was made then we could simply pass the root DocumentType into notifyCacheOfDocumentTypeChange
0350: * and be gauranteed that we will see all appropriate children as we call getChildrenDocTypes().
0351: *
0352: * <p>One last note, we don't necesarily have to stop this cache flusing at the given DocumentType but there's
0353: * no reason to duplicate the work that is going to be done in notifyCacheOfDocumentTypeChangeFromParent.
0354: */
0355: protected void notifyCacheOfDocumentTypeChangeFromRoot(
0356: DocumentType rootDocumentType, DocumentType documentType) {
0357: if (rootDocumentType.getName().equals(documentType.getName())) {
0358: return;
0359: }
0360: flushDocumentTypeFromCache(rootDocumentType.getName());
0361: for (Iterator iter = rootDocumentType.getChildrenDocTypes()
0362: .iterator(); iter.hasNext();) {
0363: notifyCacheOfDocumentTypeChangeFromRoot((DocumentType) iter
0364: .next(), documentType);
0365: }
0366: }
0367:
0368: public void notifyCacheOfRuleChange(RuleBaseValues rule,
0369: DocumentType documentType) {
0370: Boolean cachingRules = new Boolean(Utilities
0371: .getApplicationConstant(USING_RULE_CACHE_KEY));
0372: if (!cachingRules.booleanValue()) {
0373: return;
0374: }
0375: String ruleTemplateName = rule.getRuleTemplate().getName();
0376: if (documentType == null) {
0377: documentType = getDocumentTypeService().findByName(
0378: rule.getDocTypeName());
0379: // if it's a delegate rule, we need to look at the parent's template
0380: if (Boolean.TRUE.equals(rule.getDelegateRule())) {
0381: List delegations = getRuleDelegationService()
0382: .findByDelegateRuleId(
0383: rule.getRuleBaseValuesId());
0384: for (Iterator iterator = delegations.iterator(); iterator
0385: .hasNext();) {
0386: RuleDelegation ruleDelegation = (RuleDelegation) iterator
0387: .next();
0388: RuleBaseValues parentRule = ruleDelegation
0389: .getRuleResponsibility()
0390: .getRuleBaseValues();
0391: if (Boolean.TRUE.equals(parentRule.getCurrentInd())) {
0392: ruleTemplateName = parentRule.getRuleTemplate()
0393: .getName();
0394: break;
0395: }
0396: }
0397: }
0398: }
0399: flushListFromCache(ruleTemplateName, documentType.getName());
0400: // if (getListFromCache(ruleTemplateName, documentType.getName()) != null) {
0401: // eventGenerator.notify(new CacheDataModifiedEvent(RULE_CACHE_NAME, getRuleCacheKey(ruleTemplateName, documentType.getName())));
0402: // }
0403: //}
0404: //walk the down the document hierarchy when refreshing the cache. The
0405: // rule could be cached through more than one path
0406: //HREDOC could be cached under HREDOC.child and HREDOC.child1
0407: for (Iterator iter = documentType.getChildrenDocTypes()
0408: .iterator(); iter.hasNext();) {
0409: DocumentType childDocumentType = (DocumentType) iter.next();
0410: //SpringServiceLocator.getCacheAdministrator().flushEntry(getRuleCacheKey(ruleTemplateName, childDocumentType.getName()));
0411: // if (getListFromCache(rule.getRuleTemplate().getName(), childDocumentType.getName()) != null) {
0412: // eventGenerator.notify(new CacheDataModifiedEvent(RULE_CACHE_NAME, getRuleCacheKey(rule.getRuleTemplate().getName(), childDocumentType.getName())));
0413: // }
0414: notifyCacheOfRuleChange(rule, childDocumentType);
0415: }
0416: }
0417:
0418: /**
0419: * Returns the key of the rule cache.
0420: */
0421: protected String getRuleCacheKey(String ruleTemplateName,
0422: String docTypeName) {
0423: return "RuleCache:" + ruleTemplateName + "_" + docTypeName;
0424: }
0425:
0426: /*
0427: * Return the cache group name for the given DocumentType
0428: */
0429: protected String getDocumentTypeRuleCacheGroupName(
0430: String documentTypeName) {
0431: return "DocumentTypeRuleCache:" + documentTypeName;
0432: }
0433:
0434: protected List<RuleBaseValues> getListFromCache(
0435: String ruleTemplateName, String documentTypeName) {
0436: LOG
0437: .debug("Retrieving List of Rules from cache for ruleTemplate='"
0438: + ruleTemplateName
0439: + "' and documentType='"
0440: + documentTypeName + "'");
0441: return (List) KEWServiceLocator.getCacheAdministrator()
0442: .getFromCache(
0443: getRuleCacheKey(ruleTemplateName,
0444: documentTypeName));
0445: //return (List) SpringServiceLocator.getCache().getCachedObjectById(RULE_CACHE_NAME, getRuleCacheKey(ruleTemplateName, documentTypeName));
0446: }
0447:
0448: protected void putListInCache(String ruleTemplateName,
0449: String documentTypeName, List<RuleBaseValues> rules) {
0450: LOG.info("Caching " + rules.size()
0451: + " rules for ruleTemplate='" + ruleTemplateName
0452: + "' and documentType='" + documentTypeName + "'");
0453: KEWServiceLocator.getCacheAdministrator().putInCache(
0454: getRuleCacheKey(ruleTemplateName, documentTypeName),
0455: rules,
0456: getDocumentTypeRuleCacheGroupName(documentTypeName));
0457: }
0458:
0459: protected void flushDocumentTypeFromCache(String documentTypeName) {
0460: LOG
0461: .info("Flushing DocumentType from Cache for the given name: "
0462: + documentTypeName);
0463: KEWServiceLocator.getCacheAdministrator().flushGroup(
0464: getDocumentTypeRuleCacheGroupName(documentTypeName));
0465: }
0466:
0467: protected void flushListFromCache(String ruleTemplateName,
0468: String documentTypeName) {
0469: LOG.info("Flushing rules from Cache for ruleTemplate='"
0470: + ruleTemplateName + "' and documentType='"
0471: + documentTypeName + "'");
0472: KEWServiceLocator.getCacheAdministrator().flushEntry(
0473: getRuleCacheKey(ruleTemplateName, documentTypeName));
0474: }
0475:
0476: private Set getResponsibilityIdsFromGraph(RuleBaseValues rule,
0477: boolean isRuleCollecting, boolean isDelegationCollecting) {
0478: Set responsibilityIds = new HashSet();
0479: for (Iterator iterator = rule.getResponsibilities().iterator(); iterator
0480: .hasNext();) {
0481: RuleResponsibility responsibility = (RuleResponsibility) iterator
0482: .next();
0483: if (isRuleCollecting) {
0484: responsibilityIds.add(responsibility
0485: .getResponsibilityId());
0486: }
0487: // TODO why is this commented out? - Good question.
0488: // if (isDelegationCollecting && responsibility.isDelegating()) {
0489: // for (Iterator iter =
0490: // responsibility.getDelegationRules().iterator(); iter.hasNext();)
0491: // {
0492: // RuleDelegation ruleDelegation = (RuleDelegation) iter.next();
0493: // for (Iterator iterator2 =
0494: // ruleDelegation.getDelegationRuleBaseValues().getResponsibilities().iterator();
0495: // iterator2.hasNext();) {
0496: // RuleResponsibility delegationResp = (RuleResponsibility)
0497: // iterator2.next();
0498: // responsibilityIds.add(delegationResp.getRuleResponsibilityId());
0499: // }
0500: // }
0501: // }
0502: }
0503: return responsibilityIds;
0504: }
0505:
0506: /*
0507: private Map findOldDelegationRules(RuleBaseValues oldRule, RuleBaseValues newRule, PerformanceLogger performanceLogger) {
0508: Map oldRules = new HashMap();
0509: performanceLogger.log("Begin to get delegation rules.");
0510: for (Iterator iterator = oldRule.getResponsibilities().iterator(); iterator.hasNext();) {
0511: RuleResponsibility responsibility = (RuleResponsibility) iterator.next();
0512: for (Iterator delIterator = responsibility.getDelegationRules().iterator(); delIterator.hasNext();) {
0513: RuleDelegation ruleDelegation = (RuleDelegation) delIterator.next();
0514: RuleBaseValues delegateRule = ruleDelegation.getDelegationRuleBaseValues();
0515: performanceLogger.log("Found delegate rule: "+ delegateRule.getRuleBaseValuesId());
0516: oldRules.put(ruleDelegation.getDelegateRuleId(), delegateRule);
0517: }
0518: }
0519: performanceLogger.log("Begin removing rule delegations from new rule.");
0520: for (Iterator iterator = newRule.getResponsibilities().iterator(); iterator.hasNext();) {
0521: RuleResponsibility responsibility = (RuleResponsibility) iterator.next();
0522: for (Iterator delIterator = responsibility.getDelegationRules().iterator(); delIterator.hasNext();) {
0523: RuleDelegation ruleDelegation = (RuleDelegation) delIterator.next();
0524: performanceLogger.log("Removing rule delegation: "+ ruleDelegation.getDelegateRuleId()+" from new rule.");
0525: oldRules.remove(ruleDelegation.getDelegateRuleId());
0526: }
0527: }
0528: return oldRules;
0529: }
0530: */
0531: /**
0532: * This method will find any old delegation rules on the previous version of the parent rule which are not on the
0533: * new version of the rule so that they can be marked non-current.
0534: */
0535: private List findOldDelegationRules(RuleBaseValues oldRule,
0536: RuleBaseValues newRule, PerformanceLogger performanceLogger) {
0537: performanceLogger.log("Begin to get delegation rules.");
0538: List oldDelegations = getRuleDAO().findOldDelegations(oldRule,
0539: newRule);
0540: performanceLogger.log("Located " + oldDelegations.size()
0541: + " old delegation rules.");
0542: return oldDelegations;
0543: }
0544:
0545: public Long route2(Long routeHeaderId, MyRules2 myRules,
0546: WorkflowUser user, String annotation, boolean blanketApprove)
0547: throws Exception {
0548: List errors = new ArrayList();
0549: if (myRules.getRules().isEmpty()) {
0550: errors.add(new WorkflowServiceErrorImpl("Rule required",
0551: "rule.required"));
0552: }
0553: if (!errors.isEmpty()) {
0554: throw new WorkflowServiceErrorException(
0555: "RuleBaseValues validation errors", errors);
0556: }
0557: WorkflowDocument flexDoc = null;
0558: if (routeHeaderId == null) {
0559: flexDoc = new WorkflowDocument(new WorkflowIdVO(user
0560: .getWorkflowId()), getRuleDocmentTypeName(myRules
0561: .getRules()));
0562: } else {
0563: flexDoc = new WorkflowDocument(new WorkflowIdVO(user
0564: .getWorkflowId()), routeHeaderId);
0565: }
0566:
0567: for (Iterator iter = myRules.getRules().iterator(); iter
0568: .hasNext();) {
0569: RuleBaseValues rule = (RuleBaseValues) iter.next();
0570: rule.setRouteHeaderId(flexDoc.getRouteHeaderId());
0571:
0572: flexDoc.addAttributeDefinition(new RuleRoutingDefinition(
0573: rule.getDocTypeName()));
0574: getRuleDAO().retrieveAllReferences(rule);
0575: save2(rule);
0576: }
0577:
0578: flexDoc.setTitle(generateTitle(myRules));
0579: if (blanketApprove) {
0580: flexDoc.blanketApprove(annotation);
0581: } else {
0582: flexDoc.routeDocument(annotation);
0583: }
0584: return flexDoc.getRouteHeaderId();
0585: }
0586:
0587: public Long routeRuleWithDelegate(Long routeHeaderId,
0588: RuleBaseValues parentRule, RuleBaseValues delegateRule,
0589: WorkflowUser user, String annotation, boolean blanketApprove)
0590: throws Exception {
0591: if (parentRule == null) {
0592: throw new IllegalArgumentException(
0593: "Cannot route a delegate without a parent rule.");
0594: }
0595: if (parentRule.getDelegateRule().booleanValue()) {
0596: throw new IllegalArgumentException(
0597: "Parent rule cannot be a delegate.");
0598: }
0599: if (parentRule.getPreviousVersionId() == null
0600: && delegateRule.getPreviousVersionId() == null) {
0601: throw new IllegalArgumentException(
0602: "Previous rule version required.");
0603: }
0604:
0605: // if the parent rule is new, unsaved, then save it
0606: boolean isRoutingParent = parentRule.getRuleBaseValuesId() == null;
0607: if (isRoutingParent) {
0608: save2(parentRule, null, true);
0609: }
0610:
0611: // XXX: added when the RuleValidation stuff was added, basically we just need to get the RuleDelegation
0612: // that points to our delegate rule, this rule code is scary...
0613: RuleDelegation ruleDelegation = getRuleDelegation(parentRule,
0614: delegateRule);
0615:
0616: save2(delegateRule, ruleDelegation, true);
0617: WorkflowDocument flexDoc = null;
0618: if (routeHeaderId != null) {
0619: flexDoc = new WorkflowDocument(new WorkflowIdVO(user
0620: .getWorkflowId()), routeHeaderId);
0621: } else {
0622: List rules = new ArrayList();
0623: rules.add(delegateRule);
0624: rules.add(parentRule);
0625: flexDoc = new WorkflowDocument(new WorkflowIdVO(user
0626: .getWorkflowId()), getRuleDocmentTypeName(rules));
0627: }
0628: flexDoc.setTitle(generateTitle(parentRule, delegateRule));
0629: delegateRule.setRouteHeaderId(flexDoc.getRouteHeaderId());
0630: flexDoc.addAttributeDefinition(new RuleRoutingDefinition(
0631: parentRule.getDocTypeName()));
0632: getRuleDAO().save(delegateRule);
0633: if (isRoutingParent) {
0634: parentRule.setRouteHeaderId(flexDoc.getRouteHeaderId());
0635: getRuleDAO().save(parentRule);
0636: }
0637: if (blanketApprove) {
0638: flexDoc.blanketApprove(annotation);
0639: } else {
0640: flexDoc.routeDocument(annotation);
0641: }
0642: return flexDoc.getRouteHeaderId();
0643: }
0644:
0645: /**
0646: * Gets the RuleDelegation object from the parentRule that points to the delegateRule.
0647: */
0648: private RuleDelegation getRuleDelegation(RuleBaseValues parentRule,
0649: RuleBaseValues delegateRule) throws Exception {
0650: for (Iterator iterator = parentRule.getResponsibilities()
0651: .iterator(); iterator.hasNext();) {
0652: RuleResponsibility responsibility = (RuleResponsibility) iterator
0653: .next();
0654: for (Iterator respIt = responsibility.getDelegationRules()
0655: .iterator(); respIt.hasNext();) {
0656: RuleDelegation ruleDelegation = (RuleDelegation) respIt
0657: .next();
0658: // they should be the same object in memory...I think...I'm going to try and unit test some
0659: // of this stuff because I don't like trying to divine what this stuff is doing everytime
0660: // I look at it
0661: if (ruleDelegation.getDelegationRuleBaseValues()
0662: .equals(delegateRule)) {
0663: return ruleDelegation;
0664: }
0665: }
0666: }
0667: return null;
0668: }
0669:
0670: private String generateTitle(RuleBaseValues parentRule,
0671: RuleBaseValues delegateRule) {
0672: StringBuffer title = new StringBuffer();
0673: if (delegateRule.getPreviousVersionId() != null) {
0674: title.append("Editing Delegation Rule '").append(
0675: delegateRule.getDescription()).append("' on '");
0676: } else {
0677: title.append("Adding Delegation Rule '").append(
0678: delegateRule.getDescription()).append("' to '");
0679: }
0680: title.append(parentRule.getDescription()).append("'");
0681: return title.toString();
0682: }
0683:
0684: private String generateTitle(MyRules2 myRules) {
0685: StringBuffer title = new StringBuffer();
0686: RuleBaseValues firstRule = myRules.getRule(0);
0687: if (myRules.getRules().size() > 1) {
0688: title.append("Routing ").append(myRules.getSize()).append(
0689: " Rules, '");
0690: title.append(firstRule.getDescription()).append("',...");
0691: } else if (firstRule.getPreviousVersionId() != null) {
0692: title.append("Editing Rule '").append(
0693: firstRule.getDescription()).append("'");
0694: } else {
0695: title.append("Adding Rule '").append(
0696: firstRule.getDescription()).append("'");
0697: }
0698: return title.toString();
0699: }
0700:
0701: public void validate(RuleBaseValues ruleBaseValues, List errors)
0702: throws EdenUserNotFoundException {
0703: if (errors == null) {
0704: errors = new ArrayList();
0705: }
0706: if (getDocumentTypeService().findByName(
0707: ruleBaseValues.getDocTypeName()) == null) {
0708: errors
0709: .add(new WorkflowServiceErrorImpl(
0710: "Document Type Invalid",
0711: "doctype.documenttypeservice.doctypename.required"));
0712: }
0713: if (ruleBaseValues.getToDate().before(
0714: ruleBaseValues.getFromDate())) {
0715: errors.add(new WorkflowServiceErrorImpl(
0716: "From Date is later than to date",
0717: "routetemplate.ruleservice.daterange.fromafterto"));
0718: }
0719: if (ruleBaseValues.getActiveInd() == null) {
0720: errors.add(new WorkflowServiceErrorImpl(
0721: "Active Indicator is required",
0722: "routetemplate.ruleservice.activeind.required"));
0723: }
0724: if (ruleBaseValues.getDescription() == null
0725: || ruleBaseValues.getDescription().equals("")) {
0726: errors.add(new WorkflowServiceErrorImpl(
0727: "Description is required",
0728: "routetemplate.ruleservice.description.required"));
0729: }
0730: if (ruleBaseValues.getIgnorePrevious() == null) {
0731: errors
0732: .add(new WorkflowServiceErrorImpl(
0733: "Ignore Previous is required",
0734: "routetemplate.ruleservice.ignoreprevious.required"));
0735: }
0736: if (ruleBaseValues.getResponsibilities().isEmpty()) {
0737: errors
0738: .add(new WorkflowServiceErrorImpl(
0739: "A responsibility is required",
0740: "routetemplate.ruleservice.responsibility.required"));
0741: } else {
0742: for (Iterator iter = ruleBaseValues.getResponsibilities()
0743: .iterator(); iter.hasNext();) {
0744: RuleResponsibility responsibility = (RuleResponsibility) iter
0745: .next();
0746: if (responsibility.getRuleResponsibilityName() != null
0747: && EdenConstants.RULE_RESPONSIBILITY_WORKGROUP_ID
0748: .equals(responsibility
0749: .getRuleResponsibilityType())) {
0750: if (getWorkgroupService().getWorkgroup(
0751: new WorkflowGroupId(new Long(responsibility
0752: .getRuleResponsibilityName()))) == null) {
0753: errors
0754: .add(new WorkflowServiceErrorImpl(
0755: "Workgroup is invalid",
0756: "routetemplate.ruleservice.workgroup.invalid"));
0757: }
0758: } else if (responsibility.getWorkflowUser() == null
0759: && responsibility.getRole() == null) {
0760: errors.add(new WorkflowServiceErrorImpl(
0761: "User is invalid",
0762: "routetemplate.ruleservice.user.invalid"));
0763: }
0764: }
0765: }
0766: if (!errors.isEmpty()) {
0767: throw new WorkflowServiceErrorException(
0768: "RuleBaseValues validation errors", errors);
0769: }
0770: }
0771:
0772: public void validate2(RuleBaseValues ruleBaseValues,
0773: RuleDelegation ruleDelegation, List errors)
0774: throws EdenUserNotFoundException {
0775: if (errors == null) {
0776: errors = new ArrayList();
0777: }
0778: if (getDocumentTypeService().findByName(
0779: ruleBaseValues.getDocTypeName()) == null) {
0780: errors
0781: .add(new WorkflowServiceErrorImpl(
0782: "Document Type Invalid",
0783: "doctype.documenttypeservice.doctypename.required"));
0784: LOG.error("Document Type Invalid");
0785: }
0786: if (ruleBaseValues.getToDate() == null) {
0787: try {
0788: ruleBaseValues.setToDate(new Timestamp(EdenConstants
0789: .getDefaultDateFormat().parse("01/01/2100")
0790: .getTime()));
0791: } catch (ParseException e) {
0792: LOG.error("Error date-parsing default date");
0793: throw new WorkflowServiceErrorException(
0794: "Error parsing default date.", e);
0795: }
0796: }
0797: if (ruleBaseValues.getFromDate() == null) {
0798: ruleBaseValues.setFromDate(new Timestamp(System
0799: .currentTimeMillis()));
0800: }
0801: if (ruleBaseValues.getToDate().before(
0802: ruleBaseValues.getFromDate())) {
0803: errors.add(new WorkflowServiceErrorImpl(
0804: "From Date is later than to date",
0805: "routetemplate.ruleservice.daterange.fromafterto"));
0806: LOG.error("From Date is later than to date");
0807: }
0808: if (ruleBaseValues.getActiveInd() == null) {
0809: errors.add(new WorkflowServiceErrorImpl(
0810: "Active Indicator is required",
0811: "routetemplate.ruleservice.activeind.required"));
0812: LOG.error("Active Indicator is missing");
0813: }
0814: if (ruleBaseValues.getDescription() == null
0815: || ruleBaseValues.getDescription().equals("")) {
0816: errors.add(new WorkflowServiceErrorImpl(
0817: "Description is required",
0818: "routetemplate.ruleservice.description.required"));
0819: LOG.error("Description is missing");
0820: }
0821: if (ruleBaseValues.getIgnorePrevious() == null) {
0822: errors
0823: .add(new WorkflowServiceErrorImpl(
0824: "Ignore Previous is required",
0825: "routetemplate.ruleservice.ignoreprevious.required"));
0826: LOG.error("Ignore Previous is missing");
0827: }
0828: if (ruleBaseValues.getResponsibilities().isEmpty()) {
0829: errors
0830: .add(new WorkflowServiceErrorImpl(
0831: "A responsibility is required",
0832: "routetemplate.ruleservice.responsibility.required"));
0833: LOG.error("Rule does not have a responsibility");
0834: } else {
0835: for (Iterator iter = ruleBaseValues.getResponsibilities()
0836: .iterator(); iter.hasNext();) {
0837: RuleResponsibility responsibility = (RuleResponsibility) iter
0838: .next();
0839: if (responsibility.getRuleResponsibilityName() != null
0840: && EdenConstants.RULE_RESPONSIBILITY_WORKGROUP_ID
0841: .equals(responsibility
0842: .getRuleResponsibilityType())) {
0843: if (getWorkgroupService().getWorkgroup(
0844: new WorkflowGroupId(new Long(responsibility
0845: .getRuleResponsibilityName()))) == null) {
0846: errors
0847: .add(new WorkflowServiceErrorImpl(
0848: "Workgroup is invalid",
0849: "routetemplate.ruleservice.workgroup.invalid"));
0850: LOG.error("Workgroup is invalid");
0851: }
0852: } else if (responsibility.getWorkflowUser() == null
0853: && responsibility.getRole() == null) {
0854: errors.add(new WorkflowServiceErrorImpl(
0855: "User is invalid",
0856: "routetemplate.ruleservice.user.invalid"));
0857: LOG.error("User is invalid");
0858: } else if (responsibility.isUsingRole()) {
0859: if (responsibility.getApprovePolicy() == null
0860: || !(responsibility
0861: .getApprovePolicy()
0862: .equals(
0863: EdenConstants.APPROVE_POLICY_ALL_APPROVE) || responsibility
0864: .getApprovePolicy()
0865: .equals(
0866: EdenConstants.APPROVE_POLICY_FIRST_APPROVE))) {
0867: errors
0868: .add(new WorkflowServiceErrorImpl(
0869: "Approve Policy is Invalid",
0870: "routetemplate.ruleservice.approve.policy.invalid"));
0871: LOG.error("Approve Policy is Invalid");
0872: }
0873: }
0874: }
0875: }
0876:
0877: for (Iterator iter = ruleBaseValues.getRuleTemplate()
0878: .getRuleTemplateAttributes().iterator(); iter.hasNext();) {
0879: RuleTemplateAttribute templateAttribute = (RuleTemplateAttribute) iter
0880: .next();
0881: if (!templateAttribute.isRuleValidationAttribute()) {
0882: continue;
0883: }
0884: RuleValidationAttribute attribute = templateAttribute
0885: .getRuleValidationAttribute();
0886: UserSession userSession = UserSession
0887: .getAuthenticatedUser();
0888: try {
0889: RuleValidationContext validationContext = new RuleValidationContext(
0890: ruleBaseValues, ruleDelegation, userSession);
0891: ValidationResults results = attribute
0892: .validate(validationContext);
0893: if (results != null
0894: && !results.getValidationResults().isEmpty()) {
0895: errors.add(results);
0896: }
0897: } catch (Exception e) {
0898: if (e instanceof RuntimeException) {
0899: throw (RuntimeException) e;
0900: }
0901: throw new RuntimeException("Problem validation rule.",
0902: e);
0903: }
0904:
0905: }
0906: if (!errors.isEmpty()) {
0907: throw new WorkflowServiceErrorException(
0908: "RuleBaseValues validation errors", errors);
0909: }
0910: }
0911:
0912: public List findByRouteHeaderId(Long routeHeaderId) {
0913: return getRuleDAO().findByRouteHeaderId(routeHeaderId);
0914: }
0915:
0916: public List search(String docTypeName, Long ruleId,
0917: Long ruleTemplateId, String ruleDescription,
0918: Long workgroupId, String workflowId, String roleName,
0919: Boolean delegateRule, Boolean activeInd, Map extensionValues) {
0920: return getRuleDAO().search(docTypeName, ruleId, ruleTemplateId,
0921: ruleDescription, workgroupId, workflowId, roleName,
0922: delegateRule, activeInd, extensionValues);
0923: }
0924:
0925: public List search(String docTypeName, String ruleTemplateName,
0926: String ruleDescription, GroupId workgroupId, UserId userId,
0927: String roleName, Boolean workgroupMember,
0928: Boolean delegateRule, Boolean activeInd,
0929: Map extensionValues, Collection<String> actionRequestCodes)
0930: throws EdenUserNotFoundException {
0931:
0932: if ((StringUtils.isEmpty(docTypeName))
0933: && (StringUtils.isEmpty(ruleTemplateName))
0934: && (StringUtils.isEmpty(ruleDescription))
0935: && (workgroupId.isEmpty()) && (userId.isEmpty())
0936: && (StringUtils.isEmpty(roleName))
0937: && (extensionValues.isEmpty())
0938: && (actionRequestCodes.isEmpty())) {
0939: // all fields are empty
0940: throw new IllegalArgumentException(
0941: "At least one criterion must be sent");
0942: }
0943:
0944: RuleTemplate ruleTemplate = getRuleTemplateService()
0945: .findByRuleTemplateName(ruleTemplateName);
0946: Long ruleTemplateId = null;
0947: if (ruleTemplate != null) {
0948: ruleTemplateId = ruleTemplate.getRuleTemplateId();
0949: }
0950:
0951: if (((extensionValues != null) && (!extensionValues.isEmpty()))
0952: && (ruleTemplateId == null)) {
0953: // cannot have extensions without a correct template
0954: throw new IllegalArgumentException(
0955: "A Rule Template Name must be given if using Rule Extension values");
0956: }
0957:
0958: WorkflowUser user = null;
0959: if (userId != null) {
0960: // below will throw EdenUserNotFoundException
0961: user = getUserService().getWorkflowUser(userId);
0962: }
0963:
0964: Collection<String> workgroupIds = new ArrayList();
0965: if (user != null) {
0966: if ((workgroupMember == null)
0967: || (workgroupMember.booleanValue())) {
0968: // user is found from DB and we need to parse workgroups
0969: List userWorkgroups = getWorkgroupService()
0970: .getUsersGroups(user);
0971: for (Iterator iter = userWorkgroups.iterator(); iter
0972: .hasNext();) {
0973: Workgroup workgroup = (Workgroup) iter.next();
0974: workgroupIds.add(workgroup.getWorkflowGroupId()
0975: .getGroupId().toString());
0976: }
0977: } else {
0978: // user was passed but workgroups should not be parsed... do nothing
0979: }
0980: } else {
0981: if (workgroupId != null) {
0982: Workgroup group = getWorkgroupService().getWorkgroup(
0983: workgroupId);
0984: if ((group == null) && (!workgroupId.isEmpty())) {
0985: throw new IllegalArgumentException(
0986: "Workgroup name given does not exist in Workflow");
0987: } else if (group != null) {
0988: workgroupIds.add(group.getWorkflowGroupId()
0989: .getGroupId().toString());
0990: }
0991: }
0992: }
0993:
0994: return getRuleDAO().search(
0995: docTypeName,
0996: ruleTemplateId,
0997: ruleDescription,
0998: workgroupIds,
0999: (user != null) ? user.getWorkflowUserId()
1000: .getWorkflowId() : null, roleName,
1001: delegateRule, activeInd, extensionValues,
1002: actionRequestCodes);
1003: }
1004:
1005: public void delete(Long ruleBaseValuesId) {
1006: getRuleDAO().delete(ruleBaseValuesId);
1007: }
1008:
1009: public RuleBaseValues findRuleBaseValuesById(Long ruleBaseValuesId) {
1010: return getRuleDAO().findRuleBaseValuesById(ruleBaseValuesId);
1011: }
1012:
1013: public RuleResponsibility findRuleResponsibility(
1014: Long responsibilityId) {
1015: return getRuleDAO().findRuleResponsibility(responsibilityId);
1016: }
1017:
1018: public void saveDeactivationDate(RuleBaseValues rule) {
1019: getRuleDAO().saveDeactivationDate(rule);
1020: }
1021:
1022: public List fetchAllCurrentRulesForTemplateDocCombination(
1023: String ruleTemplateName, String documentType,
1024: boolean ignoreCache) {
1025: PerformanceLogger performanceLogger = new PerformanceLogger();
1026: Boolean cachingRules = new Boolean(Utilities
1027: .getApplicationConstant(USING_RULE_CACHE_KEY));
1028: if (cachingRules.booleanValue()) {
1029: //Cache cache = SpringServiceLocator.getCache();
1030: List<RuleBaseValues> rules = getListFromCache(
1031: ruleTemplateName, documentType);
1032: if (rules != null && !ignoreCache) {
1033: performanceLogger.log("Time to fetchRules by template "
1034: + ruleTemplateName + " cached.");
1035: return rules;
1036: }
1037: Long ruleTemplateId = getRuleTemplateService()
1038: .findByRuleTemplateName(ruleTemplateName)
1039: .getRuleTemplateId();
1040: //RuleListCache translatedRules = new RuleListCache();
1041: //translatedRules.setId(getRuleCacheKey(ruleTemplateName, documentType));
1042: rules = getRuleDAO()
1043: .fetchAllCurrentRulesForTemplateDocCombination(
1044: ruleTemplateId,
1045: getDocGroupAndTypeList(documentType));
1046: //translatedRules.addAll(rules);
1047: putListInCache(ruleTemplateName, documentType, rules);
1048: //cache.add(RULE_CACHE_NAME, translatedRules);
1049: performanceLogger.log("Time to fetchRules by template "
1050: + ruleTemplateName + " cache refreshed.");
1051: return rules;
1052: } else {
1053: Long ruleTemplateId = getRuleTemplateService()
1054: .findByRuleTemplateName(ruleTemplateName)
1055: .getRuleTemplateId();
1056: performanceLogger.log("Time to fetchRules by template "
1057: + ruleTemplateName + " not caching.");
1058: return getRuleDAO()
1059: .fetchAllCurrentRulesForTemplateDocCombination(
1060: ruleTemplateId,
1061: getDocGroupAndTypeList(documentType));
1062: }
1063: }
1064:
1065: public List fetchAllCurrentRulesForTemplateDocCombination(
1066: String ruleTemplateName, String documentType) {
1067: return fetchAllCurrentRulesForTemplateDocCombination(
1068: ruleTemplateName, documentType, false);
1069: }
1070:
1071: public List fetchAllCurrentRulesForTemplateDocCombination(
1072: String ruleTemplateName, String documentType,
1073: Timestamp effectiveDate) {
1074: Long ruleTemplateId = getRuleTemplateService()
1075: .findByRuleTemplateName(ruleTemplateName)
1076: .getRuleTemplateId();
1077: PerformanceLogger performanceLogger = new PerformanceLogger();
1078: performanceLogger.log("Time to fetchRules by template "
1079: + ruleTemplateName + " not caching.");
1080: return getRuleDAO()
1081: .fetchAllCurrentRulesForTemplateDocCombination(
1082: ruleTemplateId,
1083: getDocGroupAndTypeList(documentType),
1084: effectiveDate);
1085: }
1086:
1087: public List fetchAllRules(boolean currentRules) {
1088: return getRuleDAO().fetchAllRules(currentRules);
1089: }
1090:
1091: private List getDocGroupAndTypeList(String documentType) {
1092: List docTypeList = new ArrayList();
1093: DocumentTypeService docTypeService = (DocumentTypeService) KEWServiceLocator
1094: .getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE);
1095: DocumentType docType = docTypeService.findByName(documentType);
1096: while (docType != null) {
1097: docTypeList.add(docType.getName());
1098: docType = docType.getParentDocType();
1099: }
1100: return docTypeList;
1101: }
1102:
1103: private Integer getNextVersionNumber(RuleBaseValues currentRule) {
1104: List candidates = new ArrayList();
1105: candidates.add(currentRule.getVersionNbr());
1106: List pendingRules = ruleDAO.findByPreviousVersionId(currentRule
1107: .getRuleBaseValuesId());
1108: for (Iterator iterator = pendingRules.iterator(); iterator
1109: .hasNext();) {
1110: RuleBaseValues pendingRule = (RuleBaseValues) iterator
1111: .next();
1112: candidates.add(pendingRule.getVersionNbr());
1113: }
1114: Collections.sort(candidates);
1115: Integer maxVersionNumber = (Integer) candidates.get(candidates
1116: .size() - 1);
1117: if (maxVersionNumber == null) {
1118: return new Integer(0);
1119: }
1120: return new Integer(maxVersionNumber.intValue() + 1);
1121: }
1122:
1123: /**
1124: * Determines if the given rule is locked for routing.
1125: *
1126: * In the case of a root rule edit, this method will take the rule id of the rule being edited.
1127: *
1128: * In the case of a new delegate rule or a delegate rule edit, this method will take the id of it's parent.
1129: */
1130: public Long isLockedForRouting(Long currentRuleBaseValuesId) {
1131: // checks for any other versions of the given rule, essentially, if this is a rule edit we want to see how many other
1132: // pending edits are out there
1133: List pendingRules = ruleDAO
1134: .findByPreviousVersionId(currentRuleBaseValuesId);
1135: boolean isDead = true;
1136: for (Iterator iterator = pendingRules.iterator(); iterator
1137: .hasNext();) {
1138: RuleBaseValues pendingRule = (RuleBaseValues) iterator
1139: .next();
1140:
1141: if (pendingRule.getRouteHeaderId() != null
1142: && pendingRule.getRouteHeaderId().longValue() != 0) {
1143: DocumentRouteHeaderValue routeHeader = getRouteHeaderService()
1144: .getRouteHeader(pendingRule.getRouteHeaderId());
1145: // the pending edit is considered dead if it's been disapproved or cancelled and we are allowed to proceed with our own edit
1146: isDead = routeHeader.isDisaproved()
1147: || routeHeader.isCanceled();
1148: if (!isDead) {
1149: return pendingRule.getRouteHeaderId();
1150: }
1151: }
1152: for (Iterator iter = pendingRule.getResponsibilities()
1153: .iterator(); iter.hasNext();) {
1154: RuleResponsibility responsibility = (RuleResponsibility) iter
1155: .next();
1156: for (Iterator iterator2 = responsibility
1157: .getDelegationRules().iterator(); iterator2
1158: .hasNext();) {
1159: RuleDelegation delegation = (RuleDelegation) iterator2
1160: .next();
1161: List pendingDelegateRules = ruleDAO
1162: .findByPreviousVersionId(delegation
1163: .getDelegationRuleBaseValues()
1164: .getRuleBaseValuesId());
1165: for (Iterator iterator3 = pendingDelegateRules
1166: .iterator(); iterator3.hasNext();) {
1167: RuleBaseValues pendingDelegateRule = (RuleBaseValues) iterator3
1168: .next();
1169: if (pendingDelegateRule.getRouteHeaderId() != null
1170: && pendingDelegateRule
1171: .getRouteHeaderId().longValue() != 0) {
1172: DocumentRouteHeaderValue routeHeader = getRouteHeaderService()
1173: .getRouteHeader(
1174: pendingDelegateRule
1175: .getRouteHeaderId());
1176: isDead = routeHeader.isDisaproved()
1177: || routeHeader.isCanceled();
1178: if (!isDead) {
1179: return pendingDelegateRule
1180: .getRouteHeaderId();
1181: }
1182: }
1183: }
1184: }
1185: }
1186: }
1187: return null;
1188: }
1189:
1190: public RuleBaseValues getParentRule(RuleBaseValues rule) {
1191: if (rule == null || rule.getRuleBaseValuesId() == null) {
1192: throw new IllegalArgumentException(
1193: "Rule must be non-null with non-null id: " + rule);
1194: }
1195: if (!Boolean.TRUE.equals(rule.getDelegateRule())) {
1196: return null;
1197: }
1198: return getRuleDAO().getParentRule(rule.getRuleBaseValuesId());
1199: }
1200:
1201: /**
1202: * This configuration is currently stored in a application constant named "Rule.Config.CustomDocTypes",
1203: * long term we should come up with a better solution. The format of this constant is a comma-separated
1204: * list of entries of the following form:
1205: *
1206: * <<name of doc type on rule>>:<<rule template name on rule>>:<<type of rule>>:<<name of document type to use for rule routing>>
1207: *
1208: * Rule type indicates either main or delegation rules. A main rule is indicated by the character 'M' and a
1209: * delegate rule is indicated by the character 'D'.
1210: *
1211: * So, if you wanted to route "main" rules made for the "MyDocType" document with the rule template name
1212: * "MyRuleTemplate" using the "MyMainRuleDocType" doc type, it would be specified as follows:
1213: *
1214: * MyDocType:MyRuleTemplate:M:MyMainRuleDocType
1215: *
1216: * If you also wanted to route "delegate" rules made for the "MyDocType" document with rule template name
1217: * "MyDelegateTemplate" using the "MyDelegateRuleDocType", you would then set the constant as follows:
1218: *
1219: * MyDocType:MyRuleTemplate:M:MyMainRuleDocType,MyDocType:MyDelegateTemplate:D:MyDelegateRuleDocType
1220: *
1221: * TODO this method ended up being a mess, we should get rid of this as soon as we can
1222: */
1223: public String getRuleDocmentTypeName(List rules) {
1224: if (rules.size() == 0) {
1225: throw new IllegalArgumentException(
1226: "Cannot determine rule DocumentType for an empty list of rules.");
1227: }
1228: String ruleDocTypeName = null;
1229: RuleRoutingConfig config = RuleRoutingConfig.parse();
1230: // There are 2 cases here
1231: RuleBaseValues firstRule = (RuleBaseValues) rules.get(0);
1232: if (Boolean.TRUE.equals(firstRule.getDelegateRule())) {
1233: // if it's a delegate rule then the list will contain only 2 elements, the first is the delegate rule,
1234: // the second is the parent rule. In this case just look at the custom routing process for the delegate rule.
1235: ruleDocTypeName = config.getDocumentTypeName(firstRule);
1236: } else {
1237: // if this is a list of parent rules being routed, look at all configued routing types and verify that they are
1238: // all the same, if not throw an exception
1239: String parentRulesDocTypeName = null;
1240: for (Iterator iterator = rules.iterator(); iterator
1241: .hasNext();) {
1242: RuleBaseValues rule = (RuleBaseValues) iterator.next();
1243: // if it's a delegate rule just skip it
1244: if (Boolean.TRUE.equals(rule.getDelegateRule())) {
1245: continue;
1246: }
1247: String currentDocTypeName = config
1248: .getDocumentTypeName(rule);
1249: if (parentRulesDocTypeName == null) {
1250: parentRulesDocTypeName = currentDocTypeName;
1251: } else {
1252: if (!Utilities.equals(currentDocTypeName,
1253: parentRulesDocTypeName)) {
1254: throw new RuntimeException(
1255: "There are multiple rules being routed and they have different document type definitions! "
1256: + parentRulesDocTypeName
1257: + " and " + currentDocTypeName);
1258: }
1259: }
1260: }
1261: ruleDocTypeName = parentRulesDocTypeName;
1262: }
1263: if (ruleDocTypeName == null) {
1264: ruleDocTypeName = EdenConstants.DEFAULT_RULE_DOCUMENT_NAME;
1265: }
1266: return ruleDocTypeName;
1267: }
1268:
1269: public void setRuleDAO(RuleDAO ruleDAO) {
1270: this .ruleDAO = ruleDAO;
1271: }
1272:
1273: public RuleDAO getRuleDAO() {
1274: return ruleDAO;
1275: }
1276:
1277: public void deleteRuleResponsibilityById(Long ruleResponsibilityId) {
1278: getRuleResponsibilityDAO().delete(ruleResponsibilityId);
1279: }
1280:
1281: public RuleResponsibility findByRuleResponsibilityId(
1282: Long ruleResponsibilityId) {
1283: return getRuleResponsibilityDAO().findByRuleResponsibilityId(
1284: ruleResponsibilityId);
1285: }
1286:
1287: public List findRuleBaseValuesByResponsibilityReviewer(
1288: String reviewerName, String type) {
1289: return getRuleDAO().findRuleBaseValuesByResponsibilityReviewer(
1290: reviewerName, type);
1291: }
1292:
1293: public RuleTemplateService getRuleTemplateService() {
1294: return (RuleTemplateService) KEWServiceLocator
1295: .getService(KEWServiceLocator.RULE_TEMPLATE_SERVICE);
1296: }
1297:
1298: public DocumentTypeService getDocumentTypeService() {
1299: return (DocumentTypeService) KEWServiceLocator
1300: .getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE);
1301: }
1302:
1303: public WorkgroupService getWorkgroupService() {
1304: return (WorkgroupService) KEWServiceLocator
1305: .getService(KEWServiceLocator.WORKGROUP_SRV);
1306: }
1307:
1308: public ActionRequestService getActionRequestService() {
1309: return (ActionRequestService) KEWServiceLocator
1310: .getService(KEWServiceLocator.ACTION_REQUEST_SRV);
1311: }
1312:
1313: private ResponsibilityIdService getResponsibilityIdService() {
1314: return (ResponsibilityIdService) KEWServiceLocator
1315: .getService(KEWServiceLocator.RESPONSIBILITY_ID_SERVICE);
1316: }
1317:
1318: private ApplicationConstantsService getApplicationConstantsService() {
1319: return (ApplicationConstantsService) KEWServiceLocator
1320: .getService(KEWServiceLocator.APPLICATION_CONSTANTS_SRV);
1321: }
1322:
1323: private RuleDelegationService getRuleDelegationService() {
1324: return (RuleDelegationService) KEWServiceLocator
1325: .getService(KEWServiceLocator.RULE_DELEGATION_SERVICE);
1326: }
1327:
1328: private RouteHeaderService getRouteHeaderService() {
1329: return (RouteHeaderService) KEWServiceLocator
1330: .getService(KEWServiceLocator.DOC_ROUTE_HEADER_SRV);
1331: }
1332:
1333: private UserService getUserService() {
1334: return (UserService) KEWServiceLocator
1335: .getService(KEWServiceLocator.USER_SERVICE);
1336: }
1337:
1338: public class RuleDelegationSorter implements Comparator {
1339: public int compare(Object arg0, Object arg1) {
1340: RuleBaseValues rule1 = (RuleBaseValues) arg0;
1341: RuleBaseValues rule2 = (RuleBaseValues) arg1;
1342:
1343: Integer rule1Value = new Integer((rule1.getDelegateRule()
1344: .booleanValue() ? 0 : 1));
1345: Integer rule2Value = new Integer((rule2.getDelegateRule()
1346: .booleanValue() ? 0 : 1));
1347: int value = rule1Value.compareTo(rule2Value);
1348: return value;
1349: }
1350: }
1351:
1352: public void loadXml(InputStream inputStream, WorkflowUser user) {
1353: RuleXmlParser parser = new RuleXmlParser();
1354: try {
1355: parser.parseRules(inputStream);
1356: } catch (Exception e) { //any other exception
1357: LOG.error("Error loading xml file", e);
1358: WorkflowServiceErrorException wsee = new WorkflowServiceErrorException(
1359: "Error loading xml file",
1360: new WorkflowServiceErrorImpl(
1361: "Error loading xml file", XML_PARSE_ERROR));
1362: wsee.initCause(e);
1363: throw wsee;
1364: }
1365: }
1366:
1367: public Element export(ExportDataSet dataSet) {
1368: RuleXmlExporter exporter = new RuleXmlExporter();
1369: return exporter.export(dataSet);
1370: }
1371:
1372: private static class RuleRoutingConfig {
1373: private List configs = new ArrayList();
1374:
1375: public static RuleRoutingConfig parse() {
1376: RuleRoutingConfig config = new RuleRoutingConfig();
1377: String constant = Utilities
1378: .getApplicationConstant(EdenConstants.RULE_CUSTOM_DOC_TYPES_KEY);
1379: if (!StringUtils.isEmpty(constant)) {
1380: String[] ruleConfigs = constant.split(",");
1381: for (int index = 0; index < ruleConfigs.length; index++) {
1382: String[] configElements = ruleConfigs[index]
1383: .split(":");
1384: if (configElements.length != 4) {
1385: throw new RuntimeException(
1386: "Found incorrect number of config elements within a section of the custom rule document types config. There should have been four ':' delimited sections! "
1387: + ruleConfigs[index]);
1388: }
1389: config.configs.add(configElements);
1390: }
1391: }
1392: return config;
1393: }
1394:
1395: public String getDocumentTypeName(RuleBaseValues rule) {
1396: for (Iterator iterator = configs.iterator(); iterator
1397: .hasNext();) {
1398: String[] configElements = (String[]) iterator.next();
1399: String docTypeName = configElements[0];
1400: String ruleTemplateName = configElements[1];
1401: String type = configElements[2];
1402: String ruleDocTypeName = configElements[3];
1403: if (rule.getDocTypeName().equals(docTypeName)
1404: && rule.getRuleTemplateName().equals(
1405: ruleTemplateName)) {
1406: if (type.equals("M")) {
1407: if (Boolean.FALSE
1408: .equals(rule.getDelegateRule())) {
1409: return ruleDocTypeName;
1410: }
1411: } else if (type.equals("D")) {
1412: if (Boolean.TRUE.equals(rule.getDelegateRule())) {
1413: return ruleDocTypeName;
1414: }
1415: } else {
1416: throw new RuntimeException("Bad rule type '"
1417: + type
1418: + "' in rule doc type routing config.");
1419: }
1420: }
1421: }
1422: return null;
1423: }
1424: }
1425:
1426: }
|