View Javadoc

1   /*
2    * Copyright 2005-2007 The Kuali Foundation
3    * 
4    * 
5    * Licensed under the Educational Community License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    * 
9    * http://www.opensource.org/licenses/ecl2.php
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.kuali.rice.kew.rule.web;
18  
19  import java.lang.reflect.InvocationTargetException;
20  import java.util.ArrayList;
21  import java.util.Collections;
22  import java.util.HashMap;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map;
26  
27  import org.apache.commons.beanutils.BeanUtils;
28  import org.apache.commons.beanutils.PropertyUtils;
29  import org.apache.commons.lang.ArrayUtils;
30  import org.apache.commons.lang.StringUtils;
31  import org.kuali.rice.core.exception.RiceRuntimeException;
32  import org.kuali.rice.kew.doctype.bo.DocumentType;
33  import org.kuali.rice.kew.rule.GroupRuleResponsibility;
34  import org.kuali.rice.kew.rule.PersonRuleResponsibility;
35  import org.kuali.rice.kew.rule.RoleRuleResponsibility;
36  import org.kuali.rice.kew.rule.RuleBaseValues;
37  import org.kuali.rice.kew.rule.RuleDelegation;
38  import org.kuali.rice.kew.rule.RuleExtension;
39  import org.kuali.rice.kew.rule.RuleExtensionValue;
40  import org.kuali.rice.kew.rule.RuleResponsibility;
41  import org.kuali.rice.kew.rule.WorkflowAttribute;
42  import org.kuali.rice.kew.rule.bo.RuleAttribute;
43  import org.kuali.rice.kew.rule.bo.RuleTemplate;
44  import org.kuali.rice.kew.rule.bo.RuleTemplateAttribute;
45  import org.kuali.rice.kew.rule.service.RuleService;
46  import org.kuali.rice.kew.rule.xmlrouting.GenericXMLRuleAttribute;
47  import org.kuali.rice.kew.service.KEWServiceLocator;
48  import org.kuali.rice.kew.util.KEWConstants;
49  import org.kuali.rice.kim.bo.Group;
50  import org.kuali.rice.kim.bo.entity.KimPrincipal;
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  /**
57   * Some utilities which are utilized by the {@link RuleAction}.
58   *
59   * @author Kuali Rice Team (rice.collab@kuali.org)
60   */
61  public class WebRuleUtils {
62  
63  	public static final String RULE_TEMPLATE_ID_PARAM = "ruleCreationValues.ruleTemplateId";
64  	public static final String RULE_TEMPLATE_NAME_PARAM = "ruleCreationValues.ruleTemplateName";
65  	public static final String DOCUMENT_TYPE_NAME_PARAM = "ruleCreationValues.docTypeName";
66  	public static final String RESPONSIBILITY_ID_PARAM = "ruleCreationValues.responsibilityId";
67  	
68  	private static final String ID_SEPARATOR = ":";
69  	private static final String RULE_ATTRIBUTES_SECTION_ID = "RuleAttributes";
70  	private static final String RULE_ATTRIBUTES_SECTION_TITLE = "Rule Attributes";
71  	private static final String ROLES_MAINTENANCE_SECTION_ID = "RolesMaintenance";
72  	
73  	/**
74  	 * Copies the existing rule onto the current document.  This is used within the web-based rule GUI to make a
75  	 * copy of a rule on the existing document.  Essentially, this method makes a copy of the rule and all
76  	 * delegates but preserves the document ID of the original rule.
77  	 */
78      public static WebRuleBaseValues copyRuleOntoExistingDocument(WebRuleBaseValues rule) throws Exception {
79          WebRuleBaseValues ruleCopy = new WebRuleBaseValues();
80          PropertyUtils.copyProperties(ruleCopy, rule);
81          ruleCopy.setPreviousVersionId(null);
82          ruleCopy.setCurrentInd(null);
83          ruleCopy.setVersionNbr(null);
84  
85          List responsibilities = new ArrayList();
86          for (Iterator iter = ruleCopy.getResponsibilities().iterator(); iter.hasNext();) {
87              WebRuleResponsibility responsibility = (WebRuleResponsibility) iter.next();
88              WebRuleResponsibility responsibilityCopy = new WebRuleResponsibility();
89              PropertyUtils.copyProperties(responsibilityCopy, responsibility);
90  
91              responsibilityCopy.setResponsibilityId(null);
92              responsibilityCopy.setRuleResponsibilityKey(null);
93              
94              List delegations = new ArrayList();
95              for (Iterator iterator = responsibilityCopy.getDelegationRules().iterator(); iterator.hasNext();) {
96                  RuleDelegation delegation = (RuleDelegation) iterator.next();
97                  RuleDelegation delegationCopy = new RuleDelegation();
98                  PropertyUtils.copyProperties(delegationCopy, delegation);
99  
100                 delegationCopy.setDelegateRuleId(null);
101                 delegationCopy.setVersionNumber(null);
102                 delegationCopy.setRuleDelegationId(null);
103                 delegationCopy.setResponsibilityId(null);
104 
105                 WebRuleBaseValues delegationRule = ((WebRuleBaseValues) delegation.getDelegationRuleBaseValues());
106                 WebRuleBaseValues ruleDelegateCopy = new WebRuleBaseValues();
107                 PropertyUtils.copyProperties(ruleDelegateCopy, delegationRule);
108 
109                 ruleDelegateCopy.setPreviousVersionId(null);
110                 ruleDelegateCopy.setCurrentInd(null);
111                 ruleDelegateCopy.setVersionNbr(null);
112 
113                 List delegateResps = new ArrayList();
114                 for (Iterator iterator1 = ruleDelegateCopy.getResponsibilities().iterator(); iterator1.hasNext();) {
115                     WebRuleResponsibility delegateResp = (WebRuleResponsibility) iterator1.next();
116                     WebRuleResponsibility delegateRespCopy = new WebRuleResponsibility();
117                     PropertyUtils.copyProperties(delegateRespCopy, delegateResp);
118 
119                     delegateRespCopy.setResponsibilityId(null);
120                     delegateRespCopy.setRuleResponsibilityKey(null);
121                     delegateResps.add(delegateRespCopy);
122                 }
123                 ruleDelegateCopy.setResponsibilities(delegateResps);
124                 delegationCopy.setDelegationRuleBaseValues(ruleDelegateCopy);
125                 delegations.add(delegationCopy);
126             }
127             //responsibilityCopy.setDelegationRules(delegations);
128             responsibilities.add(responsibilityCopy);
129         }
130         ruleCopy.setResponsibilities(responsibilities);
131         return ruleCopy;
132     }
133     
134     /**
135      * Makes a copy of the rule and clears the document id on the rule and any of its delegates.
136      * This method is used for making a copy of a rule for a new document.  It essentially calls
137      * the copyRuleOntoExistingDocument method and then clears out the document IDs.
138      * 
139      * @param webRuleBaseValues
140      */
141     public static WebRuleBaseValues copyToNewRule(WebRuleBaseValues webRuleBaseValues) throws Exception {
142     	WebRuleBaseValues newRule = copyRuleOntoExistingDocument(webRuleBaseValues);
143     	// clear out all document IDs on the rule and it's delegates
144     	newRule.setRouteHeaderId(null);
145     	for (Iterator iterator = newRule.getResponsibilities().iterator(); iterator.hasNext(); ) {
146 			RuleResponsibility responsibility = (RuleResponsibility) iterator.next();
147 			for (Iterator iterator2 = responsibility.getDelegationRules().iterator(); iterator2.hasNext(); ) {
148 				RuleDelegation delegation = (RuleDelegation) iterator2.next();
149 				delegation.getDelegationRuleBaseValues().setRouteHeaderId(null);
150 			}
151 		}
152     	return newRule;
153     }
154 
155     public static void validateRuleTemplateAndDocumentType(RuleBaseValues oldRule, RuleBaseValues newRule, Map<String, String[]> parameters) {
156 		String[] ruleTemplateIds = parameters.get(RULE_TEMPLATE_ID_PARAM);
157 		String[] ruleTemplateNames = parameters.get(RULE_TEMPLATE_NAME_PARAM);
158 		String[] documentTypeNames = parameters.get(DOCUMENT_TYPE_NAME_PARAM);
159 		if (ArrayUtils.isEmpty(ruleTemplateIds) && ArrayUtils.isEmpty(ruleTemplateNames)) {
160 			throw new RiceRuntimeException("Rule document must be initiated with a valid rule template id or rule template name.");
161 		}
162 		if (ArrayUtils.isEmpty(documentTypeNames)) {
163 			throw new RiceRuntimeException("Rule document must be initiated with a valid document type name.");
164 		}
165 		RuleTemplate ruleTemplate = null;
166 		if (!ArrayUtils.isEmpty(ruleTemplateIds)) {
167 			String ruleTemplateId = ruleTemplateIds[0];
168 			ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateId(new Long(ruleTemplateId));
169 			if (ruleTemplate == null) {
170 				throw new RiceRuntimeException("Failed to load rule template with id '" + ruleTemplateId + "'");
171 			}
172 		}
173 		if (ruleTemplate == null) {
174 			String ruleTemplateName = ruleTemplateNames[0];
175 			ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateName(ruleTemplateName);
176 			if (ruleTemplate == null) {
177 				throw new RiceRuntimeException("Failed to load rule template with name '" + ruleTemplateName + "'");
178 			}
179 		}
180 		String documentTypeName = documentTypeNames[0];
181 		DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
182 		if (documentType == null) {
183 			throw new RiceRuntimeException("Failed to locate document type with name '" + documentTypeName + "'");
184 		}
185 		
186 		// it appears that there is always an old maintainable, even in the case of a new document creation,
187 		// if we don't initialize both the old and new versions we get errors during meshSections
188 		initializeRuleAfterNew(oldRule, ruleTemplate, documentTypeName);
189 		initializeRuleAfterNew(newRule, ruleTemplate, documentTypeName);
190 	}
191     
192 	private static void initializeRuleAfterNew(RuleBaseValues rule, RuleTemplate ruleTemplate, String documentTypeName) {
193 		rule.setRuleTemplate(ruleTemplate);
194 		rule.setRuleTemplateId(ruleTemplate.getRuleTemplateId());
195 		rule.setDocTypeName(documentTypeName);
196 	}
197 	
198 	public static void validateRuleAndResponsibility(RuleDelegation oldRuleDelegation, RuleDelegation newRuleDelegation, Map<String, String[]> parameters) {
199 		String[] responsibilityIds = parameters.get(RESPONSIBILITY_ID_PARAM);
200 		if (ArrayUtils.isEmpty(responsibilityIds)) {
201 			throw new RiceRuntimeException("Delegation rule document must be initiated with a valid responsibility ID to delegate from.");
202 		}
203 		if (!ArrayUtils.isEmpty(responsibilityIds)) {
204 			Long responsibilityId = new Long(responsibilityIds[0]);
205 			RuleResponsibility ruleResponsibility = KEWServiceLocator.getRuleService().findRuleResponsibility(responsibilityId);
206 			if (ruleResponsibility == null) {
207 				throw new RiceRuntimeException("Failed to locate a rule responsibility for responsibility ID " + responsibilityId);
208 			}
209 			oldRuleDelegation.setResponsibilityId(responsibilityId);
210 			newRuleDelegation.setResponsibilityId(responsibilityId);
211 		}
212 		
213 	}
214 
215 	public static void establishDefaultRuleValues(RuleBaseValues rule) {
216 		rule.setActiveInd(true);
217 
218         RuleBaseValues defaultRule = ((RuleService) KEWServiceLocator.getService(KEWServiceLocator.RULE_SERVICE)).findDefaultRuleByRuleTemplateId(
219         		rule.getRuleTemplate().getDelegationTemplateId());
220         if (defaultRule != null) {
221             defaultRule.setActivationDate(null);
222             defaultRule.setCurrentInd(null);
223             defaultRule.setDeactivationDate(null);
224             defaultRule.setDocTypeName(null);
225             defaultRule.setVersionNumber(null);
226             defaultRule.setRuleBaseValuesId(null);
227             defaultRule.setTemplateRuleInd(Boolean.FALSE);
228             defaultRule.setVersionNbr(null);
229             try {
230 				PropertyUtils.copyProperties(rule, defaultRule);
231 			} catch (IllegalAccessException e) {
232 				throw new RuntimeException(e);
233 			} catch (InvocationTargetException e) {
234 				throw new RuntimeException(e);
235 			} catch (NoSuchMethodException e) {
236 				throw new RuntimeException(e);
237 			}
238         }
239 	}
240 	
241 
242 	public static List customizeSections(RuleBaseValues rule, List<Section> sections, boolean delegateRule) {
243 
244 		List<Section> finalSections = new ArrayList<Section>();
245 		for (Section section : sections) {
246 			// unfortunately, in the case of an inquiry the sectionId will always be null so we have to check section title
247 			if (section.getSectionTitle().equals(RULE_ATTRIBUTES_SECTION_TITLE) || 
248 					RULE_ATTRIBUTES_SECTION_ID.equals(section.getSectionId())) {
249 				List<Row> ruleTemplateRows = getRuleTemplateRows(rule, delegateRule);
250 				if (!ruleTemplateRows.isEmpty()) {
251 					section.setRows(ruleTemplateRows);
252 					finalSections.add(section);
253 				}
254 			} else if (ROLES_MAINTENANCE_SECTION_ID.equals(section.getSectionId())) {
255 				if (hasRoles(rule)) {
256 					finalSections.add(section);
257 				}
258 			} else {
259 				finalSections.add(section);
260 			}
261 		}
262 		
263 		return finalSections;
264 	}
265 	
266 	
267 	
268 
269 	public static List<Row> getRuleTemplateRows(RuleBaseValues rule, boolean delegateRule) {
270 
271 		List<Row> rows = new ArrayList<Row>();
272 		RuleTemplate ruleTemplate = rule.getRuleTemplate();
273 		Map<String, String> fieldNameMap = new HashMap<String, String>();
274 		// refetch rule template from service because after persistence in KNS, it comes back without any rule template attributes
275 		if (ruleTemplate != null){
276 			ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateId(ruleTemplate.getRuleTemplateId());
277 			if (ruleTemplate != null) {
278 				
279 				List<RuleTemplateAttribute> ruleTemplateAttributes = ruleTemplate.getActiveRuleTemplateAttributes();
280 				Collections.sort(ruleTemplateAttributes);
281 
282 				for (RuleTemplateAttribute ruleTemplateAttribute : ruleTemplateAttributes) {
283 					if (!ruleTemplateAttribute.isWorkflowAttribute()) {
284 						continue;
285 					}
286 					WorkflowAttribute workflowAttribute = ruleTemplateAttribute.getWorkflowAttribute();
287 					RuleAttribute ruleAttribute = ruleTemplateAttribute.getRuleAttribute();
288 					if (ruleAttribute.getType().equals(KEWConstants.RULE_XML_ATTRIBUTE_TYPE)) {
289 						((GenericXMLRuleAttribute) workflowAttribute).setRuleAttribute(ruleAttribute);
290 					}
291 					Map<String, String> parameterMap = getFieldMapForRuleTemplateAttribute(rule, ruleTemplateAttribute);
292 					workflowAttribute.validateRuleData(parameterMap);
293 					List<Row> attributeRows = transformAndPopulateAttributeRows(workflowAttribute.getRuleRows(), ruleTemplateAttribute, rule, fieldNameMap, delegateRule);
294 					rows.addAll(attributeRows);
295 
296 				}
297 			}
298 			transformFieldConversions(rows, fieldNameMap);
299 		}
300 		return rows;
301 	}
302 	
303 	public static void transformFieldConversions(List<Row> rows, Map<String, String> fieldNameMap) {
304 		for (Row row : rows) {
305 			Map<String, String> transformedFieldConversions = new HashMap<String, String>();
306 			for (Field field : row.getFields()) {
307 				Map<String, String> fieldConversions = field.getFieldConversionMap();
308 				for (String lookupFieldName : fieldConversions.keySet()) {
309 					String localFieldName = fieldConversions.get(lookupFieldName);
310 					if (fieldNameMap.containsKey(localFieldName)) {
311 						// set the transformed value
312 						transformedFieldConversions.put(lookupFieldName, fieldNameMap.get(localFieldName));
313 					} else {
314 						// set the original value (not sure if this case will happen, but just in case)
315 						transformedFieldConversions.put(lookupFieldName, fieldConversions.get(lookupFieldName));
316 					}
317 				}
318 				field.setFieldConversions(transformedFieldConversions);
319 			}
320 		}
321 	}
322 	
323 
324 
325 	
326 	private static boolean hasRoles(RuleBaseValues rule) {
327 		RuleTemplate ruleTemplate = rule.getRuleTemplate();
328 		return !ruleTemplate.getRoles().isEmpty();
329 	}
330 	
331 	/**
332 	 * Processes the Fields on the various attributes Rows to assign an appropriate field name to them so that the
333 	 * field name rendered in the maintenance HTML will properly assign the value to RuleBaseValues.fieldValues.
334 	 */
335 	
336 	public static List<Row> transformAndPopulateAttributeRows(List<Row> attributeRows, RuleTemplateAttribute ruleTemplateAttribute, RuleBaseValues rule, Map<String, String> fieldNameMap, boolean delegateRule) {
337 
338 		for (Row row : attributeRows) {
339 			for (Field field : row.getFields()) {
340 				String fieldName = field.getPropertyName();
341 				if (!StringUtils.isBlank(fieldName)) {
342 					String valueKey = ruleTemplateAttribute.getRuleTemplateAttributeId() + ID_SEPARATOR + fieldName;
343 
344 					String propertyName;
345 					
346 					if (delegateRule) {
347 						propertyName = "delegationRuleBaseValues.fieldValues(" + valueKey + ")"; 
348 					} else {
349 						propertyName = "fieldValues(" + valueKey + ")"; 
350 					}
351 
352 					fieldNameMap.put(fieldName, propertyName);
353 					field.setPropertyName(propertyName);
354 					field.setPropertyValue(rule.getFieldValues().get(valueKey));
355 				}
356 			}
357 		}
358 		return attributeRows;
359 	}
360 	
361 	/**
362 	 * Since editing of a Rule should actually result in a rule with a new ID and new
363 	 * entries in the rule and rule responsibility tables, we need to clear out
364 	 * the primary keys of the rule and related objects.
365 	 */
366 	public static void clearKeysForSave(RuleBaseValues rule) {
367 		rule.setRuleBaseValuesId(null);
368 		rule.setActivationDate(null);
369 		rule.setDeactivationDate(null);
370 		rule.setCurrentInd(false);
371 		rule.setVersionNbr(null);
372 		rule.setObjectId(null);
373 		rule.setVersionNumber(0L);
374 	}
375 	
376 	public static void clearKeysForSave(RuleDelegation ruleDelegation) {
377 		ruleDelegation.setRuleDelegationId(null);
378 		ruleDelegation.setObjectId(null);
379 		ruleDelegation.setVersionNumber(0L);
380 		clearKeysForSave(ruleDelegation.getDelegationRuleBaseValues());
381 	}
382 	
383     public static void translateResponsibilitiesForSave(RuleBaseValues rule) {
384 		rule.getResponsibilities().clear();
385 		for (PersonRuleResponsibility responsibility : rule.getPersonResponsibilities()) {
386 			RuleResponsibility ruleResponsibility = new RuleResponsibility();
387 			ruleResponsibility.setActionRequestedCd(responsibility.getActionRequestedCd());
388 			ruleResponsibility.setPriority(responsibility.getPriority());
389 			ruleResponsibility.setResponsibilityId(responsibility.getResponsibilityId());
390 			if (ruleResponsibility.getResponsibilityId() == null) {
391 				ruleResponsibility.setResponsibilityId(KEWServiceLocator.getResponsibilityIdService().getNewResponsibilityId());
392 			}
393 			String principalId = KEWServiceLocator.getIdentityHelperService().getIdForPrincipalName(responsibility.getPrincipalName());
394 			ruleResponsibility.setRuleResponsibilityName(principalId);
395 			ruleResponsibility.setRuleResponsibilityType(KEWConstants.RULE_RESPONSIBILITY_WORKFLOW_ID);
396 			// default the approve policy to First Approve
397 			ruleResponsibility.setApprovePolicy(KEWConstants.APPROVE_POLICY_FIRST_APPROVE);
398 			rule.getResponsibilities().add(ruleResponsibility);
399 		}
400 		for (GroupRuleResponsibility responsibility : rule.getGroupResponsibilities()) {
401 			RuleResponsibility ruleResponsibility = new RuleResponsibility();
402 			ruleResponsibility.setActionRequestedCd(responsibility.getActionRequestedCd());
403 			ruleResponsibility.setPriority(responsibility.getPriority());
404 			ruleResponsibility.setResponsibilityId(responsibility.getResponsibilityId());
405 			if (ruleResponsibility.getResponsibilityId() == null) {
406 				ruleResponsibility.setResponsibilityId(KEWServiceLocator.getResponsibilityIdService().getNewResponsibilityId());
407 			}
408 			Group group = KEWServiceLocator.getIdentityHelperService().getGroupByName(responsibility.getNamespaceCode(), responsibility.getName());
409 			ruleResponsibility.setRuleResponsibilityName(group.getGroupId());
410 			ruleResponsibility.setRuleResponsibilityType(KEWConstants.RULE_RESPONSIBILITY_GROUP_ID);
411 			ruleResponsibility.setApprovePolicy(KEWConstants.APPROVE_POLICY_FIRST_APPROVE);
412 			rule.getResponsibilities().add(ruleResponsibility);
413 		}
414 		for (RoleRuleResponsibility responsibility : rule.getRoleResponsibilities()) {
415 			RuleResponsibility ruleResponsibility = new RuleResponsibility();
416 			ruleResponsibility.setActionRequestedCd(responsibility.getActionRequestedCd());
417 			ruleResponsibility.setPriority(responsibility.getPriority());
418 			ruleResponsibility.setResponsibilityId(responsibility.getResponsibilityId());
419 			if (ruleResponsibility.getResponsibilityId() == null) {
420 				ruleResponsibility.setResponsibilityId(KEWServiceLocator.getResponsibilityIdService().getNewResponsibilityId());
421 			}
422 			ruleResponsibility.setRuleResponsibilityName(responsibility.getRoleName());
423 			ruleResponsibility.setRuleResponsibilityType(KEWConstants.RULE_RESPONSIBILITY_ROLE_ID);
424 			ruleResponsibility.setApprovePolicy(responsibility.getApprovePolicy());
425 			rule.getResponsibilities().add(ruleResponsibility);
426 		}
427 	}
428     
429     public static void translateFieldValuesForSave(RuleBaseValues rule) {
430     	RuleTemplate ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateId(rule.getRuleTemplateId());
431 
432 		/** Populate rule extension values * */
433 		List extensions = new ArrayList();
434 		for (Iterator iterator = ruleTemplate.getActiveRuleTemplateAttributes().iterator(); iterator.hasNext();) {
435 			RuleTemplateAttribute ruleTemplateAttribute = (RuleTemplateAttribute) iterator.next();
436 			if (!ruleTemplateAttribute.isWorkflowAttribute()) {
437 				continue;
438 			}
439 			WorkflowAttribute workflowAttribute = ruleTemplateAttribute.getWorkflowAttribute();
440 
441 			RuleAttribute ruleAttribute = ruleTemplateAttribute.getRuleAttribute();
442 			if (ruleAttribute.getType().equals(KEWConstants.RULE_XML_ATTRIBUTE_TYPE)) {
443 				((GenericXMLRuleAttribute) workflowAttribute).setRuleAttribute(ruleAttribute);
444 			}
445 
446 			Map<String, String> parameterMap = getFieldMapForRuleTemplateAttribute(rule, ruleTemplateAttribute);
447 						
448 			// validate rule data populates the rule extension values for us
449 			List attValidationErrors = workflowAttribute.validateRuleData(parameterMap);
450 
451 			// because validation should be handled by business rules now, if we encounter a validation error at this point in
452 			// time, let's throw an exception
453 			if (attValidationErrors != null && !attValidationErrors.isEmpty()) {
454 				throw new RiceRuntimeException("Encountered attribute validation errors when attempting to save the Rule!");
455 			}
456 			
457 			List ruleExtensionValues = workflowAttribute.getRuleExtensionValues();
458 			if (ruleExtensionValues != null && !ruleExtensionValues.isEmpty()) {
459 				RuleExtension ruleExtension = new RuleExtension();
460 				ruleExtension.setRuleTemplateAttributeId(ruleTemplateAttribute.getRuleTemplateAttributeId());
461 
462 				ruleExtension.setExtensionValues(ruleExtensionValues);
463 				extensions.add(ruleExtension);
464 			}
465 				
466 		}
467 		rule.setRuleExtensions(extensions);
468 
469 		for (Iterator iterator = rule.getRuleExtensions().iterator(); iterator.hasNext();) {
470 			RuleExtension ruleExtension = (RuleExtension) iterator.next();
471 			ruleExtension.setRuleBaseValues(rule);
472 
473 			for (Iterator iterator2 = ruleTemplate.getActiveRuleTemplateAttributes().iterator(); iterator2.hasNext();) {
474 				RuleTemplateAttribute ruleTemplateAttribute = (RuleTemplateAttribute) iterator2.next();
475 				if (ruleTemplateAttribute.getRuleTemplateAttributeId().longValue() == ruleExtension.getRuleTemplateAttributeId().longValue()) {
476 					ruleExtension.setRuleTemplateAttribute(ruleTemplateAttribute);
477 					break;
478 				}
479 			}
480 
481 			for (Iterator iterator2 = ruleExtension.getExtensionValues().iterator(); iterator2.hasNext();) {
482 				RuleExtensionValue ruleExtensionValue = (RuleExtensionValue) iterator2.next();
483 				ruleExtensionValue.setExtension(ruleExtension);
484 			}
485 		}
486     }
487 
488     /**
489      * Based on original logic implemented in Rule system.  Essentially constructs a Map of field values related
490      * to the given RuleTemplateAttribute.
491      */
492     public static Map<String, String> getFieldMapForRuleTemplateAttribute(RuleBaseValues rule, RuleTemplateAttribute ruleTemplateAttribute) {
493     	Map<String, String> fieldMap = new HashMap<String, String>();
494     	for (String fieldKey : rule.getFieldValues().keySet()) {
495     		String ruleTemplateAttributeId = fieldKey.substring(0, fieldKey.indexOf(ID_SEPARATOR));
496     		String fieldName = fieldKey.substring(fieldKey.indexOf(ID_SEPARATOR) + 1);
497     		if (ruleTemplateAttribute.getRuleTemplateAttributeId().toString().equals(ruleTemplateAttributeId)) {
498     			fieldMap.put(fieldName, rule.getFieldValues().get(fieldKey));
499     		}
500     	}
501     	return fieldMap;
502     }
503     
504     public static void processRuleForDelegationSave(RuleDelegation ruleDelegation) {
505     	RuleBaseValues rule = ruleDelegation.getDelegationRuleBaseValues();
506     	rule.setDelegateRule(true);
507     	// certain items on a delegated rule responsibility are inherited from parent responsibility, set them to null
508     	for (RuleResponsibility responsibility : rule.getResponsibilities()) {
509     		responsibility.setActionRequestedCd(null);
510     		responsibility.setPriority(null);
511     	}
512     }
513     
514     public static void populateForCopyOrEdit(RuleBaseValues oldRule, RuleBaseValues newRule) {
515 		populateRuleMaintenanceFields(oldRule);
516 		populateRuleMaintenanceFields(newRule);
517 		// in the case of copy, our fields which are marked read only are cleared, this includes the rule template
518 		// name and the document type name but we don't want these cleared
519 		if (newRule.getRuleTemplate().getName() == null) {
520 			newRule.getRuleTemplate().setName(oldRule.getRuleTemplate().getName());
521 		}
522 		if (newRule.getDocTypeName() == null) {
523 			newRule.setDocTypeName(oldRule.getDocTypeName());
524 		}
525 	}
526     
527     /**
528 	 * This method populates fields on RuleBaseValues which are used only for
529 	 * maintenance purposes.  In otherwords, it populates the non-persistent fields
530 	 * on the RuleBaseValues which the maintenance document needs to function
531 	 * (such as the extension field values and responsibilities).
532 	 */
533 	public static void populateRuleMaintenanceFields(RuleBaseValues rule) {
534 		translateResponsibilitiesForLoad(rule);
535 		translateRuleExtensionsForLoad(rule);
536 	}
537 	
538 	public static void translateResponsibilitiesForLoad(RuleBaseValues rule) {
539 		for (RuleResponsibility responsibility : rule.getResponsibilities()) {
540 			if (responsibility.getRuleResponsibilityType().equals(KEWConstants.RULE_RESPONSIBILITY_WORKFLOW_ID)) {
541 				PersonRuleResponsibility personResponsibility = new PersonRuleResponsibility();
542 				copyResponsibility(responsibility, personResponsibility);
543 				KimPrincipal principal = KEWServiceLocator.getIdentityHelperService().getPrincipal(personResponsibility.getRuleResponsibilityName());
544 				personResponsibility.setPrincipalName(principal.getPrincipalName());
545 				rule.getPersonResponsibilities().add(personResponsibility);
546 			} else if (responsibility.getRuleResponsibilityType().equals(KEWConstants.RULE_RESPONSIBILITY_GROUP_ID)) {
547 				GroupRuleResponsibility groupResponsibility = new GroupRuleResponsibility();
548 				copyResponsibility(responsibility, groupResponsibility);
549 				Group group = KEWServiceLocator.getIdentityHelperService().getGroup(groupResponsibility.getRuleResponsibilityName());
550 				groupResponsibility.setNamespaceCode(group.getNamespaceCode());
551 				groupResponsibility.setName(group.getGroupName());
552 				rule.getGroupResponsibilities().add(groupResponsibility);
553 			} else if (responsibility.getRuleResponsibilityType().equals(KEWConstants.RULE_RESPONSIBILITY_ROLE_ID)) {
554 				RoleRuleResponsibility roleResponsibility = new RoleRuleResponsibility();
555 				copyResponsibility(responsibility, roleResponsibility);
556 				rule.getRoleResponsibilities().add(roleResponsibility);
557 			} else {
558 				throw new RiceRuntimeException("Original responsibility with id '" + responsibility.getRuleResponsibilityKey() + "' contained a bad type code of '" + responsibility.getRuleResponsibilityType());
559 			}
560 		}
561 		// since we've loaded the responsibilities, let's clear the originals so they don't get serialized to the maint doc XML
562 		rule.getResponsibilities().clear();
563 	}
564 	
565 	public static void copyResponsibility(RuleResponsibility source, RuleResponsibility target) {
566 		try {
567 			BeanUtils.copyProperties(target, source);
568 		} catch (Exception e) {
569 			throw new RiceRuntimeException("Failed to copy properties from source to target responsibility", e);
570 		}
571 	}
572 	
573 	public static void translateRuleExtensionsForLoad(RuleBaseValues rule) {
574 		for (RuleExtension ruleExtension : rule.getRuleExtensions()) {
575 			Long ruleTemplateAttributeId = ruleExtension.getRuleTemplateAttributeId();
576 			for (RuleExtensionValue ruleExtensionValue : ruleExtension.getExtensionValues()) {
577 				String fieldMapKey = ruleTemplateAttributeId + ID_SEPARATOR + ruleExtensionValue.getKey();
578 				rule.getFieldValues().put(fieldMapKey, ruleExtensionValue.getValue());
579 			}
580 		}
581 		// since we've loaded the extensions, let's clear the originals so that they don't get serialized to the maint doc XML
582 		rule.getRuleExtensions().clear();
583 	}
584 	
585 	public static void processRuleForCopy(String documentNumber, RuleBaseValues oldRule, RuleBaseValues newRule) {
586 		WebRuleUtils.populateForCopyOrEdit(oldRule, newRule);
587 		clearKeysForCopy(newRule);
588 		newRule.setRouteHeaderId(new Long(documentNumber));
589 	}
590 	
591 	public static void clearKeysForCopy(RuleBaseValues rule) {    	
592     	rule.setRuleBaseValuesId(null);
593     	rule.setPreviousVersionId(null);
594     	rule.setPreviousVersion(null);
595     	rule.setName(null);
596     	for (PersonRuleResponsibility responsibility : rule.getPersonResponsibilities()) {
597     		clearResponsibilityKeys(responsibility);
598     	}
599     	for (GroupRuleResponsibility responsibility : rule.getGroupResponsibilities()) {
600     		clearResponsibilityKeys(responsibility);
601     	}
602     	for (RoleRuleResponsibility responsibility : rule.getRoleResponsibilities()) {
603     		clearResponsibilityKeys(responsibility);
604     	}
605     }
606 
607     private static void clearResponsibilityKeys(RuleResponsibility responsibility) {
608 		responsibility.setResponsibilityId(null);
609 		responsibility.setRuleResponsibilityKey(null);
610 		responsibility.setRuleBaseValuesId(null);
611     }
612     
613 }