001/** 002 * Copyright 2005-2017 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 java.io.Serializable; 019import java.util.ArrayList; 020import java.util.List; 021import java.util.Map; 022 023import javax.persistence.CascadeType; 024import javax.persistence.Column; 025import javax.persistence.Entity; 026import javax.persistence.FetchType; 027import javax.persistence.GeneratedValue; 028import javax.persistence.Id; 029import javax.persistence.JoinColumn; 030import javax.persistence.ManyToOne; 031import javax.persistence.Table; 032import javax.persistence.Transient; 033import javax.persistence.Version; 034 035import org.apache.commons.collections.CollectionUtils; 036import org.apache.commons.lang.StringUtils; 037import org.eclipse.persistence.annotations.OptimisticLocking; 038import org.kuali.rice.core.api.mo.common.Versioned; 039import org.kuali.rice.krad.data.CopyOption; 040import org.kuali.rice.krad.data.DataObjectService; 041import org.kuali.rice.krad.data.KradDataServiceLocator; 042import org.kuali.rice.krad.data.jpa.PortableSequenceGenerator; 043import org.kuali.rice.krms.api.repository.agenda.AgendaDefinitionContract; 044import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition; 045import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinitionContract; 046import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition; 047import org.kuali.rice.krms.api.repository.type.KrmsTypeRepositoryService; 048 049/** 050 * Agenda Item business object 051 * 052 * @author Kuali Rice Team (rice.collab@kuali.org) 053 * 054 */ 055@Entity 056@Table(name = "KRMS_AGENDA_ITM_T") 057@OptimisticLocking(cascade = true) 058public class AgendaItemBo implements AgendaItemDefinitionContract, Versioned, Serializable { 059 060 private static final long serialVersionUID = 1L; 061 062 public static final String COPY_OF_TEXT = "Copy of "; 063 064 public static final String AGENDA_ITEM_SEQ_NAME = "KRMS_AGENDA_ITM_S"; 065 066 static RepositoryBoIncrementer agendaItemIdIncrementer = new RepositoryBoIncrementer(AGENDA_ITEM_SEQ_NAME); 067 068 @Transient 069 private transient DataObjectService dataObjectService = null; 070 @Transient 071 private transient KrmsTypeRepositoryService krmsTypeRepositoryService = null; 072 073 @PortableSequenceGenerator(name = AGENDA_ITEM_SEQ_NAME) 074 @GeneratedValue(generator = AGENDA_ITEM_SEQ_NAME) 075 @Id 076 @Column(name = "AGENDA_ITM_ID") 077 private String id; 078 079 @Column(name = "AGENDA_ID") 080 private String agendaId; 081 082 @Column(name = "SUB_AGENDA_ID") 083 private String subAgendaId; 084 085 @Column(name = "WHEN_TRUE", insertable = false, updatable = false) 086 private String whenTrueId; 087 088 @Column(name = "WHEN_FALSE", insertable = false, updatable = false) 089 private String whenFalseId; 090 091 @Column(name = "ALWAYS", insertable = false, updatable = false) 092 private String alwaysId; 093 094 @ManyToOne(targetEntity = RuleBo.class, fetch = FetchType.LAZY, cascade = { CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE, CascadeType.PERSIST}) 095 @JoinColumn(name = "RULE_ID", referencedColumnName = "RULE_ID") 096 private RuleBo rule; 097 098 @Column(name = "VER_NBR") 099 @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}