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