View Javadoc
1   /**
2    * Copyright 2005-2015 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.impl.repository;
17  
18  import java.io.Serializable;
19  import java.util.ArrayList;
20  import java.util.List;
21  import java.util.Map;
22  
23  import javax.persistence.CascadeType;
24  import javax.persistence.Column;
25  import javax.persistence.Entity;
26  import javax.persistence.FetchType;
27  import javax.persistence.GeneratedValue;
28  import javax.persistence.Id;
29  import javax.persistence.JoinColumn;
30  import javax.persistence.ManyToOne;
31  import javax.persistence.Table;
32  import javax.persistence.Transient;
33  import javax.persistence.Version;
34  
35  import org.apache.commons.collections.CollectionUtils;
36  import org.apache.commons.lang.StringUtils;
37  import org.eclipse.persistence.annotations.OptimisticLocking;
38  import org.kuali.rice.core.api.mo.common.Versioned;
39  import org.kuali.rice.krad.data.CopyOption;
40  import org.kuali.rice.krad.data.DataObjectService;
41  import org.kuali.rice.krad.data.KradDataServiceLocator;
42  import org.kuali.rice.krad.data.jpa.PortableSequenceGenerator;
43  import org.kuali.rice.krms.api.repository.agenda.AgendaDefinitionContract;
44  import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition;
45  import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinitionContract;
46  import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
47  import org.kuali.rice.krms.api.repository.type.KrmsTypeRepositoryService;
48  
49  /**
50   * Agenda Item business object
51   *
52   * @author Kuali Rice Team (rice.collab@kuali.org)
53   *
54   */
55  @Entity
56  @Table(name = "KRMS_AGENDA_ITM_T")
57  @OptimisticLocking(cascade = true)
58  public class AgendaItemBo implements AgendaItemDefinitionContract, Versioned, Serializable {
59  
60      private static final long serialVersionUID = 1L;
61  
62      public static final String COPY_OF_TEXT = "Copy of ";
63  
64      public static final String AGENDA_ITEM_SEQ_NAME = "KRMS_AGENDA_ITM_S";
65  
66      static RepositoryBoIncrementer agendaItemIdIncrementer = new RepositoryBoIncrementer(AGENDA_ITEM_SEQ_NAME);
67  
68      @Transient
69      private transient DataObjectService dataObjectService = null;
70      @Transient
71      private transient KrmsTypeRepositoryService krmsTypeRepositoryService = null;
72  
73      @PortableSequenceGenerator(name = AGENDA_ITEM_SEQ_NAME)
74      @GeneratedValue(generator = AGENDA_ITEM_SEQ_NAME)
75      @Id
76      @Column(name = "AGENDA_ITM_ID")
77      private String id;
78  
79      @Column(name = "AGENDA_ID")
80      private String agendaId;
81  
82      @Column(name = "SUB_AGENDA_ID")
83      private String subAgendaId;
84  
85      @Column(name = "WHEN_TRUE", insertable = false, updatable = false)
86      private String whenTrueId;
87  
88      @Column(name = "WHEN_FALSE", insertable = false, updatable = false)
89      private String whenFalseId;
90  
91      @Column(name = "ALWAYS", insertable = false, updatable = false)
92      private String alwaysId;
93  
94      @ManyToOne(targetEntity = RuleBo.class, fetch = FetchType.LAZY, cascade = { CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE, CascadeType.PERSIST})
95      @JoinColumn(name = "RULE_ID", referencedColumnName = "RULE_ID")
96      private RuleBo rule;
97  
98      @Column(name = "VER_NBR")
99      @Version
100     private Long versionNumber;
101 
102     @ManyToOne(targetEntity = AgendaItemBo.class, cascade = { CascadeType.REFRESH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE })
103     @JoinColumn(name = "WHEN_TRUE", referencedColumnName = "AGENDA_ITM_ID")
104     private AgendaItemBo whenTrue;
105 
106     @ManyToOne(targetEntity = AgendaItemBo.class, cascade = { CascadeType.REFRESH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE })
107     @JoinColumn(name = "WHEN_FALSE", referencedColumnName = "AGENDA_ITM_ID")
108     private AgendaItemBo whenFalse;
109 
110     @ManyToOne(targetEntity = AgendaItemBo.class, cascade = { CascadeType.REFRESH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE })
111     @JoinColumn(name = "ALWAYS", referencedColumnName = "AGENDA_ITM_ID")
112     private AgendaItemBo always;
113 
114     public String getUl(AgendaItemBo firstItem) {
115         return ("<ul>" + getUlHelper(firstItem) + "</ul>");
116     }
117 
118     public String getUlHelper(AgendaItemBo item) {
119         StringBuilder sb = new StringBuilder();
120         sb.append("<li>" + getRuleId() + "</li>");
121 
122         if (whenTrue != null) {
123             sb.append("<ul><li>when true</li><ul>");
124             sb.append(getUlHelper(whenTrue));
125             sb.append("</ul></ul>");
126         }
127         if (whenFalse != null) {
128             sb.append("<ul><li>when false</li><ul>");
129             sb.append(getUlHelper(whenFalse));
130             sb.append("</ul></ul>");
131         }
132         if (always != null) {
133             sb.append(getUlHelper(always));
134         }
135 
136         return sb.toString();
137     }
138 
139     public String getRuleText() {
140         StringBuilder resultBuilder = new StringBuilder();
141         if (getRule() != null) {
142             if (StringUtils.isBlank(getRule().getName())) {
143                 resultBuilder.append("- unnamed rule -");
144             } else {
145                 resultBuilder.append(getRule().getName());
146             }
147             if (!StringUtils.isBlank(getRule().getDescription())) {
148                 resultBuilder.append(": ");
149                 resultBuilder.append(getRule().getDescription());
150             }
151 
152             // add a description of the action configured on the rule, if there is one
153             if (!CollectionUtils.isEmpty(getRule().getActions())) {
154                 resultBuilder.append("   [");
155                 ActionBo action = getRule().getActions().get(0);
156                 KrmsTypeDefinition krmsTypeDefn = getKrmsTypeRepositoryService().getTypeById(action.getTypeId());
157                 resultBuilder.append(krmsTypeDefn.getName());
158                 resultBuilder.append(": ");
159                 resultBuilder.append(action.getName());
160 
161                 if (getRule().getActions().size() > 1) {
162                     resultBuilder.append(" ... ");
163                 }
164 
165                 resultBuilder.append("]");
166             }
167         } else {
168             throw new IllegalStateException();
169         }
170 
171         return resultBuilder.toString();
172     }
173 
174     public List<AgendaItemBo> getAlwaysList() {
175         List<AgendaItemBo> results = new ArrayList<AgendaItemBo>();
176         AgendaItemBo currentNode = this;
177 
178         while (currentNode.always != null) {
179             results.add(currentNode.always);
180             currentNode = currentNode.always;
181         }
182 
183         return results;
184     }
185 
186     /**
187      * @return the id
188      */
189     @Override
190     public String getId() {
191         return this.id;
192     }
193 
194     /**
195      * @param id the id to set
196      */
197     public void setId(String id) {
198         this.id = id;
199     }
200 
201     /**
202      * @return the agendaId
203      */
204     @Override
205     public String getAgendaId() {
206         return this.agendaId;
207     }
208 
209     /**
210      * @param agendaId the agendaId to set
211      */
212     public void setAgendaId(String agendaId) {
213         this.agendaId = agendaId;
214     }
215 
216     /**
217      * @return the ruleId
218      */
219     @Override
220     public String getRuleId() {
221         if (rule != null) {
222             return rule.getId();
223         }
224 
225         return null;
226     }
227 
228     /**
229      * @return the subAgendaId
230      */
231     @Override
232     public String getSubAgendaId() {
233         return this.subAgendaId;
234     }
235 
236     /**
237      * @param subAgendaId the subAgendaId to set
238      */
239     public void setSubAgendaId(String subAgendaId) {
240         this.subAgendaId = subAgendaId;
241     }
242 
243     /**
244      * @return the whenTrueId
245      */
246     @Override
247     public String getWhenTrueId() {
248         return this.whenTrueId;
249     }
250 
251     /**
252      * @param whenTrueId the whenTrueId to set
253      */
254     public void setWhenTrueId(String whenTrueId) {
255         this.whenTrueId = whenTrueId;
256     }
257 
258     /**
259      * @return the whenFalseId
260      */
261     @Override
262     public String getWhenFalseId() {
263         return this.whenFalseId;
264     }
265 
266     /**
267      * @param whenFalseId the whenFalseId to set
268      */
269     public void setWhenFalseId(String whenFalseId) {
270         this.whenFalseId = whenFalseId;
271     }
272 
273     /**
274      * @return the alwaysId
275      */
276     @Override
277     public String getAlwaysId() {
278         return this.alwaysId;
279     }
280 
281     /**
282      * @param alwaysId the alwaysId to set
283      */
284     public void setAlwaysId(String alwaysId) {
285         this.alwaysId = alwaysId;
286     }
287 
288     @Override
289     public Long getVersionNumber() {
290         return versionNumber;
291     }
292 
293     public void setVersionNumber(Long versionNumber) {
294         this.versionNumber = versionNumber;
295     }
296 
297     /**
298      * @return the whenTrue
299      */
300     @Override
301     public AgendaItemBo getWhenTrue() {
302         return this.whenTrue;
303     }
304 
305     /**
306      * @param whenTrue the whenTrue to set
307      */
308     public void setWhenTrue(AgendaItemBo whenTrue) {
309         this.whenTrue = whenTrue;
310 
311         if (whenTrue != null) {
312             setWhenTrueId(whenTrue.getId());
313         } else {
314             setWhenTrueId(null);
315         }
316     }
317 
318     /**
319      * @return the whenFalse
320      */
321     @Override
322     public AgendaItemBo getWhenFalse() {
323         return this.whenFalse;
324     }
325 
326     /**
327      * @param whenFalse the whenFalse to set
328      */
329     public void setWhenFalse(AgendaItemBo whenFalse) {
330         this.whenFalse = whenFalse;
331 
332         if (whenFalse != null) {
333             setWhenFalseId(whenFalse.getId());
334         } else {
335             setWhenFalseId(null);
336         }
337     }
338 
339     /**
340      * @return the always
341      */
342     @Override
343     public AgendaItemBo getAlways() {
344         return this.always;
345     }
346 
347     /**
348      * @param always the always to set
349      */
350     public void setAlways(AgendaItemBo always) {
351         this.always = always;
352         if (always != null) {
353             setAlwaysId(always.getId());
354         } else {
355             setAlwaysId(null);
356         }
357     }
358 
359     /**
360      * @return the rule
361      */
362     @Override
363     public RuleBo getRule() {
364         return this.rule;
365     }
366 
367     @Override
368     public AgendaDefinitionContract getSubAgenda() {
369         return null; // no sub-agenda support at this time
370     }
371 
372     /**
373      * @param rule the rule to set
374      */
375     public void setRule(RuleBo rule) {
376         this.rule = rule;
377     }
378 
379     /**
380      * Converts a mutable bo to it's immutable counterpart
381      * @param bo the mutable business object
382      * @return the immutable object
383      */
384     static AgendaItemDefinition to(AgendaItemBo bo) {
385         if (bo == null) {
386             return null;
387         }
388 
389         AgendaItemDefinition.Builder builder = AgendaItemDefinition.Builder.create(bo);
390 
391         return builder.build();
392     }
393 
394     /**
395      * Converts a immutable object to it's mutable bo counterpart
396      * @param im immutable object
397      * @return the mutable bo
398      */
399     public static AgendaItemBo from(AgendaItemDefinition im) {
400         if (im == null) {
401             return null;
402         }
403 
404         AgendaItemBo bo = new AgendaItemBo();
405         bo.id = im.getId();
406         bo.agendaId = im.getAgendaId();
407         bo.subAgendaId = im.getSubAgendaId();
408         bo.whenTrueId = im.getWhenTrueId();
409         bo.whenFalseId = im.getWhenFalseId();
410         bo.alwaysId = im.getAlwaysId();
411         bo.versionNumber = im.getVersionNumber();
412         bo.rule = RuleBo.from(im.getRule());
413         bo.whenTrue = AgendaItemBo.from(im.getWhenTrue());
414         bo.whenFalse = AgendaItemBo.from(im.getWhenFalse());
415         bo.always = AgendaItemBo.from(im.getAlways());
416 
417         return bo;
418     }
419 
420     /**
421      * Returns a copy of this AgendaItem
422      * @param copiedAgenda the new Agenda that the copied AgendiaItem will be associated with
423      * @param oldRuleIdToNew Map<String, RuleBo> mapping of old rule id to the new RuleBo
424      * @param dts DateTimeStamp to append to the copied AgendaItem name
425      * @return AgendaItemBo copy of this AgendaItem with new id and name
426      */
427     public AgendaItemBo copyAgendaItem(AgendaBo copiedAgenda, Map<String, RuleBo> oldRuleIdToNew, Map<String, AgendaItemBo> oldAgendaItemIdToNew, List<AgendaItemBo> copiedAgendaItems, final String dts) {
428         // Use deepCopy and update all the ids.
429         AgendaItemBo copiedAgendaItem = getDataObjectService().copyInstance(this, CopyOption.RESET_PK_FIELDS, CopyOption.RESET_OBJECT_ID );
430         copiedAgendaItem.setId(agendaItemIdIncrementer.getNewId());
431         copiedAgendaItem.setAgendaId(copiedAgenda.getId());
432         oldAgendaItemIdToNew.put(this.getId(), copiedAgendaItem);
433 
434         // Don't create another copy of a rule that we have already copied.
435         if (!oldRuleIdToNew.containsKey(this.getRuleId())) {
436             if (this.getRule() != null) {
437                 copiedAgendaItem.setRule(this.getRule().copyRule(COPY_OF_TEXT + this.getRule().getName() + " " + dts));
438                 oldRuleIdToNew.put(this.getRuleId(), copiedAgendaItem.getRule());
439             }
440         } else {
441             copiedAgendaItem.setRule(oldRuleIdToNew.get(this.getRuleId()));
442         }
443 
444         if (copiedAgendaItem.getWhenFalse() != null) {
445             if (!oldAgendaItemIdToNew.containsKey(this.getWhenFalseId())) {
446                 copiedAgendaItem.setWhenFalse(this.getWhenFalse().copyAgendaItem(copiedAgenda, oldRuleIdToNew, oldAgendaItemIdToNew, copiedAgendaItems, dts));
447                 oldAgendaItemIdToNew.put(this.getWhenFalseId(), copiedAgendaItem.getWhenFalse());
448                 copiedAgendaItems.add(copiedAgendaItem.getWhenFalse());
449             } else {
450                 copiedAgendaItem.setWhenFalse(oldAgendaItemIdToNew.get(this.getWhenFalseId()));
451             }
452         }
453 
454         if (copiedAgendaItem.getWhenTrue() != null) {
455             if (!oldAgendaItemIdToNew.containsKey(this.getWhenTrueId())) {
456                 copiedAgendaItem.setWhenTrue(this.getWhenTrue().copyAgendaItem(copiedAgenda, oldRuleIdToNew, oldAgendaItemIdToNew, copiedAgendaItems, dts));
457                 oldAgendaItemIdToNew.put(this.getWhenTrueId(), copiedAgendaItem.getWhenTrue());
458                 copiedAgendaItems.add(copiedAgendaItem.getWhenTrue());
459             } else {
460                 copiedAgendaItem.setWhenTrue(oldAgendaItemIdToNew.get(this.getWhenTrueId()));
461             }
462         }
463 
464         if (copiedAgendaItem.getAlways() != null) {
465             if (!oldAgendaItemIdToNew.containsKey(this.getAlwaysId())) {
466                 copiedAgendaItem.setAlways(this.getAlways().copyAgendaItem(copiedAgenda, oldRuleIdToNew, oldAgendaItemIdToNew, copiedAgendaItems, dts));
467                 oldAgendaItemIdToNew.put(this.getAlwaysId(), copiedAgendaItem.getAlways());
468                 copiedAgendaItems.add(copiedAgendaItem.getAlways());
469             } else {
470                 copiedAgendaItem.setAlways(oldAgendaItemIdToNew.get(this.getAlwaysId()));
471             }
472         }
473         return copiedAgendaItem;
474     }
475 
476     public DataObjectService getDataObjectService() {
477         if (dataObjectService == null) {
478             dataObjectService = KradDataServiceLocator.getDataObjectService();
479         }
480 
481         return dataObjectService;
482     }
483 
484     public void setDataObjectService(DataObjectService dataObjectService) {
485         this.dataObjectService = dataObjectService;
486     }
487 
488     public KrmsTypeRepositoryService getKrmsTypeRepositoryService() {
489         if (krmsTypeRepositoryService == null) {
490             krmsTypeRepositoryService = KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService();
491         }
492 
493         return krmsTypeRepositoryService;
494     }
495 
496     public void setKrmsTypeRepositoryService(KrmsTypeRepositoryService dataObjectService) {
497         this.krmsTypeRepositoryService = dataObjectService;
498     }
499 }