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