View Javadoc

1   /**
2    * Copyright 2005-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krms.service.impl;
17  
18  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
19  import org.kuali.rice.core.api.util.tree.Node;
20  import org.kuali.rice.core.api.util.tree.Tree;
21  import org.kuali.rice.krad.bo.Note;
22  import org.kuali.rice.krad.maintenance.MaintenanceDocument;
23  import org.kuali.rice.krad.uif.container.CollectionGroup;
24  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
25  import org.kuali.rice.krad.uif.view.View;
26  import org.kuali.rice.krad.util.KRADConstants;
27  import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
28  import org.kuali.rice.krms.api.KrmsConstants;
29  import org.kuali.rice.krms.api.repository.RuleManagementService;
30  import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
31  import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition;
32  import org.kuali.rice.krms.api.repository.agenda.AgendaTreeDefinition;
33  import org.kuali.rice.krms.api.repository.agenda.AgendaTreeEntryDefinitionContract;
34  import org.kuali.rice.krms.api.repository.agenda.AgendaTreeRuleEntry;
35  import org.kuali.rice.krms.api.repository.proposition.PropositionType;
36  import org.kuali.rice.krms.api.repository.rule.RuleDefinition;
37  import org.kuali.rice.krms.api.repository.term.TermDefinition;
38  import org.kuali.rice.krms.api.repository.term.TermRepositoryService;
39  import org.kuali.rice.krms.api.repository.term.TermResolverDefinition;
40  import org.kuali.rice.krms.api.repository.term.TermSpecificationDefinition;
41  import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
42  import org.kuali.rice.krms.api.repository.type.KrmsTypeRepositoryService;
43  import org.kuali.rice.krms.dto.AgendaEditor;
44  import org.kuali.rice.krms.dto.PropositionEditor;
45  import org.kuali.rice.krms.dto.PropositionParameterEditor;
46  import org.kuali.rice.krms.dto.RuleEditor;
47  import org.kuali.rice.krms.dto.RuleManagementWrapper;
48  import org.kuali.rice.krms.dto.TemplateInfo;
49  import org.kuali.rice.krms.dto.TermEditor;
50  import org.kuali.rice.krms.dto.TermParameterEditor;
51  import org.kuali.rice.krms.builder.ComponentBuilder;
52  import org.kuali.rice.krms.service.TemplateRegistry;
53  import org.kuali.rice.krms.tree.RuleCompareTreeBuilder;
54  import org.kuali.rice.krms.tree.RuleViewTreeBuilder;
55  import org.kuali.rice.krms.tree.node.RuleEditorTreeNode;
56  import org.kuali.rice.krms.service.RuleEditorMaintainable;
57  import org.kuali.student.enrollment.class1.krms.dto.EnrolRuleManagementWrapper;
58  import org.kuali.student.enrollment.class2.courseoffering.service.decorators.PermissionServiceConstants;
59  import org.kuali.rice.krms.util.PropositionTreeUtil;
60  import org.kuali.student.enrollment.uif.service.impl.KSMaintainableImpl;
61  import org.kuali.student.r2.common.dto.ContextInfo;
62  
63  import javax.xml.namespace.QName;
64  import java.util.ArrayList;
65  import java.util.Collection;
66  import java.util.HashMap;
67  import java.util.List;
68  import java.util.Map;
69  
70  /**
71   * {@link org.kuali.rice.krad.maintenance.Maintainable} for the {@link org.kuali.rice.krms.impl.ui.AgendaEditor}
72   *
73   * @author Kuali Rice Team (rice.collab@kuali.org)
74   */
75  public class RuleEditorMaintainableImpl extends KSMaintainableImpl implements RuleEditorMaintainable {
76  
77      private static final long serialVersionUID = 1L;
78  
79      private transient RuleManagementService ruleManagementService;
80      private transient KrmsTypeRepositoryService krmsTypeRepositoryService;
81      private transient TermRepositoryService termRepositoryService;
82  
83      private transient ContextInfo contextInfo;
84      private transient TemplateRegistry templateRegistry;
85  
86      public static final String NEW_AGENDA_EDITOR_DOCUMENT_TEXT = "New Agenda Editor Document";
87  
88      /**
89       * Get the AgendaEditor out of the MaintenanceDocumentForm's newMaintainableObject
90       *
91       * @param model the MaintenanceDocumentForm
92       * @return the AgendaEditor
93       */
94      private RuleEditor getRuleEditor(Object model) {
95          MaintenanceDocumentForm maintenanceDocumentForm = (MaintenanceDocumentForm) model;
96          return (RuleEditor) maintenanceDocumentForm.getDocument().getNewMaintainableObject().getDataObject();
97      }
98  
99      @Override
100     public Object retrieveObjectForEditOrCopy(MaintenanceDocument document, Map<String, String> dataObjectKeys) {
101         EnrolRuleManagementWrapper dataObject = new EnrolRuleManagementWrapper();
102 
103         List<AgendaEditor> agendas = new ArrayList<AgendaEditor>();
104         dataObject.setAgendas(agendas);
105 
106         String coId = dataObjectKeys.get("refObjectId");
107         dataObject.setRefObjectId(coId);
108 
109         dataObject.setCompareTree(RuleCompareTreeBuilder.initCompareTree());
110 
111         return dataObject;
112     }
113 
114     protected AgendaEditor getAgendaEditor(String agendaId) {
115         AgendaDefinition agenda = this.getRuleManagementService().getAgenda(agendaId);
116         AgendaEditor agendaEditor = new AgendaEditor(agenda);
117 
118         AgendaTreeDefinition agendaTree = this.getRuleManagementService().getAgendaTree(agendaId);
119         agendaEditor.setRuleEditors(getRuleEditorsFromTree(agendaTree.getEntries()));
120 
121         return agendaEditor;
122     }
123 
124     protected List<RuleEditor> getRuleEditorsFromTree(List<AgendaTreeEntryDefinitionContract> agendaTreeEntries) {
125 
126         RuleViewTreeBuilder viewTreeBuilder = new RuleViewTreeBuilder();
127         viewTreeBuilder.setRuleManagementService(this.getRuleManagementService());
128         List<RuleEditor> rules = new ArrayList<RuleEditor>();
129         for (AgendaTreeEntryDefinitionContract treeEntry : agendaTreeEntries) {
130             if (treeEntry instanceof AgendaTreeRuleEntry) {
131                 AgendaTreeRuleEntry treeRuleEntry = (AgendaTreeRuleEntry) treeEntry;
132                 AgendaItemDefinition agendaItem = this.getRuleManagementService().getAgendaItem(treeEntry.getAgendaItemId());
133 
134                 if (agendaItem.getRuleId() != null) {
135                     RuleDefinition rule = this.getRuleManagementService().getRule(treeRuleEntry.getRuleId());
136                     RuleEditor ruleEditor = new RuleEditor(rule);
137                     this.initPropositionEditor((PropositionEditor) ruleEditor.getProposition());
138                     ruleEditor.setViewTree(viewTreeBuilder.buildTree(ruleEditor));
139                     rules.add(ruleEditor);
140                 }
141 
142                 if (treeRuleEntry.getIfTrue() != null) {
143                     rules.addAll(getRuleEditorsFromTree(treeRuleEntry.getIfTrue().getEntries()));
144                 }
145             }
146         }
147         return rules;
148     }
149 
150     /**
151      * {@inheritDoc}
152      */
153     @Override
154     public void processAfterNew(MaintenanceDocument document, Map<String, String[]> requestParameters) {
155         super.processAfterNew(document, requestParameters);
156         document.getDocumentHeader().setDocumentDescription(NEW_AGENDA_EDITOR_DOCUMENT_TEXT);
157     }
158 
159     @Override
160     public void processAfterEdit(MaintenanceDocument document, Map<String, String[]> requestParameters) {
161         super.processAfterEdit(document, requestParameters);
162         document.getDocumentHeader().setDocumentDescription("Modify Agenda Editor Document");
163     }
164 
165     @Override
166     public void saveDataObject() {
167         RuleManagementWrapper ruleWrapper = (RuleManagementWrapper) getDataObject();
168 
169         for (AgendaEditor agenda : ruleWrapper.getAgendas()){
170 
171             List<RuleEditor> deleteRuleList = new ArrayList<RuleEditor>();
172             for(RuleEditor rule : agenda.getRuleEditors()) {
173                 if(!rule.isDummy()) {
174                     this.finRule(rule, ruleWrapper.getNamePrefix(), ruleWrapper.getNamespace());
175                 } else {
176                     deleteRuleList.add(rule);
177                 }
178             }
179             agenda.getRuleEditors().removeAll(deleteRuleList);
180 
181             AgendaDefinition.Builder agendaBuilder = null;
182             AgendaDefinition agendaDefinition = null;
183             if(agenda.getId() == null) {
184                 agendaBuilder = AgendaDefinition.Builder.create(agenda);
185                 agendaDefinition = agendaBuilder.build();
186             }
187 
188             if(agenda.getRuleEditors().size() == 0) {
189                 for(String deletedRuleId : ruleWrapper.getDeletedRuleIds()) {
190                     this.getRuleManagementService().deleteAgendaItem(deletedRuleId);
191                 }
192                 this.getRuleManagementService().deleteReferenceObjectBinding(agenda.getId());
193                 this.getRuleManagementService().deleteAgenda(agenda.getId());
194             } else {
195                 if(agendaDefinition == null) {
196                     agendaBuilder = AgendaDefinition.Builder.create(agenda);
197                     agendaDefinition = agendaBuilder.build();
198                 }
199                 this.getRuleManagementService().updateAgenda(agendaDefinition);
200             }
201         }
202 
203     }
204 
205     protected void finRule(RuleEditor rule, String rulePrefix, String namespace) {
206         // handle saving new parameterized terms
207         PropositionEditor proposition = (PropositionEditor) rule.getProposition();
208         if (proposition != null) {
209             this.finPropositionEditor(proposition);
210         }
211 
212         if(rule.getName() == null) {
213             rule.setName(rulePrefix + " " + rule.getDescription());
214         }
215         if(rule.getNamespace() == null) {
216             rule.setNamespace(namespace);
217         }
218 
219         RuleDefinition.Builder ruleBuilder = RuleDefinition.Builder.create(rule);
220         RuleDefinition ruleDefinition = ruleBuilder.build();
221         if (ruleDefinition.getId() == null) {
222             this.getRuleManagementService().createRule(ruleDefinition);
223         } else {
224             this.getRuleManagementService().updateRule(ruleDefinition);
225         }
226     }
227 
228     protected void finPropositionEditor(PropositionEditor propositionEditor) {
229         if (PropositionType.SIMPLE.getCode().equalsIgnoreCase(propositionEditor.getPropositionTypeCode())) {
230 
231             //Save term and set termid.
232             String termId = this.saveTerm(propositionEditor);
233             if (propositionEditor.getParameters().get(0) != null) {
234                 propositionEditor.getParameters().get(0).setValue(termId);
235             }
236 
237             //Set the default operation and value
238             TemplateInfo template = this.getTemplateRegistry().getTemplateForType(propositionEditor.getType());
239             propositionEditor.getParameters().get(2).setValue(template.getOperator());
240 
241             if (!"n".equals(template.getValue())) {
242                 propositionEditor.getParameters().get(1).setValue(template.getValue());
243             }
244 
245         } else {
246 
247             //If not a simple node, recursively finalize the child proposition editors.
248             for (PropositionEditor child : propositionEditor.getCompoundEditors()) {
249                 finPropositionEditor(child);
250             }
251 
252         }
253     }
254 
255     protected String saveTerm(PropositionEditor propositionEditor) {
256 
257         //Set the termSpecification based on current type.
258         TermEditor term = propositionEditor.getTerm();
259         term.setSpecification(this.getTermSpecForType(propositionEditor.getType()));
260 
261         TermDefinition.Builder termBuilder = TermDefinition.Builder.create(term);
262         TermDefinition termDefinition = termBuilder.build();
263         if (term.getId() == null) {
264             termDefinition = this.getTermRepositoryService().createTerm(termDefinition);
265 
266         } else {
267             this.getTermRepositoryService().updateTerm(termDefinition);
268         }
269 
270         return termDefinition.getId();
271     }
272 
273     protected TermSpecificationDefinition getTermSpecForType(String type) {
274 
275         //Get the term output name for this type.
276         String termSpecName = this.getTemplateRegistry().getTermSpecNameForType(type);
277 
278         List<TermResolverDefinition> matchingTermResolvers = this.getTermRepositoryService().findTermResolversByNamespace(PermissionServiceConstants.KS_SYS_NAMESPACE);
279         for (TermResolverDefinition termResolver : matchingTermResolvers) {
280             TermSpecificationDefinition termSpec = termResolver.getOutput();
281             if (termSpec.getName().equals(termSpecName)) {
282                 return termSpec;
283             }
284         }
285 
286         return null;
287     }
288 
289     protected void initPropositionEditor(PropositionEditor propositionEditor) {
290         if (PropositionType.SIMPLE.getCode().equalsIgnoreCase(propositionEditor.getPropositionTypeCode())) {
291 
292             if (propositionEditor.getType() == null) {
293                 KrmsTypeDefinition type = this.getKrmsTypeRepositoryService().getTypeById(propositionEditor.getTypeId());
294                 propositionEditor.setType(type.getName());
295             }
296 
297             Map<String, String> termParameters = this.getTermParameters(propositionEditor);
298             ComponentBuilder builder = this.getTemplateRegistry().getComponentBuilderForType(propositionEditor.getType());
299             if (builder != null) {
300                 builder.resolveTermParameters(propositionEditor, termParameters);
301             }
302         } else {
303             for (PropositionEditor child : propositionEditor.getCompoundEditors()) {
304                 initPropositionEditor(child);
305             }
306 
307         }
308     }
309 
310     protected Map<String, String> getTermParameters(PropositionEditor proposition) {
311 
312         Map<String, String> termParameters = new HashMap<String, String>();
313         if (proposition.getTerm() == null) {
314             if (proposition.getParameters().get(0) != null) {
315 
316                 PropositionParameterEditor termParameter = proposition.getParameters().get(0);
317                 if (termParameter.getTermValue() == null){
318                     String termId = proposition.getParameters().get(0).getValue();
319                     termParameter.setTermValue(this.getTermRepositoryService().getTerm(termId));
320                 }
321                 proposition.setTerm(new TermEditor(termParameter.getTermValue()));
322             } else {
323                 return termParameters;
324             }
325         }
326 
327         for (TermParameterEditor parameter : proposition.getTerm().getEditorParameters()) {
328             termParameters.put(parameter.getName(), parameter.getValue());
329         }
330 
331         return termParameters;
332     }
333 
334     /**
335      * In the case of edit maintenance adds a new blank line to the old side
336      * <p/>
337      * TODO: should this write some sort of missing message on the old side
338      * instead?
339      *
340      * @see org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl#processAfterAddLine(org.kuali.rice.krad.uif.view.View,
341      *      org.kuali.rice.krad.uif.container.CollectionGroup, Object,
342      *      Object)
343      */
344     @Override
345     protected void processAfterAddLine(View view, CollectionGroup collectionGroup, Object model, Object addLine) {
346         // Check for maintenance documents in edit but exclude notes
347         if (model instanceof MaintenanceDocumentForm && KRADConstants.MAINTENANCE_EDIT_ACTION.equals(((MaintenanceDocumentForm) model).getMaintenanceAction()) && !(addLine instanceof Note)) {
348             MaintenanceDocumentForm maintenanceDocumentForm = (MaintenanceDocumentForm) model;
349             MaintenanceDocument document = maintenanceDocumentForm.getDocument();
350 
351             // Figure out which rule is being edited
352             RuleEditor rule = getRuleEditor(model);
353             // Figure out which proposition is being edited
354             Tree<RuleEditorTreeNode, String> propositionTree = rule.getEditTree();
355             Node<RuleEditorTreeNode, String> editedPropositionNode = PropositionTreeUtil.findEditedProposition(propositionTree.getRootElement());
356 
357             // get the old object's collection
358             Collection<Object> oldCollection = ObjectPropertyUtils
359                     .getPropertyValue(editedPropositionNode.getData(),
360                             collectionGroup.getPropertyName());
361 
362             try {
363                 Object blankLine = collectionGroup.getCollectionObjectClass().newInstance();
364                 //Add a blank line to the top of the collection
365                 if (oldCollection instanceof List) {
366                     ((List) oldCollection).add(0, blankLine);
367                 } else {
368                     oldCollection.add(blankLine);
369                 }
370             } catch (Exception e) {
371                 throw new RuntimeException("Unable to create new line instance for old maintenance object", e);
372             }
373         }
374     }
375 
376     public RuleManagementService getRuleManagementService() {
377         if (ruleManagementService == null) {
378             ruleManagementService = (RuleManagementService) GlobalResourceLoader.getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "ruleManagementService"));
379         }
380         return ruleManagementService;
381     }
382 
383     public KrmsTypeRepositoryService getKrmsTypeRepositoryService() {
384         if (krmsTypeRepositoryService == null) {
385             krmsTypeRepositoryService = (KrmsTypeRepositoryService) GlobalResourceLoader.getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "krmsTypeRepositoryService"));
386         }
387         return krmsTypeRepositoryService;
388     }
389 
390     public TermRepositoryService getTermRepositoryService() {
391         if (termRepositoryService == null) {
392             termRepositoryService = (TermRepositoryService) GlobalResourceLoader.getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "termRepositoryService"));
393         }
394         return termRepositoryService;
395     }
396 
397     private TemplateRegistry getTemplateRegistry() {
398         if (templateRegistry == null) {
399             templateRegistry = (TemplateRegistry) GlobalResourceLoader.getService(QName.valueOf("templateResolverMockService"));
400         }
401         return templateRegistry;
402     }
403 }