001/**
002 * Copyright 2005-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krms.impl.repository;
017
018import org.apache.commons.collections.CollectionUtils;
019import org.apache.commons.lang.StringUtils;
020import org.kuali.rice.core.api.mo.common.Versioned;
021import org.kuali.rice.core.api.util.io.SerializationUtils;
022import org.kuali.rice.krad.data.jpa.PortableSequenceGenerator;
023import org.kuali.rice.krms.api.repository.agenda.AgendaDefinitionContract;
024import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition;
025import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinitionContract;
026import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
027
028import javax.persistence.CascadeType;
029import javax.persistence.Column;
030import javax.persistence.Entity;
031import javax.persistence.FetchType;
032import javax.persistence.GeneratedValue;
033import javax.persistence.Id;
034import javax.persistence.JoinColumn;
035import javax.persistence.ManyToOne;
036import javax.persistence.Table;
037import javax.persistence.Version;
038import java.io.Serializable;
039import java.util.ArrayList;
040import java.util.List;
041import java.util.Map;
042
043/**
044 * Agenda Item business object
045 *
046 * @author Kuali Rice Team (rice.collab@kuali.org)
047 *
048 */
049@Entity
050@Table(name = "KRMS_AGENDA_ITM_T")
051public class AgendaItemBo implements AgendaItemDefinitionContract, Versioned, Serializable {
052
053    private static final long serialVersionUID = 1L;
054
055    public static final String COPY_OF_TEXT = "Copy of ";
056
057    public static final String AGENDA_ITEM_SEQ_NAME = "KRMS_AGENDA_ITM_S";
058    static final RepositoryBoIncrementer agendaItemIdIncrementer = new RepositoryBoIncrementer(AGENDA_ITEM_SEQ_NAME);
059
060    @PortableSequenceGenerator(name = AGENDA_ITEM_SEQ_NAME)
061    @GeneratedValue(generator = AGENDA_ITEM_SEQ_NAME)
062    @Id
063    @Column(name = "AGENDA_ITM_ID")
064    private String id;
065
066    @Column(name = "AGENDA_ID")
067    private String agendaId;
068
069    @Column(name = "RULE_ID")
070    private String ruleId;
071
072    @Column(name = "SUB_AGENDA_ID")
073    private String subAgendaId;
074
075    @Column(name = "WHEN_TRUE")
076    private String whenTrueId;
077
078    @Column(name = "WHEN_FALSE")
079    private String whenFalseId;
080
081    @Column(name = "ALWAYS")
082    private String alwaysId;
083
084    @ManyToOne(targetEntity = RuleBo.class, fetch = FetchType.LAZY, cascade = { CascadeType.REFRESH })
085    @JoinColumn(name = "RULE_ID", referencedColumnName = "RULE_ID", insertable = false, updatable = false)
086    private RuleBo rule;
087
088    @ManyToOne(targetEntity = AgendaItemBo.class, cascade = { CascadeType.REFRESH })
089    @JoinColumn(name = "WHEN_TRUE", referencedColumnName = "AGENDA_ITM_ID", insertable = false, updatable = false)
090    private AgendaItemBo whenTrue;
091
092    @ManyToOne(targetEntity = AgendaItemBo.class, cascade = { CascadeType.REFRESH })
093    @JoinColumn(name = "WHEN_FALSE", referencedColumnName = "AGENDA_ITM_ID", insertable = false, updatable = false)
094    private AgendaItemBo whenFalse;
095
096    @ManyToOne(targetEntity = AgendaItemBo.class, cascade = { CascadeType.REFRESH })
097    @JoinColumn(name = "ALWAYS", referencedColumnName = "AGENDA_ITM_ID", insertable = false, updatable = false)
098    private AgendaItemBo always;
099
100    @Column(name = "VER_NBR")
101    @Version
102    private Long versionNumber;
103
104    public String getUl(AgendaItemBo firstItem) {
105        return ("<ul>" + getUlHelper(firstItem) + "</ul>");
106    }
107
108    public String getUlHelper(AgendaItemBo item) {
109        StringBuilder sb = new StringBuilder();
110        sb.append("<li>" + ruleId + "</li>");
111
112        if (whenTrue != null) {
113            sb.append("<ul><li>when true</li><ul>");
114            sb.append(getUlHelper(whenTrue));
115            sb.append("</ul></ul>");
116        }
117        if (whenFalse != null) {
118            sb.append("<ul><li>when false</li><ul>");
119            sb.append(getUlHelper(whenFalse));
120            sb.append("</ul></ul>");
121        }
122        if (always != null) {
123            sb.append(getUlHelper(always));
124        }
125
126        return sb.toString();
127    }
128
129    public String getRuleText() {
130        StringBuilder resultBuilder = new StringBuilder();
131        if (getRule() != null) {
132            if (StringUtils.isBlank(getRule().getName())) {
133                resultBuilder.append("- unnamed rule -");
134            } else {
135                resultBuilder.append(getRule().getName());
136            }
137            if (!StringUtils.isBlank(getRule().getDescription())) {
138                resultBuilder.append(": ");
139                resultBuilder.append(getRule().getDescription());
140            }
141
142            // add a description of the action configured on the rule, if there is one
143            if (!CollectionUtils.isEmpty(getRule().getActions())) {
144                resultBuilder.append("   [");
145                ActionBo action = getRule().getActions().get(0);
146                KrmsTypeDefinition krmsTypeDefn = KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService().getTypeById(action.getTypeId());
147                resultBuilder.append(krmsTypeDefn.getName());
148                resultBuilder.append(": ");
149                resultBuilder.append(action.getName());
150
151                if (getRule().getActions().size() > 1) {
152                    resultBuilder.append(" ... ");
153                }
154
155                resultBuilder.append("]");
156            }
157        } else {
158            throw new IllegalStateException();
159        }
160
161        return resultBuilder.toString();
162    }
163
164    public List<AgendaItemBo> getAlwaysList() {
165        List<AgendaItemBo> results = new ArrayList<AgendaItemBo>();
166        AgendaItemBo currentNode = this;
167
168        while (currentNode.always != null) {
169            results.add(currentNode.always);
170            currentNode = currentNode.always;
171        }
172
173        return results;
174    }
175
176    /**
177     * @return the id
178     */
179    public String getId() {
180        return this.id;
181    }
182
183    /**
184     * @param id the id to set
185     */
186    public void setId(String id) {
187        this.id = id;
188    }
189
190    /**
191     * @return the agendaId
192     */
193    public String getAgendaId() {
194        return this.agendaId;
195    }
196
197    /**
198     * @param agendaId the agendaId to set
199     */
200    public void setAgendaId(String agendaId) {
201        this.agendaId = agendaId;
202    }
203
204    /**
205     * @return the ruleId
206     */
207    public String getRuleId() {
208        return this.ruleId;
209    }
210
211    /**
212     * @param ruleId the ruleId to set
213     */
214    public void setRuleId(String ruleId) {
215        this.ruleId = ruleId;
216    }
217
218    /**
219     * @return the subAgendaId
220     */
221    public String getSubAgendaId() {
222        return this.subAgendaId;
223    }
224
225    /**
226     * @param subAgendaId the subAgendaId to set
227     */
228    public void setSubAgendaId(String subAgendaId) {
229        this.subAgendaId = subAgendaId;
230    }
231
232    /**
233     * @return the whenTrueId
234     */
235    public String getWhenTrueId() {
236        return this.whenTrueId;
237    }
238
239    /**
240     * @param whenTrueId the whenTrueId to set
241     */
242    public void setWhenTrueId(String whenTrueId) {
243        this.whenTrueId = whenTrueId;
244    }
245
246    /**
247     * @return the whenFalseId
248     */
249    public String getWhenFalseId() {
250        return this.whenFalseId;
251    }
252
253    /**
254     * @param whenFalseId the whenFalseId to set
255     */
256    public void setWhenFalseId(String whenFalseId) {
257        this.whenFalseId = whenFalseId;
258    }
259
260    /**
261     * @return the alwaysId
262     */
263    public String getAlwaysId() {
264        return this.alwaysId;
265    }
266
267    /**
268     * @param alwaysId the alwaysId to set
269     */
270    public void setAlwaysId(String alwaysId) {
271        this.alwaysId = alwaysId;
272    }
273
274    public Long getVersionNumber() {
275        return versionNumber;
276    }
277
278    public void setVersionNumber(Long versionNumber) {
279        this.versionNumber = versionNumber;
280    }
281
282    /**
283     * @return the whenTrue
284     */
285    public AgendaItemBo getWhenTrue() {
286        return this.whenTrue;
287    }
288
289    /**
290     * @param whenTrue the whenTrue to set
291     */
292    public void setWhenTrue(AgendaItemBo whenTrue) {
293        this.whenTrue = whenTrue;
294
295        if (whenTrue != null) {
296            setWhenTrueId(whenTrue.getId());
297        } else {
298            setWhenTrueId(null);
299        }
300    }
301
302    /**
303     * @return the whenFalse
304     */
305    public AgendaItemBo getWhenFalse() {
306        return this.whenFalse;
307    }
308
309    /**
310     * @param whenFalse the whenFalse to set
311     */
312    public void setWhenFalse(AgendaItemBo whenFalse) {
313        this.whenFalse = whenFalse;
314
315        if (whenFalse != null) {
316            setWhenFalseId(whenFalse.getId());
317        } else {
318            setWhenFalseId(null);
319        }
320    }
321
322    /**
323     * @return the always
324     */
325    public AgendaItemBo getAlways() {
326        return this.always;
327    }
328
329    /**
330     * @param always the always to set
331     */
332    public void setAlways(AgendaItemBo always) {
333        this.always = always;
334        if (always != null) {
335            setAlwaysId(always.getId());
336        } else {
337            setAlwaysId(null);
338        }
339    }
340
341    /**
342     * @return the rule
343     */
344    public RuleBo getRule() {
345        return this.rule;
346    }
347
348    @Override
349    public AgendaDefinitionContract getSubAgenda() {
350        return null; // no sub-agenda support at this time
351    }
352
353    /**
354     * @param rule the rule to set
355     */
356    public void setRule(RuleBo rule) {
357        this.rule = rule;
358        if (rule != null) {
359            setRuleId(rule.getId());
360        } else {
361            setRuleId(null);
362        }
363    }
364
365    /**
366     * Converts a mutable bo to it's immutable counterpart
367     * @param bo the mutable business object
368     * @return the immutable object
369     */
370    static AgendaItemDefinition to(AgendaItemBo bo) {
371        if (bo == null) {
372            return null;
373        }
374
375        AgendaItemDefinition.Builder builder = AgendaItemDefinition.Builder.create(bo);
376
377        return builder.build();
378    }
379
380    /**
381     * Converts a immutable object to it's mutable bo counterpart
382     * @param im immutable object
383     * @return the mutable bo
384     */
385    static AgendaItemBo from(AgendaItemDefinition im) {
386        if (im == null) {
387            return null;
388        }
389
390        AgendaItemBo bo = new AgendaItemBo();
391        bo.id = im.getId();
392        bo.agendaId = im.getAgendaId();
393        bo.ruleId = im.getRuleId();
394        bo.subAgendaId = im.getSubAgendaId();
395        bo.whenTrueId = im.getWhenTrueId();
396        bo.whenFalseId = im.getWhenFalseId();
397        bo.alwaysId = im.getAlwaysId();
398        bo.versionNumber = im.getVersionNumber();
399        bo.rule = RuleBo.from(im.getRule());
400        bo.whenTrue = AgendaItemBo.from(im.getWhenTrue());
401        bo.whenFalse = AgendaItemBo.from(im.getWhenFalse());
402        bo.always = AgendaItemBo.from(im.getAlways());
403
404        return bo;
405    }
406
407    /**
408     * Returns a copy of this AgendaItem
409     * @param copiedAgenda the new Agenda that the copied AgendiaItem will be associated with
410     * @param oldRuleIdToNew Map<String, RuleBo> mapping of old rule id to the new RuleBo
411     * @param dts DateTimeStamp to append to the copied AgendaItem name
412     * @return AgendaItemBo copy of this AgendaItem with new id and name
413     */
414    public AgendaItemBo copyAgendaItem(AgendaBo copiedAgenda, Map<String, RuleBo> oldRuleIdToNew, Map<String, AgendaItemBo> oldAgendaItemIdToNew, List<AgendaItemBo> copiedAgendaItems, final String dts) {
415        // Use deepCopy and update all the ids.  
416        AgendaItemBo copiedAgendaItem = (AgendaItemBo) SerializationUtils.deepCopy(this);
417        copiedAgendaItem.setId(agendaItemIdIncrementer.getNewId());
418        copiedAgendaItem.setAgendaId(copiedAgenda.getId());
419        oldAgendaItemIdToNew.put(this.getId(), copiedAgendaItem);
420
421        // Don't create another copy of a rule that we have already copied.  
422        if (!oldRuleIdToNew.containsKey(this.getRuleId())) {
423            if (this.getRule() != null) {
424                copiedAgendaItem.setRule(this.getRule().copyRule(COPY_OF_TEXT + this.getRule().getName() + " " + dts));
425                oldRuleIdToNew.put(this.getRuleId(), copiedAgendaItem.getRule());
426            }
427        } else {
428            copiedAgendaItem.setRule(oldRuleIdToNew.get(this.getRuleId()));
429        }
430
431        if (copiedAgendaItem.getWhenFalse() != null) {
432            if (!oldAgendaItemIdToNew.containsKey(this.getWhenFalseId())) {
433                copiedAgendaItem.setWhenFalse(this.getWhenFalse().copyAgendaItem(copiedAgenda, oldRuleIdToNew, oldAgendaItemIdToNew, copiedAgendaItems, dts));
434                oldAgendaItemIdToNew.put(this.getWhenFalseId(), copiedAgendaItem.getWhenFalse());
435                copiedAgendaItems.add(copiedAgendaItem.getWhenFalse());
436            } else {
437                copiedAgendaItem.setWhenFalse(oldAgendaItemIdToNew.get(this.getWhenFalseId()));
438            }
439        }
440
441        if (copiedAgendaItem.getWhenTrue() != null) {
442            if (!oldAgendaItemIdToNew.containsKey(this.getWhenTrueId())) {
443                copiedAgendaItem.setWhenTrue(this.getWhenTrue().copyAgendaItem(copiedAgenda, oldRuleIdToNew, oldAgendaItemIdToNew, copiedAgendaItems, dts));
444                oldAgendaItemIdToNew.put(this.getWhenTrueId(), copiedAgendaItem.getWhenTrue());
445                copiedAgendaItems.add(copiedAgendaItem.getWhenTrue());
446            } else {
447                copiedAgendaItem.setWhenTrue(oldAgendaItemIdToNew.get(this.getWhenTrueId()));
448            }
449        }
450
451        if (copiedAgendaItem.getAlways() != null) {
452            if (!oldAgendaItemIdToNew.containsKey(this.getAlwaysId())) {
453                copiedAgendaItem.setAlways(this.getAlways().copyAgendaItem(copiedAgenda, oldRuleIdToNew, oldAgendaItemIdToNew, copiedAgendaItems, dts));
454                oldAgendaItemIdToNew.put(this.getAlwaysId(), copiedAgendaItem.getAlways());
455                copiedAgendaItems.add(copiedAgendaItem.getAlways());
456            } else {
457                copiedAgendaItem.setAlways(oldAgendaItemIdToNew.get(this.getAlwaysId()));
458            }
459        }
460        return copiedAgendaItem;
461    }
462}