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