001/**
002 * Copyright 2005-2013 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krms.service.impl;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
020import org.kuali.rice.core.api.util.tree.Tree;
021import org.kuali.rice.krad.uif.UifConstants;
022import org.kuali.rice.krad.uif.component.Component;
023import org.kuali.rice.krad.uif.container.Container;
024import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
025import org.kuali.rice.krad.uif.util.ComponentFactory;
026import org.kuali.rice.krad.uif.util.ComponentUtils;
027import org.kuali.rice.krad.uif.view.View;
028import org.kuali.rice.krad.uif.view.ViewModel;
029import org.kuali.rice.krad.util.BeanPropertyComparator;
030import org.kuali.rice.krad.util.GlobalVariables;
031import org.kuali.rice.krad.util.ObjectUtils;
032import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
033import org.kuali.rice.krms.api.KrmsConstants;
034import org.kuali.rice.krms.api.repository.LogicalOperator;
035import org.kuali.rice.krms.api.repository.RuleManagementService;
036import org.kuali.rice.krms.api.repository.proposition.PropositionType;
037import org.kuali.rice.krms.api.repository.term.TermDefinition;
038import org.kuali.rice.krms.api.repository.term.TermRepositoryService;
039import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
040import org.kuali.rice.krms.api.repository.type.KrmsTypeRepositoryService;
041import org.kuali.rice.krms.builder.ComponentBuilder;
042import org.kuali.rice.krms.dto.PropositionEditor;
043import org.kuali.rice.krms.dto.PropositionParameterEditor;
044import org.kuali.rice.krms.dto.RuleEditor;
045import org.kuali.rice.krms.dto.RuleManagementWrapper;
046import org.kuali.rice.krms.dto.RuleManager;
047import org.kuali.rice.krms.dto.TermEditor;
048import org.kuali.rice.krms.dto.TermParameterEditor;
049import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
050import org.kuali.rice.krms.service.TemplateRegistry;
051import org.kuali.rice.krms.tree.RuleViewTreeBuilder;
052import org.kuali.rice.krms.tree.node.CompareTreeNode;
053import org.kuali.rice.krms.tree.RuleCompareTreeBuilder;
054import org.kuali.rice.krms.tree.RuleEditTreeBuilder;
055import org.kuali.rice.krms.tree.RulePreviewTreeBuilder;
056import org.kuali.rice.krms.util.KRMSConstants;
057import org.kuali.rice.krms.util.NaturalLanguageHelper;
058import org.kuali.rice.krms.util.PropositionTreeUtil;
059import org.kuali.rice.krms.dto.TemplateInfo;
060import org.kuali.rice.krms.service.RuleViewHelperService;
061import org.kuali.student.common.uif.service.impl.KSViewHelperServiceImpl;
062import org.kuali.student.r2.core.constants.KSKRMSServiceConstants;
063import org.springframework.beans.BeanUtils;
064
065import javax.xml.namespace.QName;
066import java.util.ArrayList;
067import java.util.Arrays;
068import java.util.HashMap;
069import java.util.List;
070import java.util.Map;
071
072/**
073 * Helpers Service for the Rule Pages.
074 *
075 * @author Kuali Student Team
076 */
077public class RuleViewHelperServiceImpl extends KSViewHelperServiceImpl implements RuleViewHelperService {
078
079    private transient RuleManagementService ruleManagementService;
080    private transient KrmsTypeRepositoryService krmsTypeRepositoryService;
081    private transient TermRepositoryService termRepositoryService;
082
083    private RuleCompareTreeBuilder compareTreeBuilder;
084    private RuleEditTreeBuilder editTreeBuilder;
085    private RulePreviewTreeBuilder previewTreeBuilder;
086    private RuleViewTreeBuilder viewTreeBuilder;
087
088    private NaturalLanguageHelper naturalLanguageHelper;
089
090    private static TemplateRegistry templateRegistry;
091
092    protected RuleEditor getRuleEditor(Object model) {
093        if (model instanceof MaintenanceDocumentForm) {
094            MaintenanceDocumentForm maintenanceDocumentForm = (MaintenanceDocumentForm) model;
095            Object dataObject = maintenanceDocumentForm.getDocument().getNewMaintainableObject().getDataObject();
096
097            if (dataObject instanceof RuleEditor) {
098                return (RuleEditor) dataObject;
099            } 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}