View Javadoc
1   /**
2    * Copyright 2005-2013 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.krms.service.impl;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.ojb.broker.OptimisticLockException;
20  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
21  import org.kuali.rice.core.api.util.tree.Node;
22  import org.kuali.rice.core.api.util.tree.Tree;
23  import org.kuali.rice.krad.bo.Note;
24  import org.kuali.rice.krad.maintenance.MaintenanceDocument;
25  import org.kuali.rice.krad.uif.UifConstants;
26  import org.kuali.rice.krad.uif.component.BindingInfo;
27  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
28  import org.kuali.rice.krad.uif.view.ViewModel;
29  import org.kuali.rice.krad.util.KRADConstants;
30  import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
31  import org.kuali.rice.krms.api.KrmsConstants;
32  import org.kuali.rice.krms.api.repository.RuleManagementService;
33  import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
34  import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition;
35  import org.kuali.rice.krms.api.repository.context.ContextDefinition;
36  import org.kuali.rice.krms.api.repository.language.NaturalLanguageTemplate;
37  import org.kuali.rice.krms.api.repository.proposition.PropositionType;
38  import org.kuali.rice.krms.api.repository.reference.ReferenceObjectBinding;
39  import org.kuali.rice.krms.api.repository.rule.RuleDefinition;
40  import org.kuali.rice.krms.api.repository.term.TermRepositoryService;
41  import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
42  import org.kuali.rice.krms.api.repository.type.KrmsTypeRepositoryService;
43  import org.kuali.rice.krms.api.repository.typerelation.TypeTypeRelation;
44  import org.kuali.rice.krms.builder.ComponentBuilder;
45  import org.kuali.rice.krms.dto.AgendaEditor;
46  import org.kuali.rice.krms.dto.AgendaTypeInfo;
47  import org.kuali.rice.krms.dto.PropositionEditor;
48  import org.kuali.rice.krms.dto.PropositionParameterEditor;
49  import org.kuali.rice.krms.dto.RuleEditor;
50  import org.kuali.rice.krms.dto.RuleManagementWrapper;
51  import org.kuali.rice.krms.dto.RuleManager;
52  import org.kuali.rice.krms.dto.RuleTypeInfo;
53  import org.kuali.rice.krms.dto.TermEditor;
54  import org.kuali.rice.krms.dto.TermParameterEditor;
55  import org.kuali.rice.krms.service.RuleEditorMaintainable;
56  import org.kuali.rice.krms.service.TemplateRegistry;
57  import org.kuali.rice.krms.tree.RuleCompareTreeBuilder;
58  import org.kuali.rice.krms.tree.RuleViewTreeBuilder;
59  import org.kuali.rice.krms.tree.node.RuleEditorTreeNode;
60  import org.kuali.rice.krms.util.AlphaIterator;
61  import org.kuali.rice.krms.util.PropositionTreeUtil;
62  import org.kuali.student.common.krms.exceptions.KRMSOptimisticLockingException;
63  import org.kuali.student.common.uif.service.impl.KSMaintainableImpl;
64  import org.kuali.student.r1.common.rice.StudentIdentityConstants;
65  import org.kuali.student.r2.core.constants.KSKRMSServiceConstants;
66  import org.slf4j.Logger;
67  import org.slf4j.LoggerFactory;
68  import org.springmodules.orm.ojb.OjbOperationException;
69  
70  import javax.xml.namespace.QName;
71  import java.util.ArrayList;
72  import java.util.Collection;
73  import java.util.Collections;
74  import java.util.Comparator;
75  import java.util.HashMap;
76  import java.util.LinkedHashMap;
77  import java.util.LinkedList;
78  import java.util.List;
79  import java.util.Map;
80  import java.util.Queue;
81  
82  /**
83   * {@link org.kuali.rice.krad.maintenance.Maintainable}
84   *
85   * @author Kuali Student Team (rice.collab@kuali.org)
86   */
87  public class RuleEditorMaintainableImpl extends KSMaintainableImpl implements RuleEditorMaintainable {
88  
89      private static final long serialVersionUID = 1L;
90  
91      private static final Logger LOG = LoggerFactory.getLogger(RuleEditorMaintainableImpl.class);
92  
93      private transient RuleManagementService ruleManagementService;
94      private transient KrmsTypeRepositoryService krmsTypeRepositoryService;
95      private transient TermRepositoryService termRepositoryService;
96  
97      private transient TemplateRegistry templateRegistry;
98      private AlphaIterator alphaIterator = new AlphaIterator(StringUtils.EMPTY);
99  
100     public static final String NEW_AGENDA_EDITOR_DOCUMENT_TEXT = "New Agenda Editor Document";
101 
102     public String getViewTypeName() {
103         return "kuali.krms.agenda.type";
104     }
105 
106     /**
107      * Get the AgendaEditor out of the MaintenanceDocumentForm's newMaintainableObject
108      *
109      * @param model the MaintenanceDocumentForm
110      * @return the AgendaEditor
111      */
112     private RuleEditor getRuleEditor(Object model) {
113         MaintenanceDocumentForm maintenanceDocumentForm = (MaintenanceDocumentForm) model;
114         return (RuleEditor) maintenanceDocumentForm.getDocument().getNewMaintainableObject().getDataObject();
115     }
116 
117     @Override
118     public Object retrieveObjectForEditOrCopy(MaintenanceDocument document, Map<String, String> dataObjectKeys) {
119         RuleManager dataObject = new RuleManagementWrapper();
120 
121         String refObjectId = dataObjectKeys.get("refObjectId");
122         dataObject.setRefObjectId(refObjectId);
123 
124         dataObject.setAgendas(this.getAgendasForRef("", refObjectId, null));
125 
126         dataObject.setCompareTree(RuleCompareTreeBuilder.initCompareTree());
127 
128         return dataObject;
129     }
130 
131     protected List<AgendaEditor> getAgendasForRef(String discriminatorType, String refObjectId, String parentRefObjectId) {
132         // Initialize new array lists.
133         List<AgendaEditor> agendas = new ArrayList<AgendaEditor>();
134         List<AgendaEditor> sortedAgendas = new ArrayList<AgendaEditor>();
135         List<AgendaEditor> parentAgendas = new ArrayList<AgendaEditor>();
136 
137         // Get the list of existing agendas
138         LOG.info("Retrieving reference object binding for refobjectid: {}", refObjectId);
139         List<ReferenceObjectBinding> refObjectsBindings = this.getRuleManagementService().findReferenceObjectBindingsByReferenceObject(discriminatorType, refObjectId);
140         for (ReferenceObjectBinding referenceObjectBinding : refObjectsBindings) {
141             LOG.info("Retrieved reference object binding with id: {}", referenceObjectBinding.getReferenceObjectId());
142             agendas.add(this.getAgendaEditor(referenceObjectBinding.getKrmsObjectId()));
143         }
144 
145         // Get the list of parent agendas
146         List<ReferenceObjectBinding> parentRefObjects = this.getParentRefOjbects(parentRefObjectId);
147         for (ReferenceObjectBinding referenceObject : parentRefObjects) {
148             parentAgendas.add(this.getAgendaEditor(referenceObject.getKrmsObjectId()));
149         }
150 
151         // Lookup existing agenda by type
152         for (AgendaTypeInfo agendaTypeInfo : this.getTypeRelationships()) {
153             AgendaEditor agenda = null;
154             for (AgendaEditor existingAgenda : agendas) {
155                 if (existingAgenda.getTypeId().equals(agendaTypeInfo.getId())) {
156                     agenda = existingAgenda;
157                     break;
158                 }
159             }
160             if (agenda == null) {
161                 agenda = new AgendaEditor();
162                 agenda.setTypeId(agendaTypeInfo.getId());
163             }
164 
165             //Set the parent agenda.
166             for (AgendaEditor parent : parentAgendas) {
167                 if (agenda.getTypeId().equals(agenda.getTypeId())) {
168                     agenda.setParent(parent);
169                     break;
170                 }
171             }
172 
173             agenda.setAgendaTypeInfo(agendaTypeInfo);
174             agenda.setRuleEditors(this.getRulesForAgendas(agenda));
175             sortedAgendas.add(agenda);
176         }
177 
178         return sortedAgendas;
179     }
180 
181     protected AgendaEditor getAgendaEditor(String agendaId) {
182         LOG.info("Retrieving agenda for id: {}", agendaId);
183         AgendaDefinition agenda = this.getRuleManagementService().getAgenda(agendaId);
184         return new AgendaEditor(agenda);
185     }
186 
187     public Map<String, RuleEditor> getRulesForAgendas(AgendaEditor agenda) {
188 
189         //Get all existing rules.
190         List<RuleEditor> existingRules = null;
191         if (agenda.getId() != null) {
192             LOG.info("Retrieving agenda item for id: {}", agenda.getFirstItemId());
193             AgendaItemDefinition firstItem = this.getRuleManagementService().getAgendaItem(agenda.getFirstItemId());
194             existingRules = getRuleEditorsFromTree(firstItem, true);
195         }
196 
197         //Get the parent rules
198         List<RuleEditor> parentRules = null;
199         if (agenda.getParent() != null) {
200             AgendaItemDefinition parentItem = this.getRuleManagementService().getAgendaItem(agenda.getParent().getFirstItemId());
201             parentRules = getRuleEditorsFromTree(parentItem, false);
202         }
203 
204         //Add dummy RuleEditors for empty rule types.
205         Map<String, RuleEditor> ruleEditors = new LinkedHashMap<String, RuleEditor>();
206         for (RuleTypeInfo ruleType : agenda.getAgendaTypeInfo().getRuleTypes()) {
207             RuleEditor ruleEditor = null;
208 
209             // Add all existing rules of this type.
210             if (existingRules != null) {
211                 for (RuleEditor rule : existingRules) {
212                     if (rule.getTypeId().equals(ruleType.getId()) && (!rule.isDummy())) {
213                         ruleEditor = rule;
214                     }
215                 }
216             }
217 
218             // If the ruletype does not exist, add an empty rule section
219             if (ruleEditor == null) {
220                 ruleEditor = createDummyRuleEditor(ruleType.getId());
221             }
222 
223             ruleEditor.setKey((String) alphaIterator.next());
224             ruleEditor.setRuleTypeInfo(ruleType);
225             ruleEditors.put(ruleEditor.getKey(), ruleEditor);
226 
227             //Set the parent agenda.
228             if (parentRules != null) {
229                 for (RuleEditor parent : parentRules) {
230                     if (ruleEditor.getTypeId().equals(parent.getTypeId())) {
231                         ruleEditor.setParent(parent);
232                         break;
233                     }
234                 }
235             }
236         }
237 
238         return ruleEditors;
239     }
240 
241     protected RuleEditor createDummyRuleEditor(String ruleTypeId) {
242         RuleEditor ruleEditor = new RuleEditor();
243         ruleEditor.setDummy(true);
244         ruleEditor.setTypeId(ruleTypeId);
245         return ruleEditor;
246     }
247 
248     protected List<RuleEditor> getRuleEditorsFromTree(AgendaItemDefinition agendaItem, boolean initProps) {
249 
250         List<RuleEditor> rules = new ArrayList<RuleEditor>();
251         if (agendaItem.getRule() != null) {
252             RuleEditor ruleEditor = new RuleEditor(agendaItem.getRule());
253             if (initProps) {
254                 this.initPropositionEditor(ruleEditor.getPropositionEditor());
255                 ruleEditor.setViewTree(this.getViewTreeBuilder().buildTree(ruleEditor));
256             }
257             rules.add(ruleEditor);
258         }
259 
260         if (agendaItem.getWhenTrue() != null) {
261             rules.addAll(getRuleEditorsFromTree(agendaItem.getWhenTrue(), initProps));
262         }
263 
264         return rules;
265     }
266 
267     /**
268      * Override this method to return the reference object id of the parent object.
269      *
270      * @param parentRefObjectId
271      * @return
272      */
273     @Override
274     public List<ReferenceObjectBinding> getParentRefOjbects(String parentRefObjectId) {
275         return null;
276     }
277 
278     protected RuleViewTreeBuilder getViewTreeBuilder() {
279         return new RuleViewTreeBuilder();
280     }
281 
282     /**
283      * Setup a map with all the type information required to build an agenda management page.
284      *
285      * @return
286      */
287     protected List<AgendaTypeInfo> getTypeRelationships() {
288         List<AgendaTypeInfo> agendaTypeInfos = new ArrayList<AgendaTypeInfo>();
289 
290         // Get Instruction Usage Id
291         String instructionUsageId = getRuleManagementService().getNaturalLanguageUsageByNameAndNamespace(KSKRMSServiceConstants.KRMS_NL_TYPE_INSTRUCTION,
292                 StudentIdentityConstants.KS_NAMESPACE_CD).getId();
293 
294         // Get Description Usage Id
295         String descriptionUsageId = getRuleManagementService().getNaturalLanguageUsageByNameAndNamespace(KSKRMSServiceConstants.KRMS_NL_TYPE_DESCRIPTION,
296                 StudentIdentityConstants.KS_NAMESPACE_CD).getId();
297 
298         // Get the super type.
299         KrmsTypeDefinition requisitesType = this.getKrmsTypeRepositoryService().getTypeByName(StudentIdentityConstants.KS_NAMESPACE_CD, this.getViewTypeName());
300 
301         // Get all agenda types linked to super type.
302         List<TypeTypeRelation> agendaRelationships = this.getSortedTypeRelationshipsForTypeId(requisitesType.getId());
303         for (TypeTypeRelation agendaRelationship : agendaRelationships) {
304             AgendaTypeInfo agendaTypeInfo = new AgendaTypeInfo();
305             agendaTypeInfo.setId(agendaRelationship.getToTypeId());
306             KrmsTypeDefinition agendaType = this.getKrmsTypeRepositoryService().getTypeById(agendaTypeInfo.getId());
307             agendaTypeInfo.setType(agendaType.getName());
308             agendaTypeInfo.setDescription(this.getDescriptionForTypeAndUsage(agendaRelationship.getToTypeId(), descriptionUsageId));
309 
310             List<RuleTypeInfo> ruleTypes = new ArrayList<RuleTypeInfo>();
311             List<TypeTypeRelation> sortedRuleRelationships = this.getSortedTypeRelationshipsForTypeId(agendaRelationship.getToTypeId());
312             for (TypeTypeRelation ruleRelationship : sortedRuleRelationships) {
313                 RuleTypeInfo ruleTypeInfo = new RuleTypeInfo();
314                 ruleTypeInfo.setId(ruleRelationship.getToTypeId());
315                 KrmsTypeDefinition ruleType = this.getKrmsTypeRepositoryService().getTypeById(ruleTypeInfo.getId());
316                 ruleTypeInfo.setType(ruleType.getName());
317                 ruleTypeInfo.setDescription(this.getDescriptionForTypeAndUsage(ruleRelationship.getToTypeId(), descriptionUsageId));
318                 if (ruleTypeInfo.getDescription().isEmpty()) {
319                     ruleTypeInfo.setDescription("Description is unset rule type");
320                 }
321                 ruleTypeInfo.setInstruction(this.getDescriptionForTypeAndUsage(ruleRelationship.getToTypeId(), instructionUsageId));
322                 if (ruleTypeInfo.getInstruction().isEmpty()) {
323                     ruleTypeInfo.setInstruction("Instruction is unset for rule type");
324                 }
325                 // Add rule types to list.
326                 ruleTypes.add(ruleTypeInfo);
327             }
328             agendaTypeInfo.setRuleTypes(ruleTypes);
329             agendaTypeInfos.add(agendaTypeInfo);
330         }
331 
332         return agendaTypeInfos;
333     }
334 
335     private List<TypeTypeRelation> getSortedTypeRelationshipsForTypeId(String typeId){
336         // Get all rule types for each agenda type
337         List<TypeTypeRelation> relationships = new ArrayList<TypeTypeRelation>();
338         relationships.addAll(this.getKrmsTypeRepositoryService().findTypeTypeRelationsByFromType(typeId));
339 
340         // order rules
341         Collections.sort(relationships, new Comparator<TypeTypeRelation>() {
342             @Override
343             public int compare(TypeTypeRelation typeTypeRelation1, TypeTypeRelation typeTypeRelation2) {
344                 return typeTypeRelation1.getSequenceNumber().compareTo(typeTypeRelation2.getSequenceNumber());
345             }
346         });
347         return relationships;
348     }
349 
350     private String getDescriptionForTypeAndUsage(String typeId, String usageId) {
351         NaturalLanguageTemplate template = null;
352         try {
353             template = getRuleManagementService().findNaturalLanguageTemplateByLanguageCodeTypeIdAndNluId("en", typeId, usageId);
354             return template.getTemplate();
355         } catch (Exception e) {
356             return StringUtils.EMPTY;
357         }
358     }
359 
360     /**
361      * {@inheritDoc}
362      */
363     @Override
364     public void processAfterNew(MaintenanceDocument document, Map<String, String[]> requestParameters) {
365         super.processAfterNew(document, requestParameters);
366         document.getDocumentHeader().setDocumentDescription(NEW_AGENDA_EDITOR_DOCUMENT_TEXT);
367     }
368 
369     @Override
370     public void processAfterEdit(MaintenanceDocument document, Map<String, String[]> requestParameters) {
371         super.processAfterEdit(document, requestParameters);
372         document.getDocumentHeader().setDocumentDescription("Modify Agenda Editor Document");
373     }
374 
375     @Override
376     public void saveDataObject() {
377         RuleManager ruleWrapper = (RuleManager) getDataObject();
378 
379         for (AgendaEditor agenda : ruleWrapper.getAgendas()) {
380 
381             //Check if this agenda has anything to save
382             if (agenda.isDummyAgenda()) {
383                 continue;
384             }
385 
386             //Set the agenda name.
387             agenda.setName(ruleWrapper.getRefObjectId() + ":" + agenda.getAgendaTypeInfo().getId() + ":1");
388 
389             //Retrieve the context and set the id on the agenda.
390             if (agenda.getContextId() == null) {
391                 ContextDefinition context = this.getRuleManagementService().getContextByNameAndNamespace("Course Requirements", ruleWrapper.getNamespace());
392                 agenda.setContextId(context.getId());
393             }
394 
395             //Create or update the agenda.
396             if (agenda.getId() == null) {
397 
398                 //Check if someone else has not created an agenda while this one was created.
399                 if(this.getRuleManagementService().getAgendaByNameAndContextId(agenda.getName(), agenda.getContextId())!=null){
400                     throw new KRMSOptimisticLockingException();
401                 }
402 
403                 AgendaDefinition.Builder agendaBldr = AgendaDefinition.Builder.create(agenda);
404                 AgendaDefinition agendaDfn = this.getRuleManagementService().createAgenda(agendaBldr.build());
405 
406                 //Set the id and versionnumber for a possible update.
407                 agenda.setId(agendaDfn.getId());
408                 agenda.setVersionNumber(agendaDfn.getVersionNumber());
409                 agenda.setFirstItemId(agendaDfn.getFirstItemId());
410 
411                 //Create the reference object binding only on create agenda, no need to update.
412                 ReferenceObjectBinding.Builder refBuilder = ReferenceObjectBinding.Builder.create("Agenda",
413                         agendaDfn.getId(), ruleWrapper.getNamespace(), ruleWrapper.getRefDiscriminatorType(), ruleWrapper.getRefObjectId());
414                 this.getRuleManagementService().createReferenceObjectBinding(refBuilder.build());
415             }
416 
417             //Update the root item.
418             try {
419 
420                 //Set the first agenda item id and save the agenda items
421                 AgendaItemDefinition firstItem = maintainAgendaItems(agenda, ruleWrapper.getRefObjectId() + ":", ruleWrapper.getNamespace());
422 
423                 //If no more rules linked to agenda, delete it.
424                 if (firstItem.getRule() == null) {
425                     List<ReferenceObjectBinding> refObjectsBindings = this.getRuleManagementService().findReferenceObjectBindingsByReferenceObject(ruleWrapper.getRefDiscriminatorType(), ruleWrapper.getRefObjectId());
426                     for (ReferenceObjectBinding referenceObjectBinding : refObjectsBindings) {
427                         if (referenceObjectBinding.getKrmsObjectId().equals(agenda.getId())) {
428                             LOG.info("Deleting reference object binding for id: {}", referenceObjectBinding.getId());
429                             this.getRuleManagementService().deleteReferenceObjectBinding(referenceObjectBinding.getId());
430                         }
431                     }
432                     this.getRuleManagementService().deleteAgenda(agenda.getId());
433                 }
434 
435 
436             } catch (OjbOperationException e) {
437                 //OptimisticLockException
438                 if (e.getCause() instanceof OptimisticLockException) {
439                     throw new KRMSOptimisticLockingException("RuleEditorMaintainableImpl Optimistic Lock exception",e);
440                 } else {
441                     throw e;
442                 }
443             }
444 
445         }
446 
447     }
448 
449     public AgendaItemDefinition maintainAgendaItems(AgendaEditor agenda, String namePrefix, String nameSpace) {
450 
451         Queue<RuleDefinition.Builder> rules = new LinkedList<RuleDefinition.Builder>();
452         for (RuleEditor rule : agenda.getRuleEditors().values()) {
453             if (!rule.isDummy()) {
454                 rules.add(this.finRule(rule, namePrefix, nameSpace));
455             }
456         }
457 
458         AgendaItemDefinition.Builder rootItemBuilder = manageFirstItem(agenda);
459 
460         AgendaItemDefinition.Builder itemToDelete = null;
461         AgendaItemDefinition.Builder itemBuilder = rootItemBuilder;
462         while (rules.peek() != null) {
463             itemBuilder.setRule(rules.poll());
464             itemBuilder.setRuleId(itemBuilder.getRule().getId());
465             if (rules.peek() != null) {
466                 if(itemBuilder.getWhenTrue()==null){
467                     itemBuilder.setWhenTrue(AgendaItemDefinition.Builder.create(null, agenda.getId()));
468                 }
469                 itemBuilder = itemBuilder.getWhenTrue();
470             } else {
471                 itemToDelete = itemBuilder.getWhenTrue();
472                 itemBuilder.setWhenTrue(null);
473             }
474         }
475 
476         return manageAgendaItems(agenda, rootItemBuilder, itemToDelete);
477     }
478 
479     protected AgendaItemDefinition.Builder manageFirstItem(AgendaEditor agenda) {
480         AgendaItemDefinition.Builder rootItemBuilder;
481         if(agenda.getFirstItemId()!=null) {
482             AgendaItemDefinition firstItem = this.getRuleManagementService().getAgendaItem(agenda.getFirstItemId());
483             rootItemBuilder = AgendaItemDefinition.Builder.create(firstItem);
484             rootItemBuilder.setRule(null);
485             rootItemBuilder.setRuleId(null);
486         } else {
487             rootItemBuilder = AgendaItemDefinition.Builder.create(null, agenda.getId());
488         }
489         return rootItemBuilder;
490     }
491 
492     protected AgendaItemDefinition manageAgendaItems(AgendaEditor agenda, AgendaItemDefinition.Builder rootItemBuilder, AgendaItemDefinition.Builder itemToDelete) {
493         //Update the root item.
494         AgendaItemDefinition agendaItem = rootItemBuilder.build();
495         try {
496             if(agendaItem.getId()==null){
497                 agendaItem = this.getRuleManagementService().createAgendaItem(agendaItem);
498                 agenda.setFirstItemId(agendaItem.getId());
499                 AgendaDefinition.Builder agendaBldr = AgendaDefinition.Builder.create(agenda);
500                 this.getRuleManagementService().updateAgenda(agendaBldr.build());
501             } else {
502                 this.getRuleManagementService().updateAgendaItem(agendaItem);
503             }
504 
505             //delete agendaitems not used.
506             if(itemToDelete!=null){
507                 this.deleteAgendaItems(itemToDelete.build());
508             }
509         } catch (OjbOperationException e) {
510             //OptimisticLockException
511             if (e.getCause() instanceof OptimisticLockException) {
512                 throw new KRMSOptimisticLockingException("Could not obtain OjbOperation ",e);
513             } else {
514                 throw e;
515             }
516         }
517 
518         //Delete orhpan rules
519         for (RuleEditor deletedRule : agenda.getDeletedRules()) {
520             this.getRuleManagementService().deleteRule(deletedRule.getId());
521         }
522         return agendaItem;
523     }
524 
525     public void deleteAgendaItems(AgendaItemDefinition agendaItem) {
526         if (agendaItem != null) {
527             //Update the agenda (hack so that it does not delete the rule.)
528             AgendaItemDefinition.Builder itemBuilder = AgendaItemDefinition.Builder.create(agendaItem.getId(), agendaItem.getAgendaId());
529             itemBuilder.setVersionNumber(agendaItem.getVersionNumber());
530             this.getRuleManagementService().updateAgendaItem(itemBuilder.build());
531 
532             //Delete the agenda item
533             this.getRuleManagementService().deleteAgendaItem(agendaItem.getId());
534             deleteAgendaItems(agendaItem.getWhenFalse());
535             deleteAgendaItems(agendaItem.getWhenTrue());
536             deleteAgendaItems(agendaItem.getAlways());
537         }
538     }
539 
540     public RuleDefinition.Builder finRule(RuleEditor rule, String rulePrefix, String namespace) {
541         // handle saving new parameterized terms
542         if (rule.getPropositionEditor() != null) {
543             this.onSubmit(rule.getPropositionEditor());
544         }
545 
546         if (rule.getNamespace() == null) {
547             rule.setNamespace(namespace);
548         }
549         rule.setName(rulePrefix + rule.getRuleTypeInfo().getId() + ":1");
550 
551         //Check if someone else has not created a rule while this one was created.
552         if(rule.getId()==null){
553             if(this.getRuleManagementService().getRuleByNameAndNamespace(rule.getName(), rule.getNamespace())!=null){
554                 throw new KRMSOptimisticLockingException();
555             }
556         }
557 
558         return RuleDefinition.Builder.create(rule);
559     }
560 
561     public void onSubmit(PropositionEditor propositionEditor) {
562         if (PropositionType.SIMPLE.getCode().equalsIgnoreCase(propositionEditor.getPropositionTypeCode())) {
563 
564             //Call onsubmit on the associated builder.
565             ComponentBuilder builder = this.getTemplateRegistry().getComponentBuilderForType(propositionEditor.getType());
566             if (builder != null) {
567                 builder.onSubmit(propositionEditor);
568             }
569 
570         } else {
571 
572             //If not a simple node, recursively finalize the child proposition editors.
573             for (PropositionEditor child : propositionEditor.getCompoundEditors()) {
574                 onSubmit(child);
575             }
576 
577         }
578     }
579 
580     public void initPropositionEditor(PropositionEditor propositionEditor) {
581         if (propositionEditor == null) {
582             return;
583         }
584 
585         if (PropositionType.SIMPLE.getCode().equalsIgnoreCase(propositionEditor.getPropositionTypeCode())) {
586 
587             if (propositionEditor.getType() == null) {
588                 KrmsTypeDefinition type = this.getKrmsTypeRepositoryService().getTypeById(propositionEditor.getTypeId());
589                 propositionEditor.setType(type.getName());
590             }
591 
592             Map<String, String> termParameters = this.getTermParameters(propositionEditor);
593             ComponentBuilder builder = this.getTemplateRegistry().getComponentBuilderForType(propositionEditor.getType());
594             if (builder != null) {
595                 builder.resolveTermParameters(propositionEditor, termParameters);
596             }
597         } else {
598             for (PropositionEditor child : propositionEditor.getCompoundEditors()) {
599                 initPropositionEditor(child);
600             }
601 
602         }
603     }
604 
605     public Map<String, String> getTermParameters(PropositionEditor proposition) {
606 
607         Map<String, String> termParameters = new HashMap<String, String>();
608         if (proposition.getTerm() == null) {
609             PropositionParameterEditor termParameter = PropositionTreeUtil.getTermParameter(proposition.getParameters());
610             if (termParameter != null) {
611 
612                 if (termParameter.getTermValue() == null) {
613                     proposition.setTerm(new TermEditor());
614                 } else {
615                     proposition.setTerm(new TermEditor(termParameter.getTermValue()));
616                 }
617 
618             } else {
619                 return termParameters;
620             }
621         }
622 
623         for (TermParameterEditor parameter : proposition.getTerm().getEditorParameters()) {
624             termParameters.put(parameter.getName(), parameter.getValue());
625         }
626 
627         return termParameters;
628     }
629 
630     /**
631      * In the case of edit maintenance adds a new blank line to the old side
632      * <p/>
633      *
634      * @see org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl#processAfterAddLine(org.kuali.rice.krad.uif.view.ViewModel, Object, String, String, boolean)
635      */
636     @Override
637     public void processAfterAddLine(ViewModel viewModel, Object addLine, String collectionId, String collectionPath, boolean isValidLine) {
638         // Check for maintenance documents in edit but exclude notes
639         if (viewModel instanceof MaintenanceDocumentForm && KRADConstants.MAINTENANCE_EDIT_ACTION.equals(((MaintenanceDocumentForm) viewModel).getMaintenanceAction()) && !(addLine instanceof Note)) {
640 
641             // Figure out which rule is being edited
642             RuleEditor rule = getRuleEditor(viewModel);
643             // Figure out which proposition is being edited
644             Tree<RuleEditorTreeNode, String> propositionTree = rule.getEditTree();
645             Node<RuleEditorTreeNode, String> editedPropositionNode = PropositionTreeUtil.findEditedProposition(propositionTree.getRootElement());
646 
647             BindingInfo bindingInfo = (BindingInfo) viewModel.getViewPostMetadata().getComponentPostData(collectionId,
648                     UifConstants.PostMetadata.BINDING_INFO);
649             // get the old object's collection
650             Collection<Object> oldCollection = ObjectPropertyUtils
651                     .getPropertyValue(editedPropositionNode.getData(),
652                             bindingInfo.getBindingName());
653 
654             Class<?> collectionObjectClass = (Class<?>) viewModel.getViewPostMetadata().getComponentPostData(collectionId,
655                     UifConstants.PostMetadata.COLL_OBJECT_CLASS);
656             try {
657                 Object blankLine = collectionObjectClass.newInstance();
658                 //Add a blank line to the top of the collection
659                 if (oldCollection instanceof List) {
660                     ((List) oldCollection).add(0, blankLine);
661                 } else {
662                     oldCollection.add(blankLine);
663                 }
664             } catch (Exception e) {
665                 throw new RuntimeException("Unable to create new line instance for old maintenance object", e);
666             }
667         }
668     }
669 
670     public RuleManagementService getRuleManagementService() {
671         if (ruleManagementService == null) {
672             ruleManagementService = (RuleManagementService) GlobalResourceLoader.getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "ruleManagementService"));
673         }
674         return ruleManagementService;
675     }
676 
677     public KrmsTypeRepositoryService getKrmsTypeRepositoryService() {
678         if (krmsTypeRepositoryService == null) {
679             krmsTypeRepositoryService = (KrmsTypeRepositoryService) GlobalResourceLoader.getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "krmsTypeRepositoryService"));
680         }
681         return krmsTypeRepositoryService;
682     }
683 
684     public TermRepositoryService getTermRepositoryService() {
685         if (termRepositoryService == null) {
686             termRepositoryService = (TermRepositoryService) GlobalResourceLoader.getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "termRepositoryService"));
687         }
688         return termRepositoryService;
689     }
690 
691     private TemplateRegistry getTemplateRegistry() {
692         if (templateRegistry == null) {
693             templateRegistry = (TemplateRegistry) GlobalResourceLoader.getService(new QName("http://student.kuali.org/wsdl/templateResolverService", "templateResolverService"));
694         }
695         return templateRegistry;
696     }
697 }