View Javadoc

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