001    /**
002     * Copyright 2005-2014 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     */
016    package org.kuali.rice.kew.rule.web;
017    
018    import java.lang.reflect.InvocationTargetException;
019    import java.util.ArrayList;
020    import java.util.Collections;
021    import java.util.HashMap;
022    import java.util.Iterator;
023    import java.util.List;
024    import java.util.Map;
025    
026    import org.apache.commons.beanutils.BeanUtils;
027    import org.apache.commons.beanutils.PropertyUtils;
028    import org.apache.commons.lang.ArrayUtils;
029    import org.apache.commons.lang.StringUtils;
030    import org.kuali.rice.core.api.exception.RiceRuntimeException;
031    import org.kuali.rice.core.api.uif.RemotableAttributeError;
032    import org.kuali.rice.kew.api.KewApiConstants;
033    import org.kuali.rice.kew.api.action.ActionRequestPolicy;
034    import org.kuali.rice.kew.api.rule.RuleTemplateAttributeContract;
035    import org.kuali.rice.kew.doctype.bo.DocumentType;
036    import org.kuali.rice.kew.rule.GroupRuleResponsibility;
037    import org.kuali.rice.kew.rule.PersonRuleResponsibility;
038    import org.kuali.rice.kew.rule.RoleRuleResponsibility;
039    import org.kuali.rice.kew.rule.RuleBaseValues;
040    import org.kuali.rice.kew.rule.RuleDelegationBo;
041    import org.kuali.rice.kew.rule.RuleExtensionBo;
042    import org.kuali.rice.kew.rule.RuleExtensionValue;
043    import org.kuali.rice.kew.rule.RuleResponsibilityBo;
044    import org.kuali.rice.kew.rule.WorkflowRuleAttributeRows;
045    import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo;
046    import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
047    import org.kuali.rice.kew.rule.service.RuleServiceInternal;
048    import org.kuali.rice.kew.service.KEWServiceLocator;
049    import org.kuali.rice.kim.api.group.Group;
050    import org.kuali.rice.kim.api.identity.principal.Principal;
051    import org.kuali.rice.kns.web.ui.Field;
052    import org.kuali.rice.kns.web.ui.Row;
053    import org.kuali.rice.kns.web.ui.Section;
054    
055    /**
056     * Some utilities which are utilized by the {@link RuleAction}.
057     *
058     * @author Kuali Rice Team (rice.collab@kuali.org)
059     */
060    public 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            if (rule.getRuleTemplate().getDelegationTemplateId() != null) {
222                RuleBaseValues defaultRule =
223                        ((RuleServiceInternal) KEWServiceLocator.getService(KEWServiceLocator.RULE_SERVICE)).
224                        findDefaultRuleByRuleTemplateId(rule.getRuleTemplate().getDelegationTemplateId());
225    
226                if (defaultRule != null) {
227                    defaultRule.setActivationDate(null);
228                    defaultRule.setCurrentInd(null);
229                    defaultRule.setDeactivationDate(null);
230                    defaultRule.setDocTypeName(null);
231                    defaultRule.setVersionNumber(null);
232                    defaultRule.setId(null);
233                    defaultRule.setTemplateRuleInd(Boolean.FALSE);
234                    defaultRule.setVersionNbr(null);
235                    try {
236                        PropertyUtils.copyProperties(rule, defaultRule);
237                    } catch (IllegalAccessException e) {
238                        throw new RuntimeException(e);
239                    } catch (InvocationTargetException e) {
240                        throw new RuntimeException(e);
241                    } catch (NoSuchMethodException e) {
242                        throw new RuntimeException(e);
243                    }
244                }
245            }
246        }
247    
248            public static List<Section> customizeSections(RuleBaseValues rule, List<Section> sections, boolean delegateRule) {
249    
250                    List<Section> finalSections = new ArrayList<Section>();
251                    for (Section section : sections) {
252                            // unfortunately, in the case of an inquiry the sectionId will always be null so we have to check section title
253                            if (section.getSectionTitle().equals(RULE_ATTRIBUTES_SECTION_TITLE) ||
254                                            RULE_ATTRIBUTES_SECTION_ID.equals(section.getSectionId())) {
255                                    List<Row> ruleTemplateRows = getRuleTemplateRows(rule, delegateRule);
256                                    if (!ruleTemplateRows.isEmpty()) {
257                                            section.setRows(ruleTemplateRows);
258                                            finalSections.add(section);
259                                    }
260                            } else if (ROLES_MAINTENANCE_SECTION_ID.equals(section.getSectionId())) {
261                                    if (hasRoles(rule)) {
262                                            finalSections.add(section);
263                                    }
264                            } else {
265                                    finalSections.add(section);
266                            }
267                    }
268    
269                    return finalSections;
270        }
271    
272        public static List<Row> getRuleTemplateRows(RuleBaseValues rule, boolean delegateRule) {
273                    List<Row> rows = new ArrayList<Row>();
274                    RuleTemplateBo ruleTemplate = rule.getRuleTemplate();
275                    Map<String, String> fieldNameMap = new HashMap<String, String>();
276                    // refetch rule template from service because after persistence in KNS, it comes back without any rule template attributes
277                    if (ruleTemplate != null) {
278                            ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateId(ruleTemplate.getId());
279                            if (ruleTemplate != null) {
280                                    List<RuleTemplateAttributeBo> ruleTemplateAttributes = ruleTemplate.getActiveRuleTemplateAttributes();
281                                    Collections.sort(ruleTemplateAttributes);
282                                    for (RuleTemplateAttributeBo ruleTemplateAttribute : ruleTemplateAttributes) {
283                                            if (!ruleTemplateAttribute.isWorkflowAttribute()) {
284                                                    continue;
285                                            }
286                        Map<String, String> parameters = getFieldMapForRuleTemplateAttribute(rule, ruleTemplateAttribute);
287                        WorkflowRuleAttributeRows workflowRuleAttributeRows =
288                                KEWServiceLocator.getWorkflowRuleAttributeMediator().getRuleRows(parameters, ruleTemplateAttribute);
289                        List<Row> attributeRows = transformAndPopulateAttributeRows(workflowRuleAttributeRows.getRows(),
290                                ruleTemplateAttribute, rule, fieldNameMap, delegateRule);
291                        rows.addAll(attributeRows);
292                                    }
293                            }
294                            transformFieldConversions(rows, fieldNameMap);
295                    }
296                    return rows;
297            }
298    
299            public static void transformFieldConversions(List<Row> rows, Map<String, String> fieldNameMap) {
300                    for (Row row : rows) {
301                            Map<String, String> transformedFieldConversions = new HashMap<String, String>();
302                            for (Field field : row.getFields()) {
303                                    Map<String, String> fieldConversions = field.getFieldConversionMap();
304                                    for (String lookupFieldName : fieldConversions.keySet()) {
305                                            String localFieldName = fieldConversions.get(lookupFieldName);
306                                            if (fieldNameMap.containsKey(localFieldName)) {
307                                                    // set the transformed value
308                                                    transformedFieldConversions.put(lookupFieldName, fieldNameMap.get(localFieldName));
309                                            } else {
310                                                    // set the original value (not sure if this case will happen, but just in case)
311                                                    transformedFieldConversions.put(lookupFieldName, fieldConversions.get(lookupFieldName));
312                                            }
313                                    }
314                                    field.setFieldConversions(transformedFieldConversions);
315                            }
316                    }
317            }
318    
319            private static boolean hasRoles(RuleBaseValues rule) {
320                    RuleTemplateBo ruleTemplate = rule.getRuleTemplate();
321                    return !ruleTemplate.getRoles().isEmpty();
322            }
323    
324            /**
325             * Processes the Fields on the various attributes Rows to assign an appropriate field name to them so that the
326             * field name rendered in the maintenance HTML will properly assign the value to RuleBaseValues.fieldValues.
327             */
328    
329            public static List<Row> transformAndPopulateAttributeRows(List<Row> attributeRows, RuleTemplateAttributeBo ruleTemplateAttribute, RuleBaseValues rule, Map<String, String> fieldNameMap, boolean delegateRule) {
330    
331                    for (Row row : attributeRows) {
332                            for (Field field : row.getFields()) {
333                                    String fieldName = field.getPropertyName();
334                                    if (!StringUtils.isBlank(fieldName)) {
335                                            String valueKey = ruleTemplateAttribute.getId() + ID_SEPARATOR + fieldName;
336    
337                                            String propertyName;
338    
339                                            if (delegateRule) {
340                            propertyName = "delegationRule.fieldValues(" + valueKey + ")";
341                        } else {
342                                                    propertyName = "fieldValues(" + valueKey + ")";
343                                            }
344    
345                                            fieldNameMap.put(fieldName, propertyName);
346                                            field.setPropertyName(propertyName);
347                                            field.setPropertyValue(rule.getFieldValues().get(valueKey));
348                                    }
349                            }
350                    }
351                    return attributeRows;
352            }
353    
354            /**
355             * Since editing of a Rule should actually result in a rule with a new ID and new
356             * entries in the rule and rule responsibility tables, we need to clear out
357             * the primary keys of the rule and related objects.
358             */
359            public static void clearKeysForSave(RuleBaseValues rule) {
360                    rule.setId(null);
361                    rule.setActivationDate(null);
362                    rule.setDeactivationDate(null);
363                    rule.setCurrentInd(false);
364                    rule.setVersionNbr(null);
365                    rule.setObjectId(null);
366                    rule.setVersionNumber(null);
367            }
368    
369            public static void clearKeysForSave(RuleDelegationBo ruleDelegation) {
370                    ruleDelegation.setRuleDelegationId(null);
371                    ruleDelegation.setObjectId(null);
372                    ruleDelegation.setVersionNumber(null);
373                    clearKeysForSave(ruleDelegation.getDelegationRule());
374            }
375    
376        public static void translateResponsibilitiesForSave(RuleBaseValues rule) {
377                    rule.getRuleResponsibilities().clear();
378                    for (PersonRuleResponsibility responsibility : rule.getPersonResponsibilities()) {
379                            RuleResponsibilityBo ruleResponsibility = new RuleResponsibilityBo();
380                            ruleResponsibility.setActionRequestedCd(responsibility.getActionRequestedCd());
381                            ruleResponsibility.setPriority(responsibility.getPriority());
382                            ruleResponsibility.setResponsibilityId(responsibility.getResponsibilityId());
383                            if (ruleResponsibility.getResponsibilityId() == null) {
384                                    ruleResponsibility.setResponsibilityId(KEWServiceLocator.getResponsibilityIdService().getNewResponsibilityId());
385                            }
386                            String principalId = KEWServiceLocator.getIdentityHelperService().getIdForPrincipalName(responsibility.getPrincipalName());
387                            ruleResponsibility.setRuleResponsibilityName(principalId);
388                            ruleResponsibility.setRuleResponsibilityType(KewApiConstants.RULE_RESPONSIBILITY_WORKFLOW_ID);
389                            // default the approve policy to First Approve
390                            ruleResponsibility.setApprovePolicy(ActionRequestPolicy.FIRST.getCode());
391                            rule.getRuleResponsibilities().add(ruleResponsibility);
392                    }
393                    for (GroupRuleResponsibility responsibility : rule.getGroupResponsibilities()) {
394                            RuleResponsibilityBo ruleResponsibility = new RuleResponsibilityBo();
395                            ruleResponsibility.setActionRequestedCd(responsibility.getActionRequestedCd());
396                            ruleResponsibility.setPriority(responsibility.getPriority());
397                            ruleResponsibility.setResponsibilityId(responsibility.getResponsibilityId());
398                            if (ruleResponsibility.getResponsibilityId() == null) {
399                                    ruleResponsibility.setResponsibilityId(KEWServiceLocator.getResponsibilityIdService().getNewResponsibilityId());
400                            }
401                            Group group = KEWServiceLocator.getIdentityHelperService().getGroupByName(responsibility.getNamespaceCode(), responsibility.getName());
402                            ruleResponsibility.setRuleResponsibilityName(group.getId());
403                            ruleResponsibility.setRuleResponsibilityType(KewApiConstants.RULE_RESPONSIBILITY_GROUP_ID);
404                            ruleResponsibility.setApprovePolicy(ActionRequestPolicy.FIRST.getCode());
405                            rule.getRuleResponsibilities().add(ruleResponsibility);
406                    }
407                    for (RoleRuleResponsibility responsibility : rule.getRoleResponsibilities()) {
408                            RuleResponsibilityBo ruleResponsibility = new RuleResponsibilityBo();
409                            ruleResponsibility.setActionRequestedCd(responsibility.getActionRequestedCd());
410                            ruleResponsibility.setPriority(responsibility.getPriority());
411                            ruleResponsibility.setResponsibilityId(responsibility.getResponsibilityId());
412                            if (ruleResponsibility.getResponsibilityId() == null) {
413                                    ruleResponsibility.setResponsibilityId(KEWServiceLocator.getResponsibilityIdService().getNewResponsibilityId());
414                            }
415                            ruleResponsibility.setRuleResponsibilityName(responsibility.getRoleName());
416                            ruleResponsibility.setRuleResponsibilityType(KewApiConstants.RULE_RESPONSIBILITY_ROLE_ID);
417                            ruleResponsibility.setApprovePolicy(responsibility.getApprovePolicy());
418                            rule.getRuleResponsibilities().add(ruleResponsibility);
419                    }
420            }
421    
422        public static void translateFieldValuesForSave(RuleBaseValues rule) {
423            RuleTemplateBo ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateId(rule.getRuleTemplateId());
424    
425                    /** Populate rule extension values * */
426                    List extensions = new ArrayList();
427                    for (Iterator iterator = ruleTemplate.getActiveRuleTemplateAttributes().iterator(); iterator.hasNext();) {
428                            RuleTemplateAttributeBo ruleTemplateAttribute = (RuleTemplateAttributeBo) iterator.next();
429                            if (!ruleTemplateAttribute.isWorkflowAttribute()) {
430                                    continue;
431                            }
432                            Map<String, String> parameterMap = getFieldMapForRuleTemplateAttribute(rule, ruleTemplateAttribute);
433                WorkflowRuleAttributeRows workflowRuleAttributeRows =
434                        KEWServiceLocator.getWorkflowRuleAttributeMediator().getRuleRows(parameterMap, ruleTemplateAttribute);
435    
436    
437                            // validate rule data populates the rule extension values for us
438                            List<RemotableAttributeError> attValidationErrors = workflowRuleAttributeRows.getValidationErrors();
439    
440                            // because validation should be handled by business rules now, if we encounter a validation error at this point in
441                            // time, let's throw an exception
442                            if (attValidationErrors != null && !attValidationErrors.isEmpty()) {
443                                    throw new RiceRuntimeException("Encountered attribute validation errors when attempting to save the Rule!");
444                            }
445    
446                            Map<String, String> ruleExtensionValuesMap = workflowRuleAttributeRows.getRuleExtensionValues();
447                            if (ruleExtensionValuesMap != null && !ruleExtensionValuesMap.isEmpty()) {
448                                    RuleExtensionBo ruleExtension = new RuleExtensionBo();
449                                    ruleExtension.setRuleTemplateAttributeId(ruleTemplateAttribute.getId());
450                    List<RuleExtensionValue> ruleExtensionValues = new ArrayList<RuleExtensionValue>();
451                    for (String key : ruleExtensionValuesMap.keySet()) {
452                        RuleExtensionValue ruleExtensionValue = new RuleExtensionValue();
453                        ruleExtensionValue.setExtension(ruleExtension);
454                        ruleExtensionValue.setKey(key);
455                        ruleExtensionValue.setValue(ruleExtensionValuesMap.get(key));
456                                        ruleExtensionValues.add(ruleExtensionValue);
457                    }
458                    ruleExtension.setExtensionValues(ruleExtensionValues);
459                                    extensions.add(ruleExtension);
460                            }
461    
462                    }
463                    rule.setRuleExtensions(extensions);
464    
465                    for (Iterator iterator = rule.getRuleExtensions().iterator(); iterator.hasNext();) {
466                            RuleExtensionBo ruleExtension = (RuleExtensionBo) iterator.next();
467                            ruleExtension.setRuleBaseValues(rule);
468    
469                            for (Iterator iterator2 = ruleTemplate.getActiveRuleTemplateAttributes().iterator(); iterator2.hasNext();) {
470                                    RuleTemplateAttributeBo ruleTemplateAttribute = (RuleTemplateAttributeBo) iterator2.next();
471                                    if (StringUtils.equals(ruleTemplateAttribute.getId(), ruleExtension.getRuleTemplateAttributeId())) {
472                                            ruleExtension.setRuleTemplateAttribute(ruleTemplateAttribute);
473                                            break;
474                                    }
475                            }
476    
477                            for (Iterator iterator2 = ruleExtension.getExtensionValues().iterator(); iterator2.hasNext();) {
478                                    RuleExtensionValue ruleExtensionValue = (RuleExtensionValue) iterator2.next();
479                                    ruleExtensionValue.setExtension(ruleExtension);
480                            }
481                    }
482        }
483    
484        /**
485         * Based on original logic implemented in Rule system.  Essentially constructs a Map of field values related
486         * to the given RuleTemplateAttribute.
487         */
488        public static Map<String, String> getFieldMapForRuleTemplateAttribute(RuleBaseValues rule, RuleTemplateAttributeContract ruleTemplateAttribute) {
489            Map<String, String> fieldMap = new HashMap<String, String>();
490            for (String fieldKey : rule.getFieldValues().keySet()) {
491                    String ruleTemplateAttributeId = fieldKey.substring(0, fieldKey.indexOf(ID_SEPARATOR));
492                    String fieldName = fieldKey.substring(fieldKey.indexOf(ID_SEPARATOR) + 1);
493                    if (ruleTemplateAttribute.getId().equals(ruleTemplateAttributeId)) {
494                            fieldMap.put(fieldName, rule.getFieldValues().get(fieldKey));
495                    }
496            }
497            return fieldMap;
498        }
499    
500        public static void processRuleForDelegationSave(RuleDelegationBo ruleDelegation) {
501            RuleBaseValues rule = ruleDelegation.getDelegationRule();
502            rule.setDelegateRule(true);
503            // certain items on a delegated rule responsibility are inherited from parent responsibility, set them to null
504            for (RuleResponsibilityBo responsibility : rule.getRuleResponsibilities()) {
505                    responsibility.setActionRequestedCd(null);
506                    responsibility.setPriority(null);
507            }
508        }
509    
510        public static void populateForCopyOrEdit(RuleBaseValues oldRule, RuleBaseValues newRule) {
511                    populateRuleMaintenanceFields(oldRule);
512                    populateRuleMaintenanceFields(newRule);
513                    // in the case of copy, our fields which are marked read only are cleared, this includes the rule template
514                    // name and the document type name but we don't want these cleared
515                    if (newRule.getRuleTemplate().getName() == null) {
516                            newRule.getRuleTemplate().setName(oldRule.getRuleTemplate().getName());
517                    }
518                    if (newRule.getDocTypeName() == null) {
519                            newRule.setDocTypeName(oldRule.getDocTypeName());
520                    }
521            }
522    
523        /**
524             * This method populates fields on RuleBaseValues which are used only for
525             * maintenance purposes.  In otherwords, it populates the non-persistent fields
526             * on the RuleBaseValues which the maintenance document needs to function
527             * (such as the extension field values and responsibilities).
528             */
529            public static void populateRuleMaintenanceFields(RuleBaseValues rule) {
530                    translateResponsibilitiesForLoad(rule);
531                    translateRuleExtensionsForLoad(rule);
532            }
533    
534            public static void translateResponsibilitiesForLoad(RuleBaseValues rule) {
535                    for (RuleResponsibilityBo responsibility : rule.getRuleResponsibilities()) {
536                            if (responsibility.getRuleResponsibilityType().equals(KewApiConstants.RULE_RESPONSIBILITY_WORKFLOW_ID)) {
537                                    PersonRuleResponsibility personResponsibility = new PersonRuleResponsibility();
538                                    copyResponsibility(responsibility, personResponsibility);
539                                    Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipal(personResponsibility.getRuleResponsibilityName());
540                                    personResponsibility.setPrincipalName(principal.getPrincipalName());
541                                    rule.getPersonResponsibilities().add(personResponsibility);
542                            } else if (responsibility.getRuleResponsibilityType().equals(KewApiConstants.RULE_RESPONSIBILITY_GROUP_ID)) {
543                                    GroupRuleResponsibility groupResponsibility = new GroupRuleResponsibility();
544                                    copyResponsibility(responsibility, groupResponsibility);
545                                    Group group = KEWServiceLocator.getIdentityHelperService().getGroup(groupResponsibility.getRuleResponsibilityName());
546                                    groupResponsibility.setNamespaceCode(group.getNamespaceCode());
547                                    groupResponsibility.setName(group.getName());
548                                    rule.getGroupResponsibilities().add(groupResponsibility);
549                            } else if (responsibility.getRuleResponsibilityType().equals(KewApiConstants.RULE_RESPONSIBILITY_ROLE_ID)) {
550                                    RoleRuleResponsibility roleResponsibility = new RoleRuleResponsibility();
551                                    copyResponsibility(responsibility, roleResponsibility);
552                                    rule.getRoleResponsibilities().add(roleResponsibility);
553                            } else {
554                                    throw new RiceRuntimeException("Original responsibility with id '" + responsibility.getId() + "' contained a bad type code of '" + responsibility.getRuleResponsibilityType());
555                            }
556                    }
557                    // since we've loaded the responsibilities, let's clear the originals so they don't get serialized to the maint doc XML
558                    rule.getRuleResponsibilities().clear();
559            }
560    
561            public static void copyResponsibility(RuleResponsibilityBo source, RuleResponsibilityBo target) {
562                    try {
563                            BeanUtils.copyProperties(target, source);
564                    } catch (Exception e) {
565                            throw new RiceRuntimeException("Failed to copy properties from source to target responsibility", e);
566                    }
567            }
568    
569            public static void translateRuleExtensionsForLoad(RuleBaseValues rule) {
570                    for (RuleExtensionBo ruleExtension : rule.getRuleExtensions()) {
571                            String ruleTemplateAttributeId = ruleExtension.getRuleTemplateAttributeId();
572                            for (RuleExtensionValue ruleExtensionValue : ruleExtension.getExtensionValues()) {
573                                    String fieldMapKey = ruleTemplateAttributeId + ID_SEPARATOR + ruleExtensionValue.getKey();
574                                    rule.getFieldValues().put(fieldMapKey, ruleExtensionValue.getValue());
575                            }
576                    }
577                    // since we've loaded the extensions, let's clear the originals so that they don't get serialized to the maint doc XML
578                    rule.getRuleExtensions().clear();
579            }
580    
581            public static void processRuleForCopy(String documentNumber, RuleBaseValues oldRule, RuleBaseValues newRule) {
582                    WebRuleUtils.populateForCopyOrEdit(oldRule, newRule);
583                    clearKeysForCopy(newRule);
584                    newRule.setDocumentId(documentNumber);
585            }
586    
587            public static void clearKeysForCopy(RuleBaseValues rule) {
588            rule.setId(null);
589            rule.setPreviousRuleId(null);
590            rule.setPreviousVersion(null);
591            rule.setName(null);
592            for (PersonRuleResponsibility responsibility : rule.getPersonResponsibilities()) {
593                    clearResponsibilityKeys(responsibility);
594            }
595            for (GroupRuleResponsibility responsibility : rule.getGroupResponsibilities()) {
596                    clearResponsibilityKeys(responsibility);
597            }
598            for (RoleRuleResponsibility responsibility : rule.getRoleResponsibilities()) {
599                    clearResponsibilityKeys(responsibility);
600            }
601        }
602    
603        private static void clearResponsibilityKeys(RuleResponsibilityBo responsibility) {
604                    responsibility.setResponsibilityId(null);
605                    responsibility.setId(null);
606                    responsibility.setRuleBaseValuesId(null);
607        }
608    
609    }