001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.kew.rule.web;
017
018import org.apache.commons.beanutils.BeanUtils;
019import org.apache.commons.beanutils.PropertyUtils;
020import org.apache.commons.lang.ArrayUtils;
021import org.apache.commons.lang.StringUtils;
022import org.kuali.rice.core.api.exception.RiceRuntimeException;
023import org.kuali.rice.core.api.uif.RemotableAttributeError;
024import org.kuali.rice.kew.api.KewApiConstants;
025import org.kuali.rice.kew.api.action.ActionRequestPolicy;
026import org.kuali.rice.kew.api.rule.RuleTemplateAttributeContract;
027import org.kuali.rice.kew.doctype.bo.DocumentType;
028import org.kuali.rice.kew.rule.GroupRuleResponsibility;
029import org.kuali.rice.kew.rule.PersonRuleResponsibility;
030import org.kuali.rice.kew.rule.RoleRuleResponsibility;
031import org.kuali.rice.kew.rule.RuleBaseValues;
032import org.kuali.rice.kew.rule.RuleDelegationBo;
033import org.kuali.rice.kew.rule.RuleExtensionBo;
034import org.kuali.rice.kew.rule.RuleExtensionValue;
035import org.kuali.rice.kew.rule.RuleResponsibilityBo;
036import org.kuali.rice.kew.rule.WorkflowRuleAttributeRows;
037import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo;
038import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
039import org.kuali.rice.kew.rule.service.RuleServiceInternal;
040import org.kuali.rice.kew.service.KEWServiceLocator;
041import org.kuali.rice.kim.api.group.Group;
042import org.kuali.rice.kim.api.identity.principal.Principal;
043import org.kuali.rice.kns.web.ui.Field;
044import org.kuali.rice.kns.web.ui.Row;
045import org.kuali.rice.kns.web.ui.Section;
046
047import java.lang.reflect.InvocationTargetException;
048import java.util.ArrayList;
049import java.util.Collections;
050import java.util.HashMap;
051import java.util.Iterator;
052import java.util.List;
053import java.util.Map;
054
055/**
056 * Some utilities which are utilized by the {@link RuleAction}.
057 *
058 * @author Kuali Rice Team (rice.collab@kuali.org)
059 */
060public final class WebRuleUtils {
061
062        public static final String RULE_TEMPLATE_ID_PARAM = "ruleCreationValues.ruleTemplateId";
063        public static final String RULE_TEMPLATE_NAME_PARAM = "ruleCreationValues.ruleTemplateName";
064        public static final String DOCUMENT_TYPE_NAME_PARAM = "ruleCreationValues.docTypeName";
065        public static final String RESPONSIBILITY_ID_PARAM = "ruleCreationValues.responsibilityId";
066
067        private static final String ID_SEPARATOR = "~";
068        private static final String RULE_ATTRIBUTES_SECTION_ID = "RuleAttributes";
069        private static final String RULE_ATTRIBUTES_SECTION_TITLE = "Rule Attributes";
070        private static final String ROLES_MAINTENANCE_SECTION_ID = "RolesMaintenance";
071        
072        private WebRuleUtils() {
073                throw new UnsupportedOperationException("do not call");
074        }
075        
076        /**
077         * Copies the existing rule onto the current document.  This is used within the web-based rule GUI to make a
078         * copy of a rule on the existing document.  Essentially, this method makes a copy of the rule and all
079         * delegates but preserves the document ID of the original rule.
080         */
081    public static WebRuleBaseValues copyRuleOntoExistingDocument(WebRuleBaseValues rule) throws Exception {
082        WebRuleBaseValues ruleCopy = new WebRuleBaseValues();
083        PropertyUtils.copyProperties(ruleCopy, rule);
084        ruleCopy.setPreviousRuleId(null);
085        ruleCopy.setCurrentInd(null);
086        ruleCopy.setVersionNbr(null);
087
088        List responsibilities = new ArrayList();
089        for (Iterator iter = ruleCopy.getRuleResponsibilities().iterator(); iter.hasNext();) {
090            WebRuleResponsibility responsibility = (WebRuleResponsibility) iter.next();
091            WebRuleResponsibility responsibilityCopy = new WebRuleResponsibility();
092            PropertyUtils.copyProperties(responsibilityCopy, responsibility);
093
094            responsibilityCopy.setResponsibilityId(null);
095            responsibilityCopy.setId(null);
096            
097            List delegations = new ArrayList();
098            for (Iterator iterator = responsibilityCopy.getDelegationRules().iterator(); iterator.hasNext();) {
099                RuleDelegationBo delegation = (RuleDelegationBo) iterator.next();
100                RuleDelegationBo delegationCopy = new RuleDelegationBo();
101                PropertyUtils.copyProperties(delegationCopy, delegation);
102
103                delegationCopy.setDelegateRuleId(null);
104                delegationCopy.setVersionNumber(null);
105                delegationCopy.setRuleDelegationId(null);
106                delegationCopy.setResponsibilityId(null);
107
108                WebRuleBaseValues delegationRule = ((WebRuleBaseValues) delegation.getDelegationRule());
109                WebRuleBaseValues ruleDelegateCopy = new WebRuleBaseValues();
110                PropertyUtils.copyProperties(ruleDelegateCopy, delegationRule);
111
112                ruleDelegateCopy.setPreviousRuleId(null);
113                ruleDelegateCopy.setCurrentInd(null);
114                ruleDelegateCopy.setVersionNbr(null);
115
116                List delegateResps = new ArrayList();
117                for (Iterator iterator1 = ruleDelegateCopy.getRuleResponsibilities().iterator(); iterator1.hasNext();) {
118                    WebRuleResponsibility delegateResp = (WebRuleResponsibility) iterator1.next();
119                    WebRuleResponsibility delegateRespCopy = new WebRuleResponsibility();
120                    PropertyUtils.copyProperties(delegateRespCopy, delegateResp);
121
122                    delegateRespCopy.setResponsibilityId(null);
123                    delegateRespCopy.setId(null);
124                    delegateResps.add(delegateRespCopy);
125                }
126                ruleDelegateCopy.setRuleResponsibilities(delegateResps);
127                delegationCopy.setDelegationRule(ruleDelegateCopy);
128                delegations.add(delegationCopy);
129            }
130            //responsibilityCopy.setDelegationRules(delegations);
131            responsibilities.add(responsibilityCopy);
132        }
133        ruleCopy.setRuleResponsibilities(responsibilities);
134        return ruleCopy;
135    }
136    
137    /**
138     * Makes a copy of the rule and clears the document id on the rule and any of its delegates.
139     * This method is used for making a copy of a rule for a new document.  It essentially calls
140     * the copyRuleOntoExistingDocument method and then clears out the document IDs.
141     * 
142     * @param webRuleBaseValues
143     */
144    public static WebRuleBaseValues copyToNewRule(WebRuleBaseValues webRuleBaseValues) throws Exception {
145        WebRuleBaseValues newRule = copyRuleOntoExistingDocument(webRuleBaseValues);
146        // clear out all document IDs on the rule and it's delegates
147        newRule.setDocumentId(null);
148        for (Iterator iterator = newRule.getRuleResponsibilities().iterator(); iterator.hasNext(); ) {
149                        RuleResponsibilityBo responsibility = (RuleResponsibilityBo) iterator.next();
150                        for (Iterator iterator2 = responsibility.getDelegationRules().iterator(); iterator2.hasNext(); ) {
151                                RuleDelegationBo delegation = (RuleDelegationBo) iterator2.next();
152                                delegation.getDelegationRule().setDocumentId(null);
153                        }
154                }
155        return newRule;
156    }
157
158    public static void validateRuleTemplateAndDocumentType(RuleBaseValues oldRule, RuleBaseValues newRule, Map<String, String[]> parameters) {
159                String[] ruleTemplateIds = parameters.get(RULE_TEMPLATE_ID_PARAM);
160                String[] ruleTemplateNames = parameters.get(RULE_TEMPLATE_NAME_PARAM);
161                String[] documentTypeNames = parameters.get(DOCUMENT_TYPE_NAME_PARAM);
162                if (ArrayUtils.isEmpty(ruleTemplateIds) && ArrayUtils.isEmpty(ruleTemplateNames)) {
163                        throw new RiceRuntimeException("Rule document must be initiated with a valid rule template id or rule template name.");
164                }
165                if (ArrayUtils.isEmpty(documentTypeNames)) {
166                        throw new RiceRuntimeException("Rule document must be initiated with a valid document type name.");
167                }
168                RuleTemplateBo ruleTemplate = null;
169                if (!ArrayUtils.isEmpty(ruleTemplateIds)) {
170                        String ruleTemplateId = ruleTemplateIds[0];
171                        ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateId(ruleTemplateId);
172                        if (ruleTemplate == null) {
173                                throw new RiceRuntimeException("Failed to load rule template with id '" + ruleTemplateId + "'");
174                        }
175                }
176                if (ruleTemplate == null) {
177                        String ruleTemplateName = ruleTemplateNames[0];
178                        ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateName(ruleTemplateName);
179                        if (ruleTemplate == null) {
180                                throw new RiceRuntimeException("Failed to load rule template with name '" + ruleTemplateName + "'");
181                        }
182                }
183                String documentTypeName = documentTypeNames[0];
184                DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
185                if (documentType == null) {
186                        throw new RiceRuntimeException("Failed to locate document type with name '" + documentTypeName + "'");
187                }
188                
189                // it appears that there is always an old maintainable, even in the case of a new document creation,
190                // if we don't initialize both the old and new versions we get errors during meshSections
191                initializeRuleAfterNew(oldRule, ruleTemplate, documentTypeName);
192                initializeRuleAfterNew(newRule, ruleTemplate, documentTypeName);
193        }
194    
195        private static void initializeRuleAfterNew(RuleBaseValues rule, RuleTemplateBo ruleTemplate, String documentTypeName) {
196                rule.setRuleTemplate(ruleTemplate);
197                rule.setRuleTemplateId(ruleTemplate.getId());
198                rule.setDocTypeName(documentTypeName);
199        }
200        
201        public static void validateRuleAndResponsibility(RuleDelegationBo oldRuleDelegation, RuleDelegationBo newRuleDelegation, Map<String, String[]> parameters) {
202                String[] responsibilityIds = parameters.get(RESPONSIBILITY_ID_PARAM);
203                if (ArrayUtils.isEmpty(responsibilityIds)) {
204                        throw new RiceRuntimeException("Delegation rule document must be initiated with a valid responsibility ID to delegate from.");
205                }
206                if (!ArrayUtils.isEmpty(responsibilityIds)) {
207                        String responsibilityId = responsibilityIds[0];
208                        RuleResponsibilityBo ruleResponsibility = KEWServiceLocator.getRuleService().findRuleResponsibility(responsibilityId);
209                        if (ruleResponsibility == null) {
210                                throw new RiceRuntimeException("Failed to locate a rule responsibility for responsibility ID " + responsibilityId);
211                        }
212                        oldRuleDelegation.setResponsibilityId(responsibilityId);
213                        newRuleDelegation.setResponsibilityId(responsibilityId);
214                }
215                
216        }
217
218        public static void establishDefaultRuleValues(RuleBaseValues rule) {
219                rule.setActive(true);
220
221        RuleBaseValues defaultRule = ((RuleServiceInternal) KEWServiceLocator.getService(KEWServiceLocator.RULE_SERVICE)).findDefaultRuleByRuleTemplateId(
222                        rule.getRuleTemplate().getDelegationTemplateId());
223        if (defaultRule != null) {
224            defaultRule.setActivationDate(null);
225            defaultRule.setCurrentInd(null);
226            defaultRule.setDeactivationDate(null);
227            defaultRule.setDocTypeName(null);
228            defaultRule.setVersionNumber(null);
229            defaultRule.setId(null);
230            defaultRule.setTemplateRuleInd(Boolean.FALSE);
231            defaultRule.setVersionNbr(null);
232            try {
233                                PropertyUtils.copyProperties(rule, defaultRule);
234                        } catch (IllegalAccessException e) {
235                                throw new RuntimeException(e);
236                        } catch (InvocationTargetException e) {
237                                throw new RuntimeException(e);
238                        } catch (NoSuchMethodException e) {
239                                throw new RuntimeException(e);
240                        }
241        }
242        }
243        
244
245        public static List<Section> customizeSections(RuleBaseValues rule, List<Section> sections, boolean delegateRule) {
246
247                List<Section> finalSections = new ArrayList<Section>();
248                for (Section section : sections) {
249                        // unfortunately, in the case of an inquiry the sectionId will always be null so we have to check section title
250                        if (section.getSectionTitle().equals(RULE_ATTRIBUTES_SECTION_TITLE) || 
251                                        RULE_ATTRIBUTES_SECTION_ID.equals(section.getSectionId())) {
252                                List<Row> ruleTemplateRows = getRuleTemplateRows(rule, delegateRule);
253                                if (!ruleTemplateRows.isEmpty()) {
254                                        section.setRows(ruleTemplateRows);
255                                        finalSections.add(section);
256                                }
257                        } else if (ROLES_MAINTENANCE_SECTION_ID.equals(section.getSectionId())) {
258                                if (hasRoles(rule)) {
259                                        finalSections.add(section);
260                                }
261                        } else {
262                                finalSections.add(section);
263                        }
264                }
265                
266                return finalSections;
267    }
268
269    public static List<Row> getRuleTemplateRows(RuleBaseValues rule, boolean delegateRule) {
270                List<Row> rows = new ArrayList<Row>();
271                RuleTemplateBo ruleTemplate = rule.getRuleTemplate();
272                Map<String, String> fieldNameMap = new HashMap<String, String>();
273                // refetch rule template from service because after persistence in KNS, it comes back without any rule template attributes
274                if (ruleTemplate != null) {
275                        ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateId(ruleTemplate.getId());
276                        if (ruleTemplate != null) {
277                                List<RuleTemplateAttributeBo> ruleTemplateAttributes = ruleTemplate.getActiveRuleTemplateAttributes();
278                                Collections.sort(ruleTemplateAttributes);
279                                for (RuleTemplateAttributeBo ruleTemplateAttribute : ruleTemplateAttributes) {
280                                        if (!ruleTemplateAttribute.isWorkflowAttribute()) {
281                                                continue;
282                                        }
283                    Map<String, String> parameters = getFieldMapForRuleTemplateAttribute(rule, ruleTemplateAttribute);
284                    WorkflowRuleAttributeRows workflowRuleAttributeRows =
285                            KEWServiceLocator.getWorkflowRuleAttributeMediator().getRuleRows(parameters, ruleTemplateAttribute);
286                    List<Row> attributeRows = transformAndPopulateAttributeRows(workflowRuleAttributeRows.getRows(),
287                            ruleTemplateAttribute, rule, fieldNameMap, delegateRule);
288                    rows.addAll(attributeRows);
289                                }
290                        }
291                        transformFieldConversions(rows, fieldNameMap);
292                }
293                return rows;
294        }
295        
296        public static void transformFieldConversions(List<Row> rows, Map<String, String> fieldNameMap) {
297                for (Row row : rows) {
298                        Map<String, String> transformedFieldConversions = new HashMap<String, String>();
299                        for (Field field : row.getFields()) {
300                                Map<String, String> fieldConversions = field.getFieldConversionMap();
301                                for (String lookupFieldName : fieldConversions.keySet()) {
302                                        String localFieldName = fieldConversions.get(lookupFieldName);
303                                        if (fieldNameMap.containsKey(localFieldName)) {
304                                                // set the transformed value
305                                                transformedFieldConversions.put(lookupFieldName, fieldNameMap.get(localFieldName));
306                                        } else {
307                                                // set the original value (not sure if this case will happen, but just in case)
308                                                transformedFieldConversions.put(lookupFieldName, fieldConversions.get(lookupFieldName));
309                                        }
310                                }
311                                field.setFieldConversions(transformedFieldConversions);
312                        }
313                }
314        }
315
316        private static boolean hasRoles(RuleBaseValues rule) {
317                RuleTemplateBo ruleTemplate = rule.getRuleTemplate();
318                return !ruleTemplate.getRoles().isEmpty();
319        }
320
321        /**
322         * Processes the Fields on the various attributes Rows to assign an appropriate field name to them so that the
323         * field name rendered in the maintenance HTML will properly assign the value to RuleBaseValues.fieldValues.
324         */
325
326        public static List<Row> transformAndPopulateAttributeRows(List<Row> attributeRows, RuleTemplateAttributeBo ruleTemplateAttribute, RuleBaseValues rule, Map<String, String> fieldNameMap, boolean delegateRule) {
327
328                for (Row row : attributeRows) {
329                        for (Field field : row.getFields()) {
330                                String fieldName = field.getPropertyName();
331                                if (!StringUtils.isBlank(fieldName)) {
332                                        String valueKey = ruleTemplateAttribute.getId() + ID_SEPARATOR + fieldName;
333
334                                        String propertyName;
335
336                                        if (delegateRule) {
337                        propertyName = "delegationRule.fieldValues(" + valueKey + ")";
338                    } else {
339                                                propertyName = "fieldValues(" + valueKey + ")";
340                                        }
341
342                                        fieldNameMap.put(fieldName, propertyName);
343                                        field.setPropertyName(propertyName);
344                                        field.setPropertyValue(rule.getFieldValues().get(valueKey));
345                                }
346                        }
347                }
348                return attributeRows;
349        }
350
351        /**
352         * Since editing of a Rule should actually result in a rule with a new ID and new
353         * entries in the rule and rule responsibility tables, we need to clear out
354         * the primary keys of the rule and related objects.
355         */
356        public static void clearKeysForSave(RuleBaseValues rule) {
357                rule.setId(null);
358                rule.setActivationDate(null);
359                rule.setDeactivationDate(null);
360                rule.setCurrentInd(false);
361                rule.setVersionNbr(null);
362                rule.setObjectId(null);
363                rule.setVersionNumber(0L);
364        }
365        
366        public static void clearKeysForSave(RuleDelegationBo ruleDelegation) {
367                ruleDelegation.setRuleDelegationId(null);
368                ruleDelegation.setObjectId(null);
369                ruleDelegation.setVersionNumber(0L);
370                clearKeysForSave(ruleDelegation.getDelegationRule());
371        }
372        
373    public static void translateResponsibilitiesForSave(RuleBaseValues rule) {
374                rule.getRuleResponsibilities().clear();
375                for (PersonRuleResponsibility responsibility : rule.getPersonResponsibilities()) {
376                        RuleResponsibilityBo ruleResponsibility = new RuleResponsibilityBo();
377                        ruleResponsibility.setActionRequestedCd(responsibility.getActionRequestedCd());
378                        ruleResponsibility.setPriority(responsibility.getPriority());
379                        ruleResponsibility.setResponsibilityId(responsibility.getResponsibilityId());
380                        if (ruleResponsibility.getResponsibilityId() == null) {
381                                ruleResponsibility.setResponsibilityId(KEWServiceLocator.getResponsibilityIdService().getNewResponsibilityId());
382                        }
383                        String principalId = KEWServiceLocator.getIdentityHelperService().getIdForPrincipalName(responsibility.getPrincipalName());
384                        ruleResponsibility.setRuleResponsibilityName(principalId);
385                        ruleResponsibility.setRuleResponsibilityType(KewApiConstants.RULE_RESPONSIBILITY_WORKFLOW_ID);
386                        // default the approve policy to First Approve
387                        ruleResponsibility.setApprovePolicy(ActionRequestPolicy.FIRST.getCode());
388                        rule.getRuleResponsibilities().add(ruleResponsibility);
389                }
390                for (GroupRuleResponsibility responsibility : rule.getGroupResponsibilities()) {
391                        RuleResponsibilityBo ruleResponsibility = new RuleResponsibilityBo();
392                        ruleResponsibility.setActionRequestedCd(responsibility.getActionRequestedCd());
393                        ruleResponsibility.setPriority(responsibility.getPriority());
394                        ruleResponsibility.setResponsibilityId(responsibility.getResponsibilityId());
395                        if (ruleResponsibility.getResponsibilityId() == null) {
396                                ruleResponsibility.setResponsibilityId(KEWServiceLocator.getResponsibilityIdService().getNewResponsibilityId());
397                        }
398                        Group group = KEWServiceLocator.getIdentityHelperService().getGroupByName(responsibility.getNamespaceCode(), responsibility.getName());
399                        ruleResponsibility.setRuleResponsibilityName(group.getId());
400                        ruleResponsibility.setRuleResponsibilityType(KewApiConstants.RULE_RESPONSIBILITY_GROUP_ID);
401                        ruleResponsibility.setApprovePolicy(ActionRequestPolicy.FIRST.getCode());
402                        rule.getRuleResponsibilities().add(ruleResponsibility);
403                }
404                for (RoleRuleResponsibility responsibility : rule.getRoleResponsibilities()) {
405                        RuleResponsibilityBo ruleResponsibility = new RuleResponsibilityBo();
406                        ruleResponsibility.setActionRequestedCd(responsibility.getActionRequestedCd());
407                        ruleResponsibility.setPriority(responsibility.getPriority());
408                        ruleResponsibility.setResponsibilityId(responsibility.getResponsibilityId());
409                        if (ruleResponsibility.getResponsibilityId() == null) {
410                                ruleResponsibility.setResponsibilityId(KEWServiceLocator.getResponsibilityIdService().getNewResponsibilityId());
411                        }
412                        ruleResponsibility.setRuleResponsibilityName(responsibility.getRoleName());
413                        ruleResponsibility.setRuleResponsibilityType(KewApiConstants.RULE_RESPONSIBILITY_ROLE_ID);
414                        ruleResponsibility.setApprovePolicy(responsibility.getApprovePolicy());
415                        rule.getRuleResponsibilities().add(ruleResponsibility);
416                }
417        }
418    
419    public static void translateFieldValuesForSave(RuleBaseValues rule) {
420        RuleTemplateBo ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateId(rule.getRuleTemplateId());
421
422                /** Populate rule extension values * */
423                List extensions = new ArrayList();
424                for (Iterator iterator = ruleTemplate.getActiveRuleTemplateAttributes().iterator(); iterator.hasNext();) {
425                        RuleTemplateAttributeBo ruleTemplateAttribute = (RuleTemplateAttributeBo) iterator.next();
426                        if (!ruleTemplateAttribute.isWorkflowAttribute()) {
427                                continue;
428                        }
429                        Map<String, String> parameterMap = getFieldMapForRuleTemplateAttribute(rule, ruleTemplateAttribute);
430            WorkflowRuleAttributeRows workflowRuleAttributeRows =
431                    KEWServiceLocator.getWorkflowRuleAttributeMediator().getRuleRows(parameterMap, ruleTemplateAttribute);
432
433                                                
434                        // validate rule data populates the rule extension values for us
435                        List<RemotableAttributeError> attValidationErrors = workflowRuleAttributeRows.getValidationErrors();
436
437                        // because validation should be handled by business rules now, if we encounter a validation error at this point in
438                        // time, let's throw an exception
439                        if (attValidationErrors != null && !attValidationErrors.isEmpty()) {
440                                throw new RiceRuntimeException("Encountered attribute validation errors when attempting to save the Rule!");
441                        }
442                        
443                        Map<String, String> ruleExtensionValuesMap = workflowRuleAttributeRows.getRuleExtensionValues();
444                        if (ruleExtensionValuesMap != null && !ruleExtensionValuesMap.isEmpty()) {
445                                RuleExtensionBo ruleExtension = new RuleExtensionBo();
446                                ruleExtension.setRuleTemplateAttributeId(ruleTemplateAttribute.getId());
447                List<RuleExtensionValue> ruleExtensionValues = new ArrayList<RuleExtensionValue>();
448                for (String key : ruleExtensionValuesMap.keySet()) {
449                    RuleExtensionValue ruleExtensionValue = new RuleExtensionValue();
450                    ruleExtensionValue.setExtension(ruleExtension);
451                    ruleExtensionValue.setKey(key);
452                    ruleExtensionValue.setValue(ruleExtensionValuesMap.get(key));
453                                    ruleExtensionValues.add(ruleExtensionValue);
454                }
455                ruleExtension.setExtensionValues(ruleExtensionValues);
456                                extensions.add(ruleExtension);
457                        }
458                                
459                }
460                rule.setRuleExtensions(extensions);
461
462                for (Iterator iterator = rule.getRuleExtensions().iterator(); iterator.hasNext();) {
463                        RuleExtensionBo ruleExtension = (RuleExtensionBo) iterator.next();
464                        ruleExtension.setRuleBaseValues(rule);
465
466                        for (Iterator iterator2 = ruleTemplate.getActiveRuleTemplateAttributes().iterator(); iterator2.hasNext();) {
467                                RuleTemplateAttributeBo ruleTemplateAttribute = (RuleTemplateAttributeBo) iterator2.next();
468                                if (StringUtils.equals(ruleTemplateAttribute.getId(), ruleExtension.getRuleTemplateAttributeId())) {
469                                        ruleExtension.setRuleTemplateAttribute(ruleTemplateAttribute);
470                                        break;
471                                }
472                        }
473
474                        for (Iterator iterator2 = ruleExtension.getExtensionValues().iterator(); iterator2.hasNext();) {
475                                RuleExtensionValue ruleExtensionValue = (RuleExtensionValue) iterator2.next();
476                                ruleExtensionValue.setExtension(ruleExtension);
477                        }
478                }
479    }
480
481    /**
482     * Based on original logic implemented in Rule system.  Essentially constructs a Map of field values related
483     * to the given RuleTemplateAttribute.
484     */
485    public static Map<String, String> getFieldMapForRuleTemplateAttribute(RuleBaseValues rule, RuleTemplateAttributeContract ruleTemplateAttribute) {
486        Map<String, String> fieldMap = new HashMap<String, String>();
487        for (String fieldKey : rule.getFieldValues().keySet()) {
488                String ruleTemplateAttributeId = fieldKey.substring(0, fieldKey.indexOf(ID_SEPARATOR));
489                String fieldName = fieldKey.substring(fieldKey.indexOf(ID_SEPARATOR) + 1);
490                if (ruleTemplateAttribute.getId().equals(ruleTemplateAttributeId)) {
491                        fieldMap.put(fieldName, rule.getFieldValues().get(fieldKey));
492                }
493        }
494        return fieldMap;
495    }
496    
497    public static void processRuleForDelegationSave(RuleDelegationBo ruleDelegation) {
498        RuleBaseValues rule = ruleDelegation.getDelegationRule();
499        rule.setDelegateRule(true);
500        // certain items on a delegated rule responsibility are inherited from parent responsibility, set them to null
501        for (RuleResponsibilityBo responsibility : rule.getRuleResponsibilities()) {
502                responsibility.setActionRequestedCd(null);
503                responsibility.setPriority(null);
504        }
505    }
506    
507    public static void populateForCopyOrEdit(RuleBaseValues oldRule, RuleBaseValues newRule) {
508                populateRuleMaintenanceFields(oldRule);
509                populateRuleMaintenanceFields(newRule);
510                // in the case of copy, our fields which are marked read only are cleared, this includes the rule template
511                // name and the document type name but we don't want these cleared
512                if (newRule.getRuleTemplate().getName() == null) {
513                        newRule.getRuleTemplate().setName(oldRule.getRuleTemplate().getName());
514                }
515                if (newRule.getDocTypeName() == null) {
516                        newRule.setDocTypeName(oldRule.getDocTypeName());
517                }
518        }
519    
520    /**
521         * This method populates fields on RuleBaseValues which are used only for
522         * maintenance purposes.  In otherwords, it populates the non-persistent fields
523         * on the RuleBaseValues which the maintenance document needs to function
524         * (such as the extension field values and responsibilities).
525         */
526        public static void populateRuleMaintenanceFields(RuleBaseValues rule) {
527                translateResponsibilitiesForLoad(rule);
528                translateRuleExtensionsForLoad(rule);
529        }
530        
531        public static void translateResponsibilitiesForLoad(RuleBaseValues rule) {
532                for (RuleResponsibilityBo responsibility : rule.getRuleResponsibilities()) {
533                        if (responsibility.getRuleResponsibilityType().equals(KewApiConstants.RULE_RESPONSIBILITY_WORKFLOW_ID)) {
534                                PersonRuleResponsibility personResponsibility = new PersonRuleResponsibility();
535                                copyResponsibility(responsibility, personResponsibility);
536                                Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipal(personResponsibility.getRuleResponsibilityName());
537                                personResponsibility.setPrincipalName(principal.getPrincipalName());
538                                rule.getPersonResponsibilities().add(personResponsibility);
539                        } else if (responsibility.getRuleResponsibilityType().equals(KewApiConstants.RULE_RESPONSIBILITY_GROUP_ID)) {
540                                GroupRuleResponsibility groupResponsibility = new GroupRuleResponsibility();
541                                copyResponsibility(responsibility, groupResponsibility);
542                                Group group = KEWServiceLocator.getIdentityHelperService().getGroup(groupResponsibility.getRuleResponsibilityName());
543                                groupResponsibility.setNamespaceCode(group.getNamespaceCode());
544                                groupResponsibility.setName(group.getName());
545                                rule.getGroupResponsibilities().add(groupResponsibility);
546                        } else if (responsibility.getRuleResponsibilityType().equals(KewApiConstants.RULE_RESPONSIBILITY_ROLE_ID)) {
547                                RoleRuleResponsibility roleResponsibility = new RoleRuleResponsibility();
548                                copyResponsibility(responsibility, roleResponsibility);
549                                rule.getRoleResponsibilities().add(roleResponsibility);
550                        } else {
551                                throw new RiceRuntimeException("Original responsibility with id '" + responsibility.getId() + "' contained a bad type code of '" + responsibility.getRuleResponsibilityType());
552                        }
553                }
554                // since we've loaded the responsibilities, let's clear the originals so they don't get serialized to the maint doc XML
555                rule.getRuleResponsibilities().clear();
556        }
557        
558        public static void copyResponsibility(RuleResponsibilityBo source, RuleResponsibilityBo target) {
559                try {
560                        BeanUtils.copyProperties(target, source);
561                } catch (Exception e) {
562                        throw new RiceRuntimeException("Failed to copy properties from source to target responsibility", e);
563                }
564        }
565        
566        public static void translateRuleExtensionsForLoad(RuleBaseValues rule) {
567                for (RuleExtensionBo ruleExtension : rule.getRuleExtensions()) {
568                        String ruleTemplateAttributeId = ruleExtension.getRuleTemplateAttributeId();
569                        for (RuleExtensionValue ruleExtensionValue : ruleExtension.getExtensionValues()) {
570                                String fieldMapKey = ruleTemplateAttributeId + ID_SEPARATOR + ruleExtensionValue.getKey();
571                                rule.getFieldValues().put(fieldMapKey, ruleExtensionValue.getValue());
572                        }
573                }
574                // since we've loaded the extensions, let's clear the originals so that they don't get serialized to the maint doc XML
575                rule.getRuleExtensions().clear();
576        }
577        
578        public static void processRuleForCopy(String documentNumber, RuleBaseValues oldRule, RuleBaseValues newRule) {
579                WebRuleUtils.populateForCopyOrEdit(oldRule, newRule);
580                clearKeysForCopy(newRule);
581                newRule.setDocumentId(documentNumber);
582        }
583        
584        public static void clearKeysForCopy(RuleBaseValues rule) {      
585        rule.setId(null);
586        rule.setPreviousRuleId(null);
587        rule.setPreviousVersion(null);
588        rule.setName(null);
589        for (PersonRuleResponsibility responsibility : rule.getPersonResponsibilities()) {
590                clearResponsibilityKeys(responsibility);
591        }
592        for (GroupRuleResponsibility responsibility : rule.getGroupResponsibilities()) {
593                clearResponsibilityKeys(responsibility);
594        }
595        for (RoleRuleResponsibility responsibility : rule.getRoleResponsibilities()) {
596                clearResponsibilityKeys(responsibility);
597        }
598    }
599
600    private static void clearResponsibilityKeys(RuleResponsibilityBo responsibility) {
601                responsibility.setResponsibilityId(null);
602                responsibility.setId(null);
603                responsibility.setRuleBaseValuesId(null);
604    }
605    
606}