View Javadoc

1   /**
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krms.controller;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.util.tree.Node;
20  import org.kuali.rice.krad.uif.UifParameters;
21  import org.kuali.rice.krad.util.GlobalVariables;
22  import org.kuali.rice.krad.util.KRADConstants;
23  import org.kuali.rice.krad.web.controller.MaintenanceDocumentController;
24  import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
25  import org.kuali.rice.krad.web.form.UifFormBase;
26  import org.kuali.rice.krms.api.repository.proposition.PropositionType;
27  import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
28  import org.kuali.rice.krms.dto.AgendaEditor;
29  import org.kuali.rice.krms.dto.PropositionEditor;
30  import org.kuali.rice.krms.dto.RuleEditor;
31  import org.kuali.rice.krms.dto.RuleManagementWrapper;
32  import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
33  import org.kuali.rice.krms.service.RuleViewHelperService;
34  import org.kuali.rice.krms.util.AgendaUtilities;
35  import org.kuali.rice.krms.tree.node.SimplePropositionEditNode;
36  import org.kuali.rice.krms.tree.node.SimplePropositionNode;
37  import org.kuali.rice.krms.tree.node.RuleEditorTreeNode;
38  import org.kuali.rice.krms.util.KRMSConstants;
39  import org.kuali.rice.krms.util.PropositionTreeUtil;
40  import org.kuali.rice.krms.util.RuleLogicExpressionParser;
41  import org.kuali.student.common.uif.util.KSControllerHelper;
42  import org.springframework.validation.BindingResult;
43  import org.springframework.web.bind.annotation.ModelAttribute;
44  import org.springframework.web.bind.annotation.RequestMapping;
45  import org.springframework.web.servlet.ModelAndView;
46  
47  import javax.servlet.http.HttpServletRequest;
48  import javax.servlet.http.HttpServletResponse;
49  import java.util.ArrayList;
50  import java.util.List;
51  import java.util.Map;
52  
53  /**
54   * Controller for the KS KRMS page.
55   *
56   * @author Kuali Student Team
57   */
58  public class RuleEditorController extends MaintenanceDocumentController {
59  
60      /**
61       * Method used to invoke the CO inquiry view from Manage Course Offering screen while search input is Course Offering
62       * Code (04a screen)
63       *
64       * @param form
65       * @param result
66       * @param request
67       * @param response
68       * @return
69       * @throws Exception
70       */
71      @RequestMapping(params = "methodToCall=goToRuleView")
72      public ModelAndView goToRuleView(@ModelAttribute("KualiForm") UifFormBase form, @SuppressWarnings("unused") BindingResult result,
73                                       @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
74  
75          //Clear the client state on new edit rule.
76          form.getClientStateForSyncing().clear();
77  
78          RuleEditor ruleEditor = AgendaUtilities.retrieveSelectedRuleEditor((MaintenanceDocumentForm) form);
79          this.getViewHelper(form).refreshInitTrees(ruleEditor);
80  
81          if (!form.getActionParameters().containsKey(UifParameters.NAVIGATE_TO_PAGE_ID)) {
82              form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, KRMSConstants.KRMS_RULE_MAINTENANCE_PAGE_ID);
83          }
84          return super.navigate(form, result, request, response);
85      }
86  
87      /**
88       * Deletes selected rule from agenda on Manage Course Requistes page
89       *
90       * @param form
91       * @param result
92       * @param request
93       * @param response
94       * @return
95       * @throws Exception
96       */
97      @RequestMapping(params = "methodToCall=deleteRule")
98      public ModelAndView deleteRule(@ModelAttribute("KualiForm") UifFormBase form, @SuppressWarnings("unused") BindingResult result,
99                                     @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
100 
101         MaintenanceDocumentForm document = (MaintenanceDocumentForm) form;
102         RuleManagementWrapper ruleWrapper = AgendaUtilities.getRuleWrapper(document);
103         String ruleKey = AgendaUtilities.getRuleKey(document);
104 
105         AgendaEditor agenda = AgendaUtilities.getSelectedAgendaEditor(ruleWrapper, ruleKey);
106         if (agenda != null) {
107             RuleEditor ruleEditor = agenda.getRuleEditors().get(ruleKey);
108 
109             //Only add rules to delete list that are already persisted.
110             if (ruleEditor.getId() != null) {
111                 agenda.getDeletedRules().add(ruleEditor);
112             }
113 
114             RuleEditor dummyRule = new RuleEditor(ruleEditor.getKey(), true, ruleEditor.getRuleTypeInfo());
115             dummyRule.setParent(ruleEditor.getParent());
116             agenda.getRuleEditors().put(ruleEditor.getKey(), dummyRule);
117         }
118 
119         return getUIFModelAndView(document);
120     }
121 
122     /**
123      * Navigates to rule maintenance page with rule type to initialize adding of new rule.
124      *
125      * @param form
126      * @param result
127      * @param request
128      * @param response
129      * @return
130      * @throws Exception
131      */
132     @RequestMapping(params = "methodToCall=addRule")
133     public ModelAndView addRule(@ModelAttribute("KualiForm") UifFormBase form, @SuppressWarnings("unused") BindingResult result,
134                                 @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
135 
136         //Clear the client state on new edit rule.
137         form.getClientStateForSyncing().clear();
138 
139         RuleEditor ruleEditor = AgendaUtilities.retrieveSelectedRuleEditor((MaintenanceDocumentForm) form);
140 
141         this.getViewHelper(form).refreshInitTrees(ruleEditor);
142 
143         if (!form.getActionParameters().containsKey(UifParameters.NAVIGATE_TO_PAGE_ID)) {
144             form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, KRMSConstants.KRMS_RULE_MAINTENANCE_PAGE_ID);
145         }
146         return super.navigate(form, result, request, response);
147     }
148 
149     /**
150      * Call the super method to avoid the agenda tree being reloaded from the db.
151      *
152      * @param form
153      * @param result
154      * @param request
155      * @param response
156      * @return
157      * @throws Exception
158      */
159     @RequestMapping(params = "methodToCall=ajaxRefresh")
160     public ModelAndView ajaxRefresh(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
161                                     HttpServletRequest request, HttpServletResponse response)
162             throws Exception {
163         return getUIFModelAndView(form);
164     }
165 
166     /**
167      * Retrieves selected rule editor from data object.
168      *
169      * @param form
170      * @return the current rule editor
171      */
172     protected RuleEditor getRuleEditor(UifFormBase form) {
173         if (form instanceof MaintenanceDocumentForm) {
174             MaintenanceDocumentForm maintenanceDocumentForm = (MaintenanceDocumentForm) form;
175             Object dataObject = maintenanceDocumentForm.getDocument().getNewMaintainableObject().getDataObject();
176 
177             if (dataObject instanceof RuleEditor) {
178                 return (RuleEditor) dataObject;
179             } else if (dataObject instanceof RuleManagementWrapper) {
180                 RuleManagementWrapper wrapper = (RuleManagementWrapper) dataObject;
181                 return wrapper.getRuleEditor();
182             }
183         }
184 
185         return null;
186     }
187 
188     //
189     // Rule Editor Controller methods
190     //
191 
192     /**
193      * Method to copy rule.
194      *
195      * @param form
196      * @param result
197      * @param request
198      * @param response
199      * @return
200      * @throws Exception
201      */
202     @RequestMapping(params = "methodToCall=copyRule")
203     public ModelAndView copyRule(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
204                                  HttpServletRequest request, HttpServletResponse response) throws Exception {
205         return super.refresh(form, result, request, response);
206     }
207 
208     /**
209      * This method starts an edit on proposition.
210      *
211      * @param form
212      * @param result
213      * @param request
214      * @param response
215      * @return
216      * @throws Exception
217      */
218     @RequestMapping(params = "methodToCall=goToEditProposition")
219     public ModelAndView goToEditProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
220                                             HttpServletRequest request, HttpServletResponse response) throws Exception {
221 
222         RuleViewHelperService viewHelper = this.getViewHelper(form);
223         RuleEditor ruleEditor = getRuleEditor(form);
224 
225         PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
226         PropositionEditor proposition = PropositionTreeUtil.getProposition(ruleEditor);
227         proposition.setEditMode(true);
228 
229         if (!PropositionType.COMPOUND.getCode().equalsIgnoreCase(proposition.getPropositionTypeCode())) {
230 
231             String propositionTypeId = proposition.getTypeId();
232             if (propositionTypeId == null) {
233                 proposition.setType(null);
234             } else {
235 
236                 KrmsTypeDefinition type = KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService().getTypeById(propositionTypeId);
237                 if (type != null) {
238                     proposition.setType(type.getName());
239                 }
240             }
241 
242         }
243 
244         //refresh the tree
245         viewHelper.refreshInitTrees(ruleEditor);
246 
247         return getUIFModelAndView(form);
248     }
249 
250     /**
251      * Method to initialize the adding of proposition to rule.
252      *
253      * @param form
254      * @param result
255      * @param request
256      * @param response
257      * @return
258      * @throws Exception
259      */
260     @RequestMapping(params = "methodToCall=addProposition")
261     public ModelAndView addProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
262                                        HttpServletRequest request, HttpServletResponse response) throws Exception {
263 
264         RuleEditor ruleEditor = getRuleEditor(form);
265         String selectedPropKey = ruleEditor.getSelectedKey();
266 
267         // find parent
268         Node<RuleEditorTreeNode, String> root = ruleEditor.getEditTree().getRootElement();
269         Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(root, selectedPropKey);
270 
271         //PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor);
272         RuleViewHelperService viewHelper = this.getViewHelper(form);
273 
274         //Special case when only one proposition in tree or no proposition selected
275         if (selectedPropKey.isEmpty() && parent == null && root.getChildren().size() > 0) {
276             //Special case when now proposition selected and more than one proposition in tree
277             if (root.getChildren().get(root.getChildren().size() - 1).getNodeType().contains("compoundNode")) {
278                 parent = root.getChildren().get(root.getChildren().size() - 1);
279                 selectedPropKey = parent.getChildren().get(parent.getChildren().size() - 1).getData().getProposition().getKey();
280             } //Special case when one proposition in tree and no proposition selected
281             else {
282                 parent = root;
283                 selectedPropKey = root.getChildren().get(root.getChildren().size() - 1).getData().getProposition().getKey();
284             }
285         } //If root compound proposition selected
286         else if (parent != null) {
287             if (parent.getNodeType().equals("treeRoot") && !parent.getChildren().get(parent.getChildren().size() - 1).getNodeType().contains("simple")) {
288                 parent = root.getChildren().get(root.getChildren().size() - 1);
289                 selectedPropKey = parent.getChildren().get(parent.getChildren().size() - 1).getData().getProposition().getKey();
290             }
291         }
292 
293         // add new child at appropriate spot
294         if (parent != null) {
295             List<Node<RuleEditorTreeNode, String>> children = parent.getChildren();
296             for (int index = 0; index < children.size(); index++) {
297                 Node<RuleEditorTreeNode, String> child = children.get(index);
298 
299                 // if our selected node is a simple proposition, add a new one after
300                 if (propKeyMatches(child, selectedPropKey)) {
301                     // handle special case of adding to a lone simple proposition.
302                     // in this case, we need to change the root level proposition to a compound proposition
303                     // move the existing simple proposition as the first compound component,
304                     // then add a new blank simple prop as the second compound component.
305                     PropositionEditor blank = null;
306                     if (parent.equals(root) && (isSimpleNode(child.getNodeType()))) {
307 
308                         // create a new compound proposition
309                         blank = viewHelper.createCompoundPropositionBoStub(child.getData().getProposition(), true);
310                         // don't set compound.setEditMode(true) as the Simple Prop in the compound prop is the only prop in edit mode
311                         ruleEditor.setProposition(blank);
312                     }
313                     // handle regular case of adding a simple prop to an existing compound prop
314                     else if (!parent.equals(root)) {
315 
316                         // build new Blank Proposition
317                         blank = viewHelper.createSimplePropositionBoStub(child.getData().getProposition());
318                         //add it to the parent
319                         PropositionEditor parentProp = parent.getData().getProposition();
320                         parentProp.getCompoundEditors().add(((index / 2) + 1), blank);
321                     } else {
322                         return getUIFModelAndView(form);
323                     }
324                     this.getViewHelper(form).refreshInitTrees(ruleEditor);
325                     if (blank != null) {
326                         ruleEditor.setSelectedKey(blank.getKey());
327                     } else {
328                         ruleEditor.setSelectedKey(null);
329                     }
330                     break;
331                 }
332             }
333         } else {
334             // special case, if root has no children, add a new simple proposition
335             // todo: how to add compound proposition. - just add another to the firs simple
336             if (root.getChildren().isEmpty()) {
337                 PropositionEditor blank = viewHelper.createSimplePropositionBoStub(null);
338                 blank.setRuleId(ruleEditor.getId());
339                 ruleEditor.setPropId(blank.getId());
340                 ruleEditor.setProposition(blank);
341             }
342             this.getViewHelper(form).refreshInitTrees(ruleEditor);
343         }
344         return getUIFModelAndView(form);
345     }
346 
347     /**
348      * Returns <code>true</code> if proposition key matches tree node key
349      *
350      * @param node
351      * @param propKey
352      * @return if proposition key matches tree node key; <code>false</code> otherwise
353      */
354     private boolean propKeyMatches(Node<RuleEditorTreeNode, String> node, String propKey) {
355         if (propKey != null && node != null && node.getData() != null && propKey.equalsIgnoreCase(node.getData().getProposition().getKey())) {
356             return true;
357         }
358         return false;
359     }
360 
361     /**
362      * This method return the index of the position of the child that matches the id
363      *
364      * @param parent
365      * @param propKey
366      * @return index if found, -1 if not found
367      */
368     private int findChildIndex(Node<RuleEditorTreeNode, String> parent, String propKey) {
369         int index;
370         List<Node<RuleEditorTreeNode, String>> children = parent.getChildren();
371         for (index = 0; index < children.size(); index++) {
372             Node<RuleEditorTreeNode, String> child = children.get(index);
373             // if our selected node is a simple proposition, add a new one after
374             if (propKeyMatches(child, propKey)) {
375                 return index;
376             }
377         }
378         return -1;
379     }
380 
381     /**
382      * Moves proposition up in tree structure.
383      *
384      * @param form
385      * @param result
386      * @param request
387      * @param response
388      * @return
389      * @throws Exception
390      */
391     @RequestMapping(params = "methodToCall=movePropositionUp")
392     public ModelAndView movePropositionUp(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
393                                           HttpServletRequest request, HttpServletResponse response)
394             throws Exception {
395         moveSelectedProposition(form, true);
396 
397         return getUIFModelAndView(form);
398     }
399 
400     /**
401      * Moves proposition down in tree structure.
402      *
403      * @param form
404      * @param result
405      * @param request
406      * @param response
407      * @return
408      * @throws Exception
409      */
410     @RequestMapping(params = "methodToCall=movePropositionDown")
411     public ModelAndView movePropositionDown(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
412                                             HttpServletRequest request, HttpServletResponse response)
413             throws Exception {
414         moveSelectedProposition(form, false);
415 
416         return getUIFModelAndView(form);
417     }
418 
419     /**
420      * Moves proposition up or down.
421      * <p/>
422      * Rough algorithm for moving a node up.
423      * <p/>
424      * find the following:
425      * node := the selected node
426      * parent := the selected node's parent, its containing node (via when true or when false relationship)
427      * parentsOlderCousin := the parent's level-order predecessor (sibling or cousin)
428      *
429      * @param form
430      * @param up   whether the desired move is in an up direction
431      * @throws Exception
432      */
433     private void moveSelectedProposition(UifFormBase form, boolean up) throws Exception {
434 
435         RuleEditor ruleEditor = getRuleEditor(form);
436         String selectedPropKey = ruleEditor.getSelectedKey();
437 
438         // find parent
439         Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(ruleEditor.getEditTree().getRootElement(), selectedPropKey);
440 
441         // add new child at appropriate spot
442         if (parent != null) {
443             List<Node<RuleEditorTreeNode, String>> children = parent.getChildren();
444             for (int index = 0; index < children.size(); index++) {
445                 Node<RuleEditorTreeNode, String> child = children.get(index);
446                 // if our selected node is a simple proposition, add a new one after
447                 if (propKeyMatches(child, selectedPropKey) &&
448                         (isSimpleNode(child.getNodeType()) ||
449                                 (RuleEditorTreeNode.COMPOUND_NODE_TYPE.equalsIgnoreCase(child.getNodeType())) ||
450                                 (child.getNodeType().contains(RuleEditorTreeNode.FIRST_IN_GROUP)) ||
451                                 (child.getNodeType().contains(RuleEditorTreeNode.LAST_IN_GROUP)))) {
452 
453                     //remove it from its current spot
454                     PropositionEditor parentProp = parent.getData().getProposition();
455                     PropositionEditor workingProp = null;
456                     if (index != 0 && up) {
457                         workingProp = parentProp.getCompoundEditors().remove(index / 2);
458                     } else if (!up && index != (children.size() - 1)) {
459                         workingProp = parentProp.getCompoundEditors().remove(index / 2);
460                     }
461                     if ((index > 0) && up) {
462                         parentProp.getCompoundEditors().add((index / 2) - 1, workingProp);
463                     } else if ((index < (children.size() - 1) && !up)) {
464                         parentProp.getCompoundEditors().add((index / 2) + 1, workingProp);
465                     }
466                     // redisplay the tree (editMode = true)
467                     this.getViewHelper(form).refreshInitTrees(ruleEditor);
468                     break;
469                 }
470             }
471         }
472         //Compare rule with parent rule.
473         compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
474 
475     }
476 
477     /**
478      * Returns <code>true</code> if node is of type simple
479      *
480      * @param nodeType
481      * @return if node is of type simple; <code>false</code> otherwise
482      */
483     public boolean isSimpleNode(String nodeType) {
484         if (nodeType.contains(SimplePropositionNode.NODE_TYPE) ||
485                 SimplePropositionEditNode.NODE_TYPE.equalsIgnoreCase(nodeType)) {
486             return true;
487         }
488         return false;
489     }
490 
491     /**
492      * Moves proposition left in tree structure.
493      * <p/>
494      * Rough algorithm for moving a node up.
495      * <p/>
496      * find the following:
497      * node := the selected node
498      * parent := the selected node's parent, its containing node (via when true or when false relationship)
499      * parentsOlderCousin := the parent's level-order predecessor (sibling or cousin)
500      *
501      * @param form
502      * @param result
503      * @param request
504      * @param response
505      * @return
506      * @throws Exception
507      */
508     @RequestMapping(params = "methodToCall=movePropositionLeft")
509     public ModelAndView movePropositionLeft(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
510                                             HttpServletRequest request, HttpServletResponse response)
511             throws Exception {
512 
513         RuleEditor ruleEditor = getRuleEditor(form);
514         String selectedpropKey = ruleEditor.getSelectedKey();
515 
516         // find agendaEditor.getAgendaItemLine().getRule().getPropositionTree().getRootElement()parent
517         Node<RuleEditorTreeNode, String> root = ruleEditor.getEditTree().getRootElement();
518         Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(root, selectedpropKey);
519         if ((parent != null) && (!parent.getNodeType().contains(RuleEditorTreeNode.ROOT_TYPE))) {
520             Node<RuleEditorTreeNode, String> granny = PropositionTreeUtil.findParentPropositionNode(root, parent.getData().getProposition().getKey());
521             if (!granny.equals(root)) {
522                 int oldIndex = findChildIndex(parent, selectedpropKey);
523                 int newIndex = findChildIndex(granny, parent.getData().getProposition().getKey());
524                 if (oldIndex >= 0 && newIndex >= 0) {
525                     PropositionEditor prop = parent.getData().getProposition().getCompoundEditors().remove(oldIndex / 2);
526                     if ((parent.getChildren().size() == 1) || (parent.getChildren().size() == 3)) {
527                         PropositionTreeUtil.removeCompoundProp(ruleEditor.getPropositionEditor());
528                     }
529                     if (granny.getData().getProposition().getCompoundEditors().isEmpty()) {
530                         granny.getData().getProposition().getCompoundEditors().add(newIndex, prop);
531                     } else {
532                         granny.getData().getProposition().getCompoundEditors().add((newIndex / 2) + 1, prop);
533                     }
534                     this.getViewHelper(form).refreshInitTrees(ruleEditor);
535                 }
536             }
537 
538         }
539         //Compare rule with parent rule.
540         compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
541         return getUIFModelAndView(form);
542     }
543 
544     /**
545      * Move proposition right in tree structure.
546      * <p/>
547      * Rough algorithm for moving a node Right
548      * if the selected node is above a compound proposition, move it into the compound proposition as the first child
549      * if the node is above a simple proposition, do nothing.
550      * find the following:
551      * node := the selected node
552      * parent := the selected node's parent, its containing node
553      * nextSibling := the node after the selected node
554      *
555      * @param form
556      * @param result
557      * @param request
558      * @param response
559      * @return
560      * @throws Exception
561      */
562     @RequestMapping(params = "methodToCall=movePropositionRight")
563     public ModelAndView movePropositionRight(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
564                                              HttpServletRequest request, HttpServletResponse response)
565             throws Exception {
566 
567         RuleEditor ruleEditor = getRuleEditor(form);
568         String selectedpropKey = ruleEditor.getSelectedKey();
569 
570         // find parent
571         Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(
572                 ruleEditor.getEditTree().getRootElement(), selectedpropKey);
573         if (parent != null) {
574             int index = findChildIndex(parent, selectedpropKey);
575             // if we are the last child, do nothing, otherwise
576             if (index >= 0 && index + 1 < parent.getChildren().size()) {
577                 Node<RuleEditorTreeNode, String> nextSibling = parent.getChildren().get(index + 2);
578                 // if selected node above a compound node, move it into it as first child
579                 if (nextSibling.getNodeType().contains(RuleEditorTreeNode.COMPOUND_NODE_TYPE)) {
580                     // remove selected node from it's current spot
581                     PropositionEditor prop = parent.getData().getProposition().getCompoundEditors().remove(index / 2);
582                     // add it to it's siblings children
583                     nextSibling.getData().getProposition().getCompoundEditors().add(0, prop);
584                 }
585                 //Remove single parents and refresh the tree.
586                 PropositionTreeUtil.removeCompoundProp(parent.getData().getProposition());
587                 this.getViewHelper(form).refreshInitTrees(ruleEditor);
588             }
589         }
590         //Compare rule with parent rule.
591         compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
592         return getUIFModelAndView(form);
593     }
594 
595     /**
596      * Introduces a new compound proposition between the selected proposition and its parent.
597      * Additionally, it puts a new blank simple proposition underneath the compound proposition
598      * as a sibling to the selected proposition.
599      *
600      * @param form
601      * @param result
602      * @param request
603      * @param response
604      * @return
605      * @throws Exception
606      */
607     @RequestMapping(params = "methodToCall=togglePropositionSimpleCompound")
608     public ModelAndView togglePropositionSimpleCompound(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
609                                                         HttpServletRequest request, HttpServletResponse response)
610             throws Exception {
611 
612         RuleEditor ruleEditor = getRuleEditor(form);
613         String selectedPropKey = ruleEditor.getSelectedKey();
614 
615         PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
616         RuleViewHelperService viewHelper = this.getViewHelper(form);
617 
618         if (!StringUtils.isBlank(selectedPropKey)) {
619             // find parent
620             Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(
621                     ruleEditor.getEditTree().getRootElement(), selectedPropKey);
622             if (parent != null) {
623 
624                 int index = findChildIndex(parent, selectedPropKey);
625                 PropositionEditor propBo = parent.getChildren().get(index).getData().getProposition();
626 
627                 // create a new compound proposition
628                 PropositionEditor compound = viewHelper.createCompoundPropositionBoStub(propBo, true);
629 
630                 if (parent.getData() == null) { // SPECIAL CASE: this is the only proposition in the tree
631                     ruleEditor.setProposition(compound);
632                 } else {
633                     PropositionEditor parentBo = parent.getData().getProposition();
634                     List<PropositionEditor> siblings = parentBo.getCompoundEditors();
635 
636                     int propIndex = -1;
637                     for (int i = 0; i < siblings.size(); i++) {
638                         if (propBo.getKey().equals(siblings.get(i).getKey())) {
639                             propIndex = i;
640                             break;
641                         }
642                     }
643 
644                     parentBo.getCompoundEditors().set(propIndex, compound);
645                     compound.getCompoundEditors().get(1).setEditMode(true);
646                 }
647 
648                 viewHelper.refreshInitTrees(ruleEditor);
649                 ruleEditor.setSelectedKey(compound.getCompoundEditors().get(1).getKey());
650 
651             }
652         }
653 
654         return getUIFModelAndView(form);
655     }
656 
657     /**
658      * Paste proposition in selected position in tree structure.
659      *
660      * @param form
661      * @param result
662      * @param request
663      * @param response
664      * @return
665      * @throws Exception
666      */
667     @RequestMapping(params = "methodToCall=pasteProposition")
668     public ModelAndView pasteProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
669                                          HttpServletRequest request, HttpServletResponse response)
670             throws Exception {
671 
672         boolean cutAction = true;
673         RuleEditor ruleEditor = getRuleEditor(form);
674         RuleViewHelperService viewHelper = this.getViewHelper(form);
675 
676         // get selected id
677         String selectedPropKey = ruleEditor.getSelectedKey();
678         if (StringUtils.isBlank(selectedPropKey)) {
679             return getUIFModelAndView(form);
680         }
681 
682         // get the id to move
683         String movePropKey = ruleEditor.getCutKey();
684         if (StringUtils.isBlank(movePropKey)) {
685             movePropKey = ruleEditor.getCopyKey();
686             cutAction = false;
687         }
688 
689         // check if selected and move is not the same
690         if (StringUtils.isNotBlank(movePropKey)) {
691 
692             PropositionEditor newParent = null;
693             PropositionEditor workingProp = null;
694             PropositionEditor root = ruleEditor.getPropositionEditor();
695 
696             // Special case when the user copy the the only proposition in tree.
697             if (movePropKey.equals(root.getKey())) {
698                 newParent = viewHelper.createCompoundPropositionBoStub(root, false);
699                 workingProp = viewHelper.copyProposition(root);
700             } else {
701                 Node<RuleEditorTreeNode, String> rootNode = ruleEditor.getEditTree().getRootElement();
702                 if (selectedPropKey.equals(root.getKey())) {
703                     newParent = root;
704                 } else {
705                     newParent = PropositionTreeUtil.findParentPropositionNode(rootNode, selectedPropKey).getData().getProposition();
706                 }
707                 PropositionEditor oldParent = PropositionTreeUtil.findParentPropositionNode(rootNode, movePropKey).getData().getProposition();
708 
709                 // cut or copy from old
710                 if (oldParent != null) {
711                     List<PropositionEditor> children = oldParent.getCompoundEditors();
712                     for (int index = 0; index < children.size(); index++) {
713                         if (movePropKey.equalsIgnoreCase(children.get(index).getKey())) {
714                             if (cutAction) {
715                                 workingProp = oldParent.getCompoundEditors().remove(index);
716                             } else {
717                                 workingProp = viewHelper.copyProposition(oldParent.getCompoundEditors().get(index));
718                             }
719                             break;
720                         }
721                     }
722                 }
723             }
724 
725             // add to new
726             addProposition(selectedPropKey, newParent, workingProp);
727             if (movePropKey.equals(root.getKey())) {
728                 ruleEditor.setProposition(newParent);
729             }
730 
731             //Refresh the tree.
732             PropositionTreeUtil.removeCompoundProp(ruleEditor);
733             ruleEditor.setSelectedKey(StringUtils.EMPTY);
734             viewHelper.refreshInitTrees(ruleEditor);
735         }
736 
737         //Compare rule with parent rule.
738         compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
739 
740         // call the super method to avoid the agenda tree being reloaded from the db
741         return getUIFModelAndView(form);
742     }
743 
744     /**
745      * Adds proposition at selected position.
746      *
747      * @param selectedpropKey
748      * @param newParent
749      * @param workingProp
750      */
751     private void addProposition(String selectedpropKey, PropositionEditor newParent, PropositionEditor workingProp) {
752         // add to new
753         if (newParent != null && workingProp != null) {
754             //Selected is parent, add to list.
755             if(selectedpropKey.equalsIgnoreCase(newParent.getKey())){
756                 newParent.getCompoundEditors().add(workingProp);
757                 return;
758             }
759 
760             //Add after selected prop.
761             List<PropositionEditor> children = newParent.getCompoundEditors();
762             for (int index = 0; index < children.size(); index++) {
763                 if (selectedpropKey.equalsIgnoreCase(children.get(index).getKey())) {
764                     children.add(index + 1, workingProp);
765                     return;
766                 }
767             }
768         }
769     }
770 
771     /**
772      * Removes proposition.
773      *
774      * @param form
775      * @param result
776      * @param request
777      * @param response
778      * @return
779      * @throws Exception
780      */
781     @RequestMapping(params = "methodToCall=deleteProposition")
782     public ModelAndView deleteProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
783                                           HttpServletRequest request, HttpServletResponse response)
784             throws Exception {
785         RuleEditor ruleEditor = getRuleEditor(form);
786         String selectedpropKey = ruleEditor.getSelectedKey();
787         Node<RuleEditorTreeNode, String> root = ruleEditor.getEditTree().getRootElement();
788 
789         Node<RuleEditorTreeNode, String> parentNode = PropositionTreeUtil.findParentPropositionNode(root, selectedpropKey);
790 
791         // what if it is the root?
792         if (parentNode != null && parentNode.getData() != null) { // it is not the root as there is a parent w/ a prop
793             PropositionEditor parent = parentNode.getData().getProposition();
794             if (parent != null) {
795                 List<PropositionEditor> children = parent.getCompoundEditors();
796                 for (int index = 0; index < children.size(); index++) {
797                     if (selectedpropKey.equalsIgnoreCase(children.get(index).getKey())) {
798                         parent.getCompoundComponents().remove(index);
799                         break;
800                     }
801                 }
802             }
803             PropositionTreeUtil.removeCompoundProp(ruleEditor);
804             ruleEditor.setSelectedKey(StringUtils.EMPTY);
805         } else { // no parent, it is the root
806             ruleEditor.reset();
807         }
808 
809         //Compare rule with parent rule.
810         compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
811 
812         this.getViewHelper(form).refreshInitTrees(ruleEditor);
813         return getUIFModelAndView(form);
814     }
815 
816     /**
817      * Updates compound operator in tree structure.
818      *
819      * @param form
820      * @param result
821      * @param request
822      * @param response
823      * @return
824      * @throws Exception
825      */
826     @RequestMapping(params = "methodToCall=updateCompoundOperator")
827     public ModelAndView updateCompoundOperator(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
828                                                HttpServletRequest request, HttpServletResponse response)
829             throws Exception {
830 
831         RuleEditor ruleEditor = getRuleEditor(form);
832         String selectedpropKey = ruleEditor.getSelectedKey();
833         Node<RuleEditorTreeNode, String> parentNode = PropositionTreeUtil.findParentPropositionNode(ruleEditor.getEditTree().getRootElement(), selectedpropKey);
834         PropositionEditor parent = parentNode.getData().getProposition();
835 
836         PropositionEditor proposition = PropositionTreeUtil.findProposition(parentNode, selectedpropKey);
837 
838         RuleViewHelperService viewHelper = this.getViewHelper(form);
839         viewHelper.setTypeForCompoundOpCode(parent, proposition.getCompoundOpCode());
840         viewHelper.resetDescription(parent);
841         viewHelper.refreshInitTrees(ruleEditor);
842 
843         //Compare rule with parent rule.
844         compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
845 
846         return getUIFModelAndView(form);
847     }
848 
849     /**
850      * Updates rule with new or changed propositions.
851      *
852      * @param form
853      * @param result
854      * @param request
855      * @param response
856      * @return
857      * @throws Exception
858      */
859     @RequestMapping(params = "methodToCall=updateProposition")
860     public ModelAndView updateProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
861                                           HttpServletRequest request, HttpServletResponse response)
862             throws Exception {
863 
864 
865         //Reset the description on current selected proposition
866         RuleEditor ruleEditor = getRuleEditor(form);
867         PropositionEditor proposition = PropositionTreeUtil.getProposition(ruleEditor);
868         if (proposition != null) {
869 
870             //Validate the proposition and return if has errors.
871             this.getViewHelper(form).validateProposition(proposition);
872             if (!GlobalVariables.getMessageMap().getErrorMessages().isEmpty()) {
873                 return getUIFModelAndView(form);
874             }
875 
876             if (!GlobalVariables.getMessageMap().getWarningMessages().isEmpty()) {
877                 if (!hasDialogBeenAnswered(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING, form)) {
878                     return showDialog(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING, form, request, response);
879                 }
880 
881                 String dialogResponse = getStringDialogResponse(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING, form, request, response);
882                 if ("N".equals(dialogResponse)) {
883                     form.getDialogManager().resetDialogStatus(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING);
884                     return getUIFModelAndView(form);
885                 }
886             }
887 
888             //Reset the description and natural language for the proposition.
889             this.getViewHelper(form).resetDescription(proposition);
890             if (!GlobalVariables.getMessageMap().getErrorMessages().isEmpty()) {
891                 return getUIFModelAndView(form);
892             }
893 
894             //Check if the proposition that was edited is the root proposition and replace.
895             if (ruleEditor.getPropositionEditor().getKey().equals(ruleEditor.getSelectedKey())) {
896                 ruleEditor.setProposition(proposition);
897             } else {
898                 //Replace old proposition if not the root proposition.
899                 this.setUpdatedProposition(ruleEditor.getPropositionEditor(), proposition);
900             }
901 
902         }
903 
904         if (ruleEditor.getProposition() != null) {
905             PropositionTreeUtil.resetNewProp(ruleEditor.getPropositionEditor());
906         }
907 
908         // clear dialog history so user can press the button again
909         form.getDialogManager().resetDialogStatus(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING);
910 
911         //Compare rule with parent rule.
912         compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
913 
914         //Remove the edit mode
915         PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
916         this.getViewHelper(form).refreshInitTrees(ruleEditor);
917 
918         return getUIFModelAndView(form);
919     }
920 
921     /**
922      * Replace old proposition with the updated proposition once the user clicked "Update Preview". We keep the
923      * old proposition for when the user want to cancel the editing of this proposition.
924      * <p/>
925      * Recursively walk through the proposition tree and search for the proposition with the same key, if found
926      * replace it at the same index.
927      *
928      * @param proposition
929      * @param updatedProposition
930      */
931     private void setUpdatedProposition(PropositionEditor proposition, PropositionEditor updatedProposition) {
932 
933         if (proposition.getCompoundEditors() != null) {
934             for (int i = 0; i < proposition.getCompoundEditors().size(); i++) {
935                 PropositionEditor childProp = proposition.getCompoundEditors().get(i);
936                 if (childProp.getKey().equals(updatedProposition.getKey())) {
937                     proposition.getCompoundEditors().set(i, updatedProposition);
938                 } else {
939                     setUpdatedProposition(childProp, updatedProposition);
940                 }
941             }
942         }
943     }
944 
945     protected void compareRulePropositions(MaintenanceDocumentForm form, RuleEditor ruleEditor) throws Exception {
946 
947         RuleManagementWrapper ruleWrapper = (RuleManagementWrapper) form.getDocument().getNewMaintainableObject().getDataObject();
948 
949         //Compare CO to CLU and display info message
950         if (ruleEditor.getProposition() != null) {
951             if (!this.getViewHelper(form).compareRules(ruleWrapper.getRuleEditor())) {
952                 GlobalVariables.getMessageMap().putInfoForSectionId(KRMSConstants.KRMS_RULE_TREE_GROUP_ID, "info.krms.tree.rule.changed");
953             } else if (GlobalVariables.getMessageMap().containsMessageKey(KRMSConstants.KRMS_RULE_TREE_GROUP_ID)) {
954                 GlobalVariables.getMessageMap().removeAllInfoMessagesForProperty(KRMSConstants.KRMS_RULE_TREE_GROUP_ID);
955             }
956         }
957     }
958 
959     /**
960      * Updates rule and redirects to agenda maintenance page.
961      *
962      * @param form
963      * @param result
964      * @param request
965      * @param response
966      * @return
967      * @throws Exception
968      */
969     @RequestMapping(params = "methodToCall=updateRule")
970     public ModelAndView updateRule(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
971                                    HttpServletRequest request, HttpServletResponse response)
972             throws Exception {
973 
974         RuleEditor ruleEditor = getRuleEditor(form);
975 
976         //Return with error message if user is currently editing a proposition.
977         PropositionEditor proposition = PropositionTreeUtil.getProposition(ruleEditor);
978         if ((proposition!=null) && (proposition.isEditMode())) {
979             GlobalVariables.getMessageMap().putErrorForSectionId(KRMSConstants.KRMS_PROPOSITION_DETAILSECTION_ID, KRMSConstants.KRMS_MSG_ERROR_RULE_PREVIEW);
980             return getUIFModelAndView(form);
981         }
982 
983         if (!(ruleEditor.getProposition() == null && ruleEditor.getPropId() == null)) {
984             PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
985             ruleEditor.setDummy(false);
986             PropositionTreeUtil.resetNewProp(ruleEditor.getPropositionEditor());
987         }
988         this.getViewHelper(form).refreshViewTree(ruleEditor);
989 
990         //Replace edited rule with existing rule.
991         RuleManagementWrapper ruleWrapper = AgendaUtilities.getRuleWrapper((MaintenanceDocumentForm) form);
992         AgendaEditor agendaEditor = AgendaUtilities.getSelectedAgendaEditor(ruleWrapper, ruleEditor.getKey());
993         agendaEditor.getRuleEditors().put(ruleEditor.getKey(), ruleEditor);
994 
995         if (!form.getActionParameters().containsKey(UifParameters.NAVIGATE_TO_PAGE_ID)) {
996             form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, KRMSConstants.KRMS_AGENDA_MAINTENANCE_PAGE_ID);
997         }
998         return super.navigate(form, result, request, response);
999     }
1000 
1001     /**
1002      * Updates view with changed logic expressions.
1003      * Also does validation and displays necessary messages on view.
1004      *
1005      * @param form
1006      * @param result
1007      * @param request
1008      * @param response
1009      * @return
1010      * @throws Exception
1011      */
1012     @RequestMapping(params = "methodToCall=updatePreview")
1013     public ModelAndView updatePreview(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1014                                       HttpServletRequest request, HttpServletResponse response)
1015             throws Exception {
1016         RuleEditor ruleEditor = getRuleEditor(form);
1017         parseRuleExpression(ruleEditor, this.getViewHelper(form));
1018 
1019         //Clear new collection lines to remove new collection add line only for edit tree
1020         if (form.getNewCollectionLines().size() != 1) {
1021             List<String> keys = new ArrayList<String>(form.getNewCollectionLines().keySet());
1022             for (String key : keys) {
1023                 if (key.contains(PropositionTreeUtil.EDIT_TREE_NEW_COLLECTION_LINE)) {
1024                     form.getNewCollectionLines().remove(key);
1025                 }
1026             }
1027         }
1028 
1029         this.getViewHelper(form).refreshInitTrees(ruleEditor);
1030         return getUIFModelAndView(form);
1031     }
1032 
1033     /**
1034      * Validation for logic expression.
1035      *
1036      * @param ruleEditor
1037      */
1038     private void parseRuleExpression(RuleEditor ruleEditor, RuleViewHelperService viewHelper) {
1039         RuleLogicExpressionParser ruleLogicExpressionParser = new RuleLogicExpressionParser();
1040         ruleLogicExpressionParser.setExpression(ruleEditor.getLogicArea());
1041         List<String> propsAlpha = this.getPropositionKeys(new ArrayList<String>(), ruleEditor.getPropositionEditor());
1042 
1043         //validate the expression
1044         List<String> errorMessages = new ArrayList<String>();
1045         boolean validExpression = ruleLogicExpressionParser.validateExpression(errorMessages, propsAlpha);
1046 
1047         //show errors and don't change anything else
1048         if (!validExpression) {
1049             for (int i = 0; i < errorMessages.size(); i++) {
1050                 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.dataObject.logicArea", errorMessages.get(i));
1051             }
1052             // reload page1
1053             return;
1054         }
1055 
1056         ruleEditor.setProposition(ruleLogicExpressionParser.parseExpressionIntoRule(ruleEditor, viewHelper));
1057     }
1058 
1059     /**
1060      * Returns list of proposition keys.
1061      *
1062      * @param propositionKeys
1063      * @param propositionEditor
1064      * @return
1065      */
1066     private List<String> getPropositionKeys(List<String> propositionKeys, PropositionEditor propositionEditor) {
1067         propositionKeys.add(propositionEditor.getKey());
1068         if (propositionEditor.getCompoundComponents() != null) {
1069             for (PropositionEditor child : propositionEditor.getCompoundEditors()) {
1070                 this.getPropositionKeys(propositionKeys, child);
1071             }
1072         }
1073         return propositionKeys;
1074     }
1075 
1076     /**
1077      * Reverts rule to previous state and refreshes view.
1078      *
1079      * @param form
1080      * @param result
1081      * @param request
1082      * @param response
1083      * @return
1084      * @throws Exception
1085      */
1086     @RequestMapping(params = "methodToCall=cancelEditProposition")
1087     public ModelAndView cancelEditProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1088                                               HttpServletRequest request, HttpServletResponse response)
1089             throws Exception {
1090 
1091         RuleEditor ruleEditor = getRuleEditor(form);
1092         PropositionEditor root = ruleEditor.getPropositionEditor();
1093 
1094         //If first root and not yet updated, clear rule root
1095         if (root.isNewProp() && root.isEditMode()) {
1096             ruleEditor.reset();
1097         } else {
1098             PropositionTreeUtil.cancelNewProp(root);
1099             PropositionTreeUtil.removeCompoundProp(ruleEditor);
1100 
1101             ruleEditor.setSelectedKey(StringUtils.EMPTY);
1102             PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
1103         }
1104 
1105         //Clear new collection lines to remove new collection add line only for edit tree
1106         if (form.getNewCollectionLines().size() != 1) {
1107             List<String> keys = new ArrayList<String>(form.getNewCollectionLines().keySet());
1108             for (String key : keys) {
1109                 if (key.contains(PropositionTreeUtil.EDIT_TREE_NEW_COLLECTION_LINE)) {
1110                     form.getNewCollectionLines().remove(key);
1111                 }
1112             }
1113         }
1114 
1115         this.getViewHelper(form).refreshInitTrees(ruleEditor);
1116 
1117         //Compare rule with parent rule.
1118         compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
1119 
1120         return getUIFModelAndView(form);
1121     }
1122 
1123     /**
1124      * Reverts rule to previous state and navigates to agenda maintenance page.
1125      *
1126      * @param form
1127      * @param result
1128      * @param request
1129      * @param response
1130      * @return
1131      * @throws Exception
1132      */
1133     @RequestMapping(params = "methodToCall=cancelEditRule")
1134     public ModelAndView cancelEditRule(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1135                                        HttpServletRequest request, HttpServletResponse response)
1136             throws Exception {
1137 
1138         RuleEditor ruleEditor = getRuleEditor(form);
1139         PropositionEditor proposition = ruleEditor.getPropositionEditor();
1140 
1141         //Reset the editing tree.
1142         if (proposition != null) {
1143             PropositionTreeUtil.cancelNewProp(proposition);
1144         }
1145         PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
1146 
1147         if (!form.getActionParameters().containsKey(UifParameters.NAVIGATE_TO_PAGE_ID)) {
1148             form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, KRMSConstants.KRMS_AGENDA_MAINTENANCE_PAGE_ID);
1149         }
1150         return super.navigate(form, result, request, response);
1151     }
1152 
1153     /**
1154      * Updates proposition type and reloads view.
1155      *
1156      * @param form
1157      * @param result
1158      * @param request
1159      * @param response
1160      * @return
1161      * @throws Exception
1162      */
1163     @RequestMapping(params = "methodToCall=updatePropositionType")
1164     public ModelAndView updatePropositionType(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1165                                               HttpServletRequest request, HttpServletResponse response)
1166             throws Exception {
1167 
1168         PropositionEditor proposition = PropositionTreeUtil.getProposition(this.getRuleEditor(form));
1169         proposition.clear();
1170         this.getViewHelper(form).configurePropositionForType(proposition);
1171 
1172         return getUIFModelAndView(form);
1173     }
1174 
1175     /**
1176      * Test method for a controller that invokes a dialog lightbox.
1177      *
1178      * @param form     - test form
1179      * @param result   - Spring form binding result
1180      * @param request  - http request
1181      * @param response - http response
1182      * @return
1183      * @throws Exception
1184      */
1185     @RequestMapping(params = "methodToCall=compareRules")
1186     public ModelAndView compareRules(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1187                                      HttpServletRequest request, HttpServletResponse response) throws Exception {
1188 
1189         doCompareRules(form);
1190 
1191         // redirect back to client to display lightbox
1192         return showDialog(KRMSConstants.KSKRMS_DIALOG_COMPARE, form, request, response);
1193     }
1194 
1195     protected void doCompareRules(UifFormBase form) throws Exception {
1196         MaintenanceDocumentForm document = (MaintenanceDocumentForm) form;
1197         Object dataObject = document.getDocument().getNewMaintainableObject().getDataObject();
1198         if (dataObject instanceof RuleManagementWrapper) {
1199             RuleManagementWrapper ruleWrapper = (RuleManagementWrapper) dataObject;
1200             String ruleId = document.getActionParamaterValue(KRMSConstants.KRMS_PARM_RULE_KEY);
1201             RuleEditor ruleEditor = null;
1202             if ((ruleId != null) && (StringUtils.isNotBlank(ruleId))) {
1203                 //Get a specific ruleEditor based on the ruleId.
1204                 ruleEditor = AgendaUtilities.getSelectedRuleEditor(ruleWrapper, ruleId);
1205             } else {
1206                 //Get the current editing ruleEditor.
1207                 ruleEditor = ruleWrapper.getRuleEditor();
1208             }
1209 
1210             //Build the compare rule tree
1211             ruleWrapper.setCompareTree(this.getViewHelper(form).buildCompareTree(ruleEditor, ruleEditor.getParent()));
1212             ruleWrapper.setCompareLightBoxHeader(ruleEditor.getRuleTypeInfo().getDescription());
1213         }
1214     }
1215 
1216     /**
1217      * Returns form's view helper serivce.
1218      *
1219      * @param form
1220      * @return
1221      */
1222     protected RuleViewHelperService getViewHelper(UifFormBase form) {
1223         return (RuleViewHelperService) KSControllerHelper.getViewHelperService(form);
1224     }
1225 
1226     /**
1227      * Retrieves selected proposition key and initializes edit on propostion.
1228      *
1229      * @param form
1230      * @param result
1231      * @param request
1232      * @param response
1233      * @return
1234      * @throws Exception
1235      */
1236     @RequestMapping(params = "methodToCall=getSelectedKey")
1237     public ModelAndView getSelectedKey(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1238                                        HttpServletRequest request, HttpServletResponse response) throws Exception {
1239 
1240         //Clear the current states of the tabs to open the first tab again with the edit tree.
1241         Map<String, String> states = (Map<String, String>) form.getClientStateForSyncing().get(KRMSConstants.KRMS_RULE_TABS_ID);
1242         states.put(KRMSConstants.KRMS_PARM_ACTIVE_TAB, KRMSConstants.KRMS_RULE_EDITWITHOBJECT_ID);
1243 
1244         //Set the selected rule statement key.
1245         String selectedKey = request.getParameter(KRMSConstants.KRMS_PARM_SELECTED_KEY);
1246         getRuleEditor(form).setSelectedKey(selectedKey);
1247 
1248         return this.goToEditProposition(form, result, request, response);
1249     }
1250 
1251 }