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.Tree;
21  import org.kuali.rice.krad.uif.UifConstants;
22  import org.kuali.rice.krad.uif.component.Component;
23  import org.kuali.rice.krad.uif.container.Container;
24  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
25  import org.kuali.rice.krad.uif.util.ComponentFactory;
26  import org.kuali.rice.krad.uif.util.ComponentUtils;
27  import org.kuali.rice.krad.uif.view.View;
28  import org.kuali.rice.krad.uif.view.ViewModel;
29  import org.kuali.rice.krad.util.BeanPropertyComparator;
30  import org.kuali.rice.krad.util.GlobalVariables;
31  import org.kuali.rice.krad.util.ObjectUtils;
32  import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
33  import org.kuali.rice.krms.api.KrmsConstants;
34  import org.kuali.rice.krms.api.repository.LogicalOperator;
35  import org.kuali.rice.krms.api.repository.RuleManagementService;
36  import org.kuali.rice.krms.api.repository.proposition.PropositionType;
37  import org.kuali.rice.krms.api.repository.term.TermDefinition;
38  import org.kuali.rice.krms.api.repository.term.TermRepositoryService;
39  import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
40  import org.kuali.rice.krms.api.repository.type.KrmsTypeRepositoryService;
41  import org.kuali.rice.krms.builder.ComponentBuilder;
42  import org.kuali.rice.krms.dto.PropositionEditor;
43  import org.kuali.rice.krms.dto.PropositionParameterEditor;
44  import org.kuali.rice.krms.dto.RuleEditor;
45  import org.kuali.rice.krms.dto.RuleManagementWrapper;
46  import org.kuali.rice.krms.dto.RuleManager;
47  import org.kuali.rice.krms.dto.TermEditor;
48  import org.kuali.rice.krms.dto.TermParameterEditor;
49  import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
50  import org.kuali.rice.krms.service.TemplateRegistry;
51  import org.kuali.rice.krms.tree.RuleViewTreeBuilder;
52  import org.kuali.rice.krms.tree.node.CompareTreeNode;
53  import org.kuali.rice.krms.tree.RuleCompareTreeBuilder;
54  import org.kuali.rice.krms.tree.RuleEditTreeBuilder;
55  import org.kuali.rice.krms.tree.RulePreviewTreeBuilder;
56  import org.kuali.rice.krms.util.KRMSConstants;
57  import org.kuali.rice.krms.util.NaturalLanguageHelper;
58  import org.kuali.rice.krms.util.PropositionTreeUtil;
59  import org.kuali.rice.krms.dto.TemplateInfo;
60  import org.kuali.rice.krms.service.RuleViewHelperService;
61  import org.kuali.student.common.uif.service.impl.KSViewHelperServiceImpl;
62  import org.kuali.student.r2.core.constants.KSKRMSServiceConstants;
63  import org.springframework.beans.BeanUtils;
64  
65  import javax.xml.namespace.QName;
66  import java.util.ArrayList;
67  import java.util.Arrays;
68  import java.util.HashMap;
69  import java.util.List;
70  import java.util.Map;
71  
72  /**
73   * Helpers Service for the Rule Pages.
74   *
75   * @author Kuali Student Team
76   */
77  public class RuleViewHelperServiceImpl extends KSViewHelperServiceImpl implements RuleViewHelperService {
78  
79      private transient RuleManagementService ruleManagementService;
80      private transient KrmsTypeRepositoryService krmsTypeRepositoryService;
81      private transient TermRepositoryService termRepositoryService;
82  
83      private RuleCompareTreeBuilder compareTreeBuilder;
84      private RuleEditTreeBuilder editTreeBuilder;
85      private RulePreviewTreeBuilder previewTreeBuilder;
86      private RuleViewTreeBuilder viewTreeBuilder;
87  
88      private NaturalLanguageHelper naturalLanguageHelper;
89  
90      private static TemplateRegistry templateRegistry;
91  
92      protected RuleEditor getRuleEditor(Object model) {
93          if (model instanceof MaintenanceDocumentForm) {
94              MaintenanceDocumentForm maintenanceDocumentForm = (MaintenanceDocumentForm) model;
95              Object dataObject = maintenanceDocumentForm.getDocument().getNewMaintainableObject().getDataObject();
96  
97              if (dataObject instanceof RuleEditor) {
98                  return (RuleEditor) dataObject;
99              } else if (dataObject instanceof RuleManager) {
100                 RuleManager wrapper = (RuleManager) dataObject;
101                 return wrapper.getRuleEditor();
102             }
103         }
104         return null;
105     }
106 
107     @Override
108     public TemplateInfo getTemplateForType(String type) {
109         return this.getTemplateRegistry().getTemplateForType(type);
110     }
111 
112     @Override
113     public void addCustomContainerComponents(ViewModel model, Container container) {
114         if (KRMSConstants.KRMS_PROPOSITION_DETAILSECTION_ID.equals(container.getId())) {
115             customizePropositionEditSection(model, container);
116         }
117     }
118 
119     private void customizePropositionEditSection(Object model, Container container) {
120         //Retrieve the current editing proposition if exists.
121         MaintenanceDocumentForm maintenanceDocumentForm = (MaintenanceDocumentForm) model;
122         Object dataObject = maintenanceDocumentForm.getDocument().getNewMaintainableObject().getDataObject();
123 
124         RuleEditor ruleEditor = ((RuleManager) dataObject).getRuleEditor();
125         PropositionEditor propEditor = PropositionTreeUtil.getProposition(ruleEditor);
126 
127         List<Component> components = new ArrayList<Component>();
128         if (propEditor != null) {
129             //Retrieve the name of the xml component to display for the proposition type.
130             TemplateInfo template = this.getTemplateForType(propEditor.getType());
131             if (template != null) {
132 
133                 //Only set the objectpath on ajax component refresh.
134                 String objectPath = null;
135                 if ((maintenanceDocumentForm.getUpdateComponentId() != null) &&
136                         maintenanceDocumentForm.getUpdateComponentId().startsWith(container.getId())) {
137                     objectPath = ViewLifecycle.getView().getDefaultBindingObjectPath();
138                 }
139 
140                 //Add custom component
141                 if (template.getComponentId() != null) {
142                     components.add(createComponent(objectPath, propEditor.getBindingPath(), template.getComponentId()));
143                 }
144 
145                 //Add constant component.
146                 if (template.getConstantComponentId() != null) {
147                     components.add(createComponent(objectPath, propEditor.getBindingPath(), template.getConstantComponentId()));
148                 }
149             }
150         }
151 
152         //Do not display if there are no components.
153         if (components.size() == 0) {
154             container.getHeader().setRender(false);
155         }
156 
157         container.setItems(components);
158     }
159 
160     private Component createComponent(String objectPath, String bindingPath, String componentId) {
161         Component component = ComponentFactory.getNewComponentInstance(componentId);
162         if (objectPath != null) {
163             String nodePath = objectPath + "." + bindingPath;
164             ComponentUtils.pushObjectToContext(component, UifConstants.ContextVariableNames.NODE_PATH, nodePath);
165         }
166         return component;
167     }
168 
169     /**
170      * Validate the rule.
171      *
172      * @param rule
173      * @return True if valid, false if not.
174      */
175     @Override
176     public Boolean validateRule(RuleEditor rule) {
177 
178         boolean hasError = false;
179 
180         //Return with error message if user is currently editing a proposition.
181         PropositionEditor proposition = PropositionTreeUtil.getProposition(rule);
182         if ((proposition != null) && (proposition.isEditMode())) {
183             GlobalVariables.getMessageMap().putErrorForSectionId(KRMSConstants.KRMS_PROPOSITION_DETAILSECTION_ID, KRMSConstants.KRMS_MSG_ERROR_RULE_PREVIEW);
184             hasError = true;
185         }
186 
187         return hasError;
188     }
189 
190     /**
191      * Validate the proposition.
192      *
193      * @param proposition
194      * @return True if valid, false if not.
195      */
196     @Override
197     public Boolean validateProposition(PropositionEditor proposition) {
198 
199         // Retrieve the builder for the current proposition type.
200         ComponentBuilder builder = this.getTemplateRegistry().getComponentBuilderForType(proposition.getType());
201         if (builder != null) {
202             // Execute validation
203             builder.validate(proposition);
204         }
205 
206         if (GlobalVariables.getMessageMap().getErrorMessages().isEmpty()) {
207             return Boolean.TRUE;
208         }
209 
210         return Boolean.FALSE;
211     }
212 
213     /**
214      * Initializes the proposition, populating the type and terms.
215      *
216      * @param propositionEditor
217      */
218     @Override
219     public void initPropositionEditor(PropositionEditor propositionEditor) {
220         if (PropositionType.SIMPLE.getCode().equalsIgnoreCase(propositionEditor.getPropositionTypeCode())) {
221 
222             if (propositionEditor.getType() == null) {
223                 KrmsTypeDefinition type = this.getKrmsTypeRepositoryService().getTypeById(propositionEditor.getTypeId());
224                 propositionEditor.setType(type.getName());
225             }
226 
227             ComponentBuilder builder = this.getTemplateRegistry().getComponentBuilderForType(propositionEditor.getType());
228             if (builder != null) {
229                 Map<String, String> termParameters = this.getTermParameters(propositionEditor);
230                 builder.resolveTermParameters(propositionEditor, termParameters);
231             }
232         } else {
233             for (PropositionEditor child : propositionEditor.getCompoundEditors()) {
234                 initPropositionEditor(child);
235             }
236 
237         }
238     }
239 
240     /**
241      * Finalizes the proposition, setting the type and terms.
242      *
243      * @param propositionEditor
244      */
245     @Override
246     public void finPropositionEditor(PropositionEditor propositionEditor) {
247         if (PropositionType.SIMPLE.getCode().equalsIgnoreCase(propositionEditor.getPropositionTypeCode())) {
248 
249             //Set the default operation and value
250             TemplateInfo template = this.getTemplateRegistry().getTemplateForType(propositionEditor.getType());
251             PropositionTreeUtil.getOperatorParameter(propositionEditor.getParameters()).setValue(template.getOperator());
252 
253             if (!"n".equals(template.getValue())) {
254                 PropositionTreeUtil.getConstantParameter(propositionEditor.getParameters()).setValue(template.getValue());
255             }
256 
257             if (propositionEditor.getTerm() != null) {
258                 TermDefinition.Builder termBuilder = TermDefinition.Builder.create(propositionEditor.getTerm());
259                 PropositionTreeUtil.getTermParameter(propositionEditor.getParameters()).setTermValue(termBuilder.build());
260             }
261 
262         } else {
263 
264             //If not a simple node, recursively finalize the child proposition editors.
265             for (PropositionEditor child : propositionEditor.getCompoundEditors()) {
266                 finPropositionEditor(child);
267             }
268 
269         }
270     }
271 
272     /**
273      * Create TermEditor from the TermDefinition objects to be used in the ui and return a map of
274      * the key and values of the term parameters.
275      *
276      * @param proposition
277      * @return
278      */
279     @Override
280     public Map<String, String> getTermParameters(PropositionEditor proposition) {
281 
282         Map<String, String> termParameters = new HashMap<String, String>();
283         if (proposition.getTerm() == null) {
284             PropositionParameterEditor termParameter = PropositionTreeUtil.getTermParameter(proposition.getParameters());
285             if (termParameter != null) {
286                 proposition.setTerm(new TermEditor(termParameter.getTermValue()));
287             } else {
288                 return termParameters;
289             }
290         }
291 
292         for (TermParameterEditor parameter : proposition.getTerm().getEditorParameters()) {
293             termParameters.put(parameter.getName(), parameter.getValue());
294         }
295 
296         return termParameters;
297     }
298 
299     /**
300      * Clear the description and natural language on proposition editors.
301      *
302      * @param prop
303      * @return
304      */
305     @Override
306     public void resetDescription(PropositionEditor prop) {
307 
308         //If proposition type is null, set description and term null
309         if (prop.getType() == null) {
310             prop.setDescription(StringUtils.EMPTY);
311             prop.setTerm(null);
312             prop.getNaturalLanguage().clear();
313             return;
314         }
315 
316         //Build the new termParamters with the matching component builder.
317         if (PropositionType.SIMPLE.getCode().equalsIgnoreCase(prop.getPropositionTypeCode())) {
318             Map<String, String> termParameters = null;
319             ComponentBuilder builder = this.getTemplateRegistry().getComponentBuilderForType(prop.getType());
320             if (builder != null) {
321                 termParameters = builder.buildTermParameters(prop);
322             }
323 
324             List<TermParameterEditor> parameters = new ArrayList<TermParameterEditor>();
325             if (termParameters != null) {
326                 for (Map.Entry<String, String> entry : termParameters.entrySet()) {
327 
328                     TermParameterEditor parameterEditor = null;
329                     if (prop.getTerm().getParameters() != null) {
330                         for (TermParameterEditor parameter : prop.getTerm().getEditorParameters()) {
331 
332                             if (entry.getKey().equals(parameter.getName())) {
333                                 parameterEditor = parameter;
334                                 parameterEditor.setValue(entry.getValue());
335                                 break;
336                             }
337                         }
338                     }
339 
340                     //Create a new parameter if not exist.
341                     if (parameterEditor == null) {
342                         parameterEditor = new TermParameterEditor();
343                         parameterEditor.setName(entry.getKey());
344                         parameterEditor.setValue(entry.getValue());
345                     }
346                     parameters.add(parameterEditor);
347                 }
348             }
349 
350             prop.getTerm().setParameters(parameters);
351 
352             //Set the term specification if it doesn't exist.
353             if (prop.getTerm().getSpecification() == null) {
354                 String termSpecName = this.getTemplateRegistry().getTermSpecNameForType(prop.getType());
355                 prop.getTerm().setSpecification(getTermRepositoryService().getTermSpecificationByNameAndNamespace(termSpecName, KSKRMSServiceConstants.NAMESPACE_CODE));
356             }
357 
358         } else {
359             prop.setTerm(null);
360         }
361 
362         //Refresh the natural language.
363         prop.getNaturalLanguage().clear();
364     }
365 
366     @Override
367     public void buildActions(RuleEditor ruleEditor) {
368     }
369 
370     public void configurePropositionForType(PropositionEditor proposition) {
371 
372         if (proposition != null) {
373 
374             if (PropositionType.COMPOUND.getCode().equalsIgnoreCase(proposition.getPropositionTypeCode())) {
375                 return;
376             }
377 
378             String propositionTypeId = proposition.getTypeId();
379             if ((propositionTypeId == null) || (propositionTypeId.isEmpty())) {
380                 proposition.setType(null);
381                 return;
382             }
383 
384             KrmsTypeDefinition type = KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService().getTypeById(propositionTypeId);
385             if (type != null) {
386                 proposition.setType(type.getName());
387             }
388 
389             if (proposition.getTerm() == null) {
390                 proposition.setTerm(new TermEditor());
391             }
392 
393             String termSpecName = this.getTemplateRegistry().getTermSpecNameForType(proposition.getType());
394             proposition.getTerm().setSpecification(getTermRepositoryService().getTermSpecificationByNameAndNamespace(termSpecName, KSKRMSServiceConstants.NAMESPACE_CODE));
395 
396             ComponentBuilder builder = this.getTemplateRegistry().getComponentBuilderForType(proposition.getType());
397             if (builder != null) {
398                 builder.initialize(proposition);
399             }
400 
401         }
402     }
403 
404     @Override
405     public void refreshInitTrees(RuleEditor rule) {
406 
407         if (rule == null) {
408             return;
409         }
410 
411         //Rebuild the trees
412         rule.setEditTree(this.getEditTreeBuilder().buildTree(rule));
413         rule.setPreviewTree(this.getPreviewTreeBuilder().buildTree(rule));
414     }
415 
416     /**
417      * Rebuild the tree used for the view only trees.
418      *
419      * @param rule
420      */
421     @Override
422     public void refreshViewTree(RuleEditor rule) {
423 
424         if (rule == null) {
425             return;
426         }
427 
428         //Rebuild the trees
429         rule.setViewTree(this.getViewTreeBuilder().buildTree(rule));
430 
431     }
432 
433     @Override
434     public Tree<CompareTreeNode, String> buildCompareTree(RuleEditor original, RuleEditor compare) {
435 
436         //Build the Tree
437         return this.getCompareTreeBuilder().buildTree(original, compare);
438 
439     }
440 
441     @Override
442     public Tree<CompareTreeNode, String> buildMultiViewTree(RuleEditor original, RuleEditor compare) {
443 
444         //Build the Tree
445         return this.getCompareTreeBuilder().buildTree(original, compare);
446 
447     }
448 
449     /**
450      * Compare all the propositions in a rule tree with a parent rule tree. Returns false if any proposition's type
451      * or term parameters are not the same.
452      * <p/>
453      * Apart from the type and termparameters, all other detail is derived from the typeid and therefore not included in
454      * the comparison.     *
455      *
456      * @param original
457      * @return boolean
458      * @throws Exception
459      */
460     @Override
461     public Boolean compareRules(RuleEditor original) {
462 
463         //Do null check on propositions.
464         RuleEditor compareEditor = original.getParent();
465         if ((compareEditor == null) || (compareEditor.getProposition() == null)) {
466             if (original.getProposition() != null) {
467                 return false; //if compare is null and original is not, they differ.
468             } else {
469                 return true; //both of them are null.
470             }
471         } else if (original.getProposition() == null) {
472             return false;
473         }
474 
475         //Compare Root Proposition Type and if the same test recursively
476         if (original.getProposition().getTypeId().equals(compareEditor.getProposition().getTypeId())) {
477             return compareProposition(original.getPropositionEditor(), compareEditor.getPropositionEditor());
478         } else {
479             return false;
480         }
481     }
482 
483     /**
484      * Method to handle the proposition comparison recursively.
485      *
486      * @param original
487      * @param compare
488      * @return true if proposition are the same.
489      */
490     @Override
491     public Boolean compareProposition(PropositionEditor original, PropositionEditor compare) {
492         //Compare the proposition
493         BeanPropertyComparator propositionComparator = new BeanPropertyComparator(Arrays.asList("typeId"));
494         if (propositionComparator.compare(original, compare) != 0) {
495             return false;
496         }
497 
498         //Compare the term values
499         if (PropositionType.SIMPLE.getCode().equalsIgnoreCase(original.getPropositionTypeCode())) {
500             TermEditor term = new TermEditor(PropositionTreeUtil.getTermParameter(compare.getParameters()).getTermValue());
501             if (!compareTerm(original.getTerm().getEditorParameters(), term.getEditorParameters())) {
502                 return false;
503             }
504         }
505 
506         //Compare the compound propositions.
507         return compareCompoundProposition(original.getCompoundEditors(), compare.getCompoundEditors());
508     }
509 
510     /**
511      * Compare all the keys and values of the term parameter. Returns false if any of the keys (names) or
512      * values of the term paramters is not the same.
513      *
514      * @param original list of term parameters for current term
515      * @param compare  list of term paramters to compare with.
516      * @return true if all names and values are the same.
517      */
518     @Override
519     public Boolean compareTerm(List<TermParameterEditor> original, List<TermParameterEditor> compare) {
520 
521         //If the sizes doesn't match, they are not same.
522         int originalSize = original == null ? 0 : original.size();
523         if (originalSize != (compare == null ? 0 : compare.size())) {
524             return false;
525         } else if (originalSize > 0) {
526 
527             //Compare the compound propositions.
528             BeanPropertyComparator termComparator = new BeanPropertyComparator(Arrays.asList("name", "value"));
529             for (int index = 0; index < originalSize; index++) {
530                 if (termComparator.compare(original.get(index), compare.get(index)) != 0) {
531                     return false;
532                 }
533             }
534         }
535 
536         return true;
537 
538     }
539 
540     /**
541      * Recursively compare child propositions.
542      *
543      * @param original
544      * @param compare
545      * @return
546      */
547     @Override
548     public Boolean compareCompoundProposition(List<PropositionEditor> original, List<PropositionEditor> compare) {
549 
550         //If the sizes doesn't match, they are not same.
551         int originalSize = original == null ? 0 : original.size();
552         if (originalSize != (compare == null ? 0 : compare.size())) {
553             return false;
554         } else if (originalSize > 0) {
555 
556             //Compare the compound propositions.
557             for (int index = 0; index < originalSize; index++) {
558                 if (!compareProposition(original.get(index), compare.get(index))) {
559                     return false;
560                 }
561             }
562         }
563 
564         return true;
565     }
566 
567     /**
568      * Make a new copy of the current proposition including the compounds.
569      * <p/>
570      * The deepcopy is done to make sure that create a full copy and does not only copy the references.
571      *
572      * @param oldProposition
573      * @return
574      */
575     @Override
576     public PropositionEditor copyProposition(PropositionEditor oldProposition) {
577         try {
578             PropositionEditor newProposition = this.copyPropositionEditor(oldProposition);
579 
580             //Use a deepcopy to create new references to inner objects such as string.
581             return (PropositionEditor) ObjectUtils.deepCopy(newProposition);
582         } catch (Exception e) {
583             return null;
584         }
585     }
586 
587     /**
588      * Used when the user clicked the copy button. It creates a new copy of the proposition with all the related
589      * compound propositions.
590      * <p/>
591      * The compound propositions is handled recursively.
592      *
593      * @param oldProposition
594      * @return
595      */
596     protected PropositionEditor copyPropositionEditor(PropositionEditor oldProposition) {
597         PropositionEditor newProposition;
598         try {
599             newProposition = this.getPropositionEditorClass().newInstance();
600         } catch (Exception e) {
601             newProposition = new PropositionEditor();
602         }
603         BeanUtils.copyProperties(oldProposition, newProposition, new String[]{"key", "id", "term", "parameters", "versionNumber"});
604 
605         if (!oldProposition.getPropositionTypeCode().equals("C")) {
606             List<PropositionParameterEditor> propositionParameterEditors = new ArrayList<PropositionParameterEditor>();
607             for (PropositionParameterEditor parm : oldProposition.getParameters()) {
608                 PropositionParameterEditor newParm = new PropositionParameterEditor();
609                 BeanUtils.copyProperties(parm, newParm, new String[]{"termValue", "id", "versionNumber"});
610                 propositionParameterEditors.add(newParm);
611             }
612 
613             newProposition.setParameters(propositionParameterEditors);
614 
615             TermEditor termEditor = new TermEditor();
616             List<TermParameterEditor> termParameterEditors = new ArrayList<TermParameterEditor>();
617             if (oldProposition.getTerm() != null) {
618                 BeanUtils.copyProperties(oldProposition.getTerm(), termEditor, new String[]{"id", "versionNumber", "parameters"});
619                 for (TermParameterEditor termParm : oldProposition.getTerm().getEditorParameters()) {
620                     TermParameterEditor newTermParm = new TermParameterEditor();
621                     BeanUtils.copyProperties(termParm, newTermParm, new String[]{"id", "versionNumber"});
622                     termParameterEditors.add(newTermParm);
623                 }
624             }
625             termEditor.setParameters(termParameterEditors);
626 
627             newProposition.setTerm(termEditor);
628             this.resetDescription(newProposition);
629         }
630 
631         if (newProposition.getCompoundEditors() != null) {
632             List<PropositionEditor> props = new ArrayList<PropositionEditor>();
633             for (PropositionEditor prop : newProposition.getCompoundEditors()) {
634                 props.add(this.copyPropositionEditor(prop));
635             }
636             newProposition.setCompoundEditors(props);
637         }
638 
639 
640         return newProposition;
641     }
642 
643     @Override
644     public PropositionEditor createCompoundPropositionBoStub(PropositionEditor existing, boolean addNewChild) {
645         try {
646             PropositionEditor compound = PropositionTreeUtil.createCompoundPropositionBoStub(existing, addNewChild, this.getPropositionEditorClass());
647             this.setTypeForCompoundOpCode(compound, LogicalOperator.AND.getCode());
648             return compound;
649         } catch (Exception e) {
650             return null;
651         }
652     }
653 
654     @Override
655     public void setTypeForCompoundOpCode(PropositionEditor proposition, String compoundOpCode) {
656         //Return as quickly as possible for performance.
657         if (compoundOpCode.equals(proposition.getCompoundOpCode())) {
658             return;
659         }
660 
661         //Clear the natural language so the the tree builder can rebuild it.
662         proposition.getNaturalLanguage().clear();
663         proposition.setCompoundOpCode(compoundOpCode);
664     }
665 
666     /**
667      * Creates a new instance of a simple proposition.
668      *
669      * @param sibling
670      * @return
671      */
672     @Override
673     public PropositionEditor createSimplePropositionBoStub(PropositionEditor sibling) {
674         try {
675             return PropositionTreeUtil.createSimplePropositionBoStub(sibling, this.getPropositionEditorClass());
676         } catch (Exception e) {
677             return null;
678         }
679     }
680 
681     /**
682      * Override this method to return a different class type if you need to use a different propositoin editor class.
683      *
684      * @return
685      */
686     public Class<? extends PropositionEditor> getPropositionEditorClass() {
687         return PropositionEditor.class;
688     }
689 
690     protected RuleManagementService getRuleManagementService() {
691         if (ruleManagementService == null) {
692             ruleManagementService = (RuleManagementService) GlobalResourceLoader.getService(QName.valueOf("ruleManagementService"));
693         }
694         return ruleManagementService;
695     }
696 
697     protected RuleCompareTreeBuilder getCompareTreeBuilder() {
698         if (compareTreeBuilder == null) {
699             compareTreeBuilder = new RuleCompareTreeBuilder();
700         }
701         return compareTreeBuilder;
702     }
703 
704     protected RuleEditTreeBuilder getEditTreeBuilder() {
705         if (editTreeBuilder == null) {
706             editTreeBuilder = new RuleEditTreeBuilder();
707         }
708         return editTreeBuilder;
709     }
710 
711     protected RulePreviewTreeBuilder getPreviewTreeBuilder() {
712         if (previewTreeBuilder == null) {
713             previewTreeBuilder = new RulePreviewTreeBuilder();
714         }
715         return previewTreeBuilder;
716     }
717 
718     protected RuleViewTreeBuilder getViewTreeBuilder() {
719         if (viewTreeBuilder == null) {
720             viewTreeBuilder = new RuleViewTreeBuilder();
721         }
722         return viewTreeBuilder;
723     }
724 
725     protected NaturalLanguageHelper getNaturalLanguageHelper() {
726         if (naturalLanguageHelper == null) {
727             naturalLanguageHelper = new NaturalLanguageHelper();
728             naturalLanguageHelper.setRuleManagementService(this.getRuleManagementService());
729         }
730         return naturalLanguageHelper;
731     }
732 
733     protected TemplateRegistry getTemplateRegistry() {
734         if (templateRegistry == null) {
735             templateRegistry = (TemplateRegistry) GlobalResourceLoader.getService(new QName("http://student.kuali.org/wsdl/templateResolverService", "templateResolverService"));
736         }
737         return templateRegistry;
738     }
739 
740     protected KrmsTypeRepositoryService getKrmsTypeRepositoryService() {
741         if (krmsTypeRepositoryService == null) {
742             krmsTypeRepositoryService = (KrmsTypeRepositoryService) GlobalResourceLoader.getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "krmsTypeRepositoryService"));
743         }
744         return krmsTypeRepositoryService;
745     }
746 
747     public TermRepositoryService getTermRepositoryService() {
748         if (termRepositoryService == null) {
749             termRepositoryService = (TermRepositoryService) GlobalResourceLoader.getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "termRepositoryService"));
750         }
751         return termRepositoryService;
752     }
753 
754 }