View Javadoc
1   /**
2    * Copyright 2005-2015 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.rule.web;
17  
18  import java.lang.reflect.InvocationTargetException;
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.HashMap;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.apache.commons.beanutils.BeanUtils;
27  import org.apache.commons.beanutils.PropertyUtils;
28  import org.apache.commons.lang.ArrayUtils;
29  import org.apache.commons.lang.StringUtils;
30  import org.kuali.rice.core.api.exception.RiceRuntimeException;
31  import org.kuali.rice.core.api.uif.RemotableAttributeError;
32  import org.kuali.rice.kew.api.KewApiConstants;
33  import org.kuali.rice.kew.api.action.ActionRequestPolicy;
34  import org.kuali.rice.kew.api.rule.RuleTemplateAttributeContract;
35  import org.kuali.rice.kew.doctype.bo.DocumentType;
36  import org.kuali.rice.kew.rule.GroupRuleResponsibility;
37  import org.kuali.rice.kew.rule.PersonRuleResponsibility;
38  import org.kuali.rice.kew.rule.RoleRuleResponsibility;
39  import org.kuali.rice.kew.rule.RuleBaseValues;
40  import org.kuali.rice.kew.rule.RuleDelegationBo;
41  import org.kuali.rice.kew.rule.RuleExtensionBo;
42  import org.kuali.rice.kew.rule.RuleExtensionValue;
43  import org.kuali.rice.kew.rule.RuleResponsibilityBo;
44  import org.kuali.rice.kew.rule.WorkflowRuleAttributeRows;
45  import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo;
46  import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
47  import org.kuali.rice.kew.rule.service.RuleServiceInternal;
48  import org.kuali.rice.kew.service.KEWServiceLocator;
49  import org.kuali.rice.kim.api.group.Group;
50  import org.kuali.rice.kim.api.identity.principal.Principal;
51  import org.kuali.rice.kns.web.ui.Field;
52  import org.kuali.rice.kns.web.ui.Row;
53  import org.kuali.rice.kns.web.ui.Section;
54  
55  /**
56   * Some utilities which are utilized by the {@link RuleAction}.
57   *
58   * @author Kuali Rice Team (rice.collab@kuali.org)
59   */
60  public final class WebRuleUtils {
61  
62  	public static final String RULE_TEMPLATE_ID_PARAM = "ruleCreationValues.ruleTemplateId";
63  	public static final String RULE_TEMPLATE_NAME_PARAM = "ruleCreationValues.ruleTemplateName";
64  	public static final String DOCUMENT_TYPE_NAME_PARAM = "ruleCreationValues.docTypeName";
65  	public static final String RESPONSIBILITY_ID_PARAM = "ruleCreationValues.responsibilityId";
66  
67  	private static final String ID_SEPARATOR = "~";
68  	private static final String RULE_ATTRIBUTES_SECTION_ID = "RuleAttributes";
69  	private static final String RULE_ATTRIBUTES_SECTION_TITLE = "Rule Attributes";
70  	private static final String ROLES_MAINTENANCE_SECTION_ID = "RolesMaintenance";
71  
72  	private WebRuleUtils() {
73  		throw new UnsupportedOperationException("do not call");
74  	}
75  
76  	/**
77  	 * Copies the existing rule onto the current document.  This is used within the web-based rule GUI to make a
78  	 * copy of a rule on the existing document.  Essentially, this method makes a copy of the rule and all
79  	 * delegates but preserves the document ID of the original rule.
80  	 */
81      public static WebRuleBaseValues copyRuleOntoExistingDocument(WebRuleBaseValues rule) throws Exception {
82          WebRuleBaseValues ruleCopy = new WebRuleBaseValues();
83          PropertyUtils.copyProperties(ruleCopy, rule);
84          ruleCopy.setPreviousRuleId(null);
85          ruleCopy.setCurrentInd(null);
86          ruleCopy.setVersionNbr(null);
87  
88          List responsibilities = new ArrayList();
89          for (Iterator iter = ruleCopy.getRuleResponsibilities().iterator(); iter.hasNext();) {
90              WebRuleResponsibility responsibility = (WebRuleResponsibility) iter.next();
91              WebRuleResponsibility responsibilityCopy = new WebRuleResponsibility();
92              PropertyUtils.copyProperties(responsibilityCopy, responsibility);
93  
94              responsibilityCopy.setResponsibilityId(null);
95              responsibilityCopy.setId(null);
96  
97              List delegations = new ArrayList();
98              for (Iterator iterator = responsibilityCopy.getDelegationRules().iterator(); iterator.hasNext();) {
99                  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 && ruleTemplate.getId() != 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 }