1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krms.impl.repository;
17
18 import java.io.Serializable;
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23
24 import javax.persistence.CascadeType;
25 import javax.persistence.Column;
26 import javax.persistence.Convert;
27 import javax.persistence.Entity;
28 import javax.persistence.FetchType;
29 import javax.persistence.GeneratedValue;
30 import javax.persistence.Id;
31 import javax.persistence.JoinColumn;
32 import javax.persistence.ManyToOne;
33 import javax.persistence.OneToMany;
34 import javax.persistence.Table;
35 import javax.persistence.Transient;
36 import javax.persistence.Version;
37
38 import org.apache.commons.lang.StringUtils;
39 import org.eclipse.persistence.annotations.OptimisticLocking;
40 import org.kuali.rice.core.api.mo.common.Versioned;
41 import org.kuali.rice.core.api.util.tree.Node;
42 import org.kuali.rice.core.api.util.tree.Tree;
43 import org.kuali.rice.krad.data.DataObjectService;
44 import org.kuali.rice.krad.data.jpa.PortableSequenceGenerator;
45 import org.kuali.rice.krad.data.jpa.converters.BooleanYNConverter;
46 import org.kuali.rice.krad.service.KRADServiceLocator;
47 import org.kuali.rice.krms.api.repository.LogicalOperator;
48 import org.kuali.rice.krms.api.repository.action.ActionDefinition;
49 import org.kuali.rice.krms.api.repository.proposition.PropositionType;
50 import org.kuali.rice.krms.api.repository.rule.RuleDefinition;
51 import org.kuali.rice.krms.api.repository.rule.RuleDefinitionContract;
52 import org.kuali.rice.krms.api.repository.type.KrmsAttributeDefinition;
53 import org.kuali.rice.krms.impl.ui.CompoundOpCodeNode;
54 import org.kuali.rice.krms.impl.ui.CompoundPropositionEditNode;
55 import org.kuali.rice.krms.impl.ui.RuleTreeNode;
56 import org.kuali.rice.krms.impl.ui.SimplePropositionEditNode;
57 import org.kuali.rice.krms.impl.ui.SimplePropositionNode;
58
59 @Entity
60 @Table(name = "KRMS_RULE_T")
61 @OptimisticLocking(cascade = true)
62 public class RuleBo implements RuleDefinitionContract, Versioned, Serializable {
63
64 private static final long serialVersionUID = 1L;
65
66 public static final String RULE_SEQ_NAME = "KRMS_RULE_S";
67 static final RepositoryBoIncrementer ruleIdIncrementer = new RepositoryBoIncrementer(RULE_SEQ_NAME);
68 static final RepositoryBoIncrementer actionIdIncrementer = new RepositoryBoIncrementer("KRMS_ACTN_S");
69 static final RepositoryBoIncrementer ruleAttributeIdIncrementer = new RepositoryBoIncrementer("KRMS_RULE_ATTR_S");
70 static final RepositoryBoIncrementer actionAttributeIdIncrementer = new RepositoryBoIncrementer("KRMS_ACTN_ATTR_S");
71
72 @PortableSequenceGenerator(name = RULE_SEQ_NAME)
73 @GeneratedValue(generator = RULE_SEQ_NAME)
74 @Id
75 @Column(name = "RULE_ID")
76 private String id;
77
78 @Column(name = "NMSPC_CD")
79 private String namespace;
80
81 @Column(name = "DESC_TXT")
82 private String description;
83
84 @Column(name = "NM")
85 private String name;
86
87 @Column(name = "TYP_ID", nullable = true)
88 private String typeId;
89
90 @Column(name = "ACTV")
91 @Convert(converter = BooleanYNConverter.class)
92 private boolean active = true;
93
94 @Column(name = "VER_NBR")
95 @Version
96 private Long versionNumber;
97
98 @ManyToOne(targetEntity = PropositionBo.class, fetch = FetchType.LAZY,
99 cascade = { CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE, CascadeType.PERSIST })
100 @JoinColumn(name = "PROP_ID", referencedColumnName = "PROP_ID")
101 private PropositionBo proposition;
102
103 @OneToMany(orphanRemoval = true, mappedBy = "rule", fetch = FetchType.LAZY,
104 cascade = { CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE, CascadeType.PERSIST })
105 @JoinColumn(name = "RULE_ID", referencedColumnName = "RULE_ID")
106 private List<ActionBo> actions;
107
108 @OneToMany(orphanRemoval = true, mappedBy = "rule", fetch = FetchType.LAZY,
109 cascade = { CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE, CascadeType.PERSIST })
110 @JoinColumn(name = "RULE_ID", referencedColumnName = "RULE_ID")
111 private List<RuleAttributeBo> attributeBos;
112
113 @Transient
114 private Tree<RuleTreeNode, String> propositionTree;
115
116 @Transient
117 private String propositionSummary;
118
119 @Transient
120 private StringBuffer propositionSummaryBuffer;
121
122 @Transient
123 private String selectedPropositionId;
124
125 public RuleBo() {
126 actions = new ArrayList<ActionBo>();
127 attributeBos = new ArrayList<RuleAttributeBo>();
128 }
129
130 @Override
131 public PropositionBo getProposition() {
132 return proposition;
133 }
134
135 public void setProposition(PropositionBo proposition) {
136 this.proposition = proposition;
137 }
138
139
140
141
142
143
144
145 public void setTypeId(String typeId) {
146 if (StringUtils.isBlank(typeId)) {
147 this.typeId = null;
148 } else {
149 this.typeId = typeId;
150 }
151 }
152
153 @Override
154 public Map<String, String> getAttributes() {
155 HashMap<String, String> attributes = new HashMap<String, String>();
156
157 for (RuleAttributeBo attr : attributeBos) {
158 DataObjectService dataObjectService = KRADServiceLocator.getDataObjectService();
159 dataObjectService.wrap(attr).fetchRelationship("attributeDefinition", false, true);
160 attributes.put(attr.getAttributeDefinition().getName(), attr.getValue());
161 }
162
163 return attributes;
164 }
165
166 public void setAttributes(Map<String, String> attributes) {
167 this.attributeBos = new ArrayList<RuleAttributeBo>();
168
169 if (!StringUtils.isBlank(this.typeId)) {
170 List<KrmsAttributeDefinition> attributeDefinitions = KrmsRepositoryServiceLocator.getKrmsAttributeDefinitionService().findAttributeDefinitionsByType(this.getTypeId());
171 Map<String, KrmsAttributeDefinition> attributeDefinitionsByName = new HashMap<String, KrmsAttributeDefinition>();
172
173 if (attributeDefinitions != null) {
174 for (KrmsAttributeDefinition attributeDefinition : attributeDefinitions) {
175 attributeDefinitionsByName.put(attributeDefinition.getName(), attributeDefinition);
176 }
177 }
178
179 for (Map.Entry<String, String> attr : attributes.entrySet()) {
180 KrmsAttributeDefinition attributeDefinition = attributeDefinitionsByName.get(attr.getKey());
181 RuleAttributeBo attributeBo = new RuleAttributeBo();
182 attributeBo.setRule(this);
183 attributeBo.setValue(attr.getValue());
184 attributeBo.setAttributeDefinition(KrmsAttributeDefinitionBo.from(attributeDefinition));
185 attributeBos.add(attributeBo);
186 }
187 }
188 }
189
190 public String getPropositionSummary() {
191 if (this.propositionTree == null) {
192 this.propositionTree = refreshPropositionTree(false);
193 }
194
195 return propositionSummaryBuffer.toString();
196 }
197
198
199
200
201
202
203 public Tree getPropositionTree() {
204 if (this.propositionTree == null) {
205 this.propositionTree = refreshPropositionTree(false);
206 }
207
208 return this.propositionTree;
209 }
210
211 public void setPropositionTree(Tree<RuleTreeNode, String> tree) {
212 this.propositionTree.equals(tree);
213 }
214
215 public Tree refreshPropositionTree(Boolean editMode) {
216 Tree myTree = new Tree<RuleTreeNode, String>();
217
218 Node<RuleTreeNode, String> rootNode = new Node<RuleTreeNode, String>();
219 myTree.setRootElement(rootNode);
220
221 propositionSummaryBuffer = new StringBuffer();
222 PropositionBo prop = this.getProposition();
223 if (prop!=null && StringUtils.isBlank(prop.getDescription())) {
224 prop.setDescription("");
225 }
226 buildPropTree(rootNode, prop, editMode);
227 this.propositionTree = myTree;
228 return myTree;
229 }
230
231
232
233
234
235
236
237
238
239
240
241 private void buildPropTree(Node sprout, PropositionBo prop, Boolean editMode) {
242
243
244
245
246 if (prop != null) {
247
248
249 String nodeLabel = prop.getDescription();
250 if (StringUtils.isBlank(nodeLabel)) {
251 nodeLabel = ": : blank proposition name : :";
252 }
253
254 if (PropositionType.SIMPLE.getCode().equalsIgnoreCase(prop.getPropositionTypeCode())) {
255
256
257 Node<RuleTreeNode, String> child = new Node<RuleTreeNode, String>();
258 child.setNodeLabel(nodeLabel);
259
260 if (prop.getEditMode()) {
261 child.setNodeLabel("");
262 child.setNodeType(SimplePropositionEditNode.NODE_TYPE);
263 SimplePropositionEditNode pNode = new SimplePropositionEditNode(prop);
264 child.setData(pNode);
265 } else {
266 child.setNodeType(SimplePropositionNode.NODE_TYPE);
267 SimplePropositionNode pNode = new SimplePropositionNode(prop);
268 child.setData(pNode);
269 }
270
271 sprout.getChildren().add(child);
272 propositionSummaryBuffer.append(prop.getParameterDisplayString());
273 } else if (PropositionType.COMPOUND.getCode().equalsIgnoreCase(prop.getPropositionTypeCode())) {
274
275 propositionSummaryBuffer.append(" ( ");
276 Node<RuleTreeNode, String> aNode = new Node<RuleTreeNode, String>();
277 aNode.setNodeLabel(nodeLabel);
278
279
280 if (prop.getEditMode()) {
281 aNode.setNodeLabel("");
282 aNode.setNodeType("ruleTreeNode compoundNode editNode");
283 CompoundPropositionEditNode pNode = new CompoundPropositionEditNode(prop);
284 aNode.setData(pNode);
285 } else {
286 aNode.setNodeType("ruleTreeNode compoundNode");
287 RuleTreeNode pNode = new RuleTreeNode(prop);
288 aNode.setData(pNode);
289 }
290
291 sprout.getChildren().add(aNode);
292 boolean first = true;
293 List<PropositionBo> allMyChildren = prop.getCompoundComponents();
294 int compoundSequenceNumber = 0;
295
296 for (PropositionBo child : allMyChildren) {
297 child.setCompoundSequenceNumber((compoundSequenceNumber = ++compoundSequenceNumber));
298
299
300
301 if (!first) {
302 addOpCodeNode(aNode, prop);
303 }
304
305 first = false;
306
307 buildPropTree(aNode, child, editMode);
308 }
309
310 propositionSummaryBuffer.append(" ) ");
311 }
312 }
313 }
314
315
316
317
318
319
320
321
322 private void addOpCodeNode(Node currentNode, PropositionBo prop) {
323 String opCodeLabel = "";
324
325 if (LogicalOperator.AND.getCode().equalsIgnoreCase(prop.getCompoundOpCode())) {
326 opCodeLabel = "AND";
327 } else if (LogicalOperator.OR.getCode().equalsIgnoreCase(prop.getCompoundOpCode())) {
328 opCodeLabel = "OR";
329 }
330
331 propositionSummaryBuffer.append(" " + opCodeLabel + " ");
332 Node<RuleTreeNode, String> aNode = new Node<RuleTreeNode, String>();
333 aNode.setNodeLabel("");
334 aNode.setNodeType("ruleTreeNode compoundOpCodeNode");
335 aNode.setData(new CompoundOpCodeNode(prop));
336
337 currentNode.getChildren().add(aNode);
338 }
339
340
341
342
343
344
345
346 public static RuleDefinition to(RuleBo bo) {
347 if (bo == null) {
348 return null;
349 }
350
351 return RuleDefinition.Builder.create(bo).build();
352 }
353
354
355
356
357
358
359
360 public static RuleBo from(RuleDefinition im) {
361 if (im == null) {
362 return null;
363 }
364
365 RuleBo bo = new RuleBo();
366 bo.id = im.getId();
367 bo.namespace = im.getNamespace();
368 bo.name = im.getName();
369 bo.description = im.getDescription();
370 bo.typeId = im.getTypeId();
371 bo.active = im.isActive();
372
373 if (im.getProposition() != null) {
374 PropositionBo propositionBo = PropositionBo.from(im.getProposition());
375 bo.proposition = propositionBo;
376 propositionBo.setRuleId(im.getId());
377 }
378
379 bo.setVersionNumber(im.getVersionNumber());
380 bo.actions = new ArrayList<ActionBo>();
381
382 for (ActionDefinition action : im.getActions()) {
383 ActionBo actionBo = ActionBo.from(action);
384 bo.actions.add(actionBo);
385 actionBo.setRule(bo);
386 }
387
388
389 List<RuleAttributeBo> attrs = new ArrayList<RuleAttributeBo>();
390
391 RuleAttributeBo attributeBo;
392 for (Map.Entry<String, String> entry : im.getAttributes().entrySet()) {
393 KrmsAttributeDefinitionBo attrDefBo = KrmsRepositoryServiceLocator.getKrmsAttributeDefinitionService().getKrmsAttributeBo(entry.getKey(), im.getNamespace());
394 attributeBo = new RuleAttributeBo();
395 attributeBo.setRule(RuleBo.from(im));
396 attributeBo.setAttributeDefinition(attrDefBo);
397 attributeBo.setValue(entry.getValue());
398 attributeBo.setAttributeDefinition(attrDefBo);
399 attrs.add(attributeBo);
400 }
401
402 bo.setAttributeBos(attrs);
403
404 return bo;
405 }
406
407 public static RuleBo copyRule(RuleBo existing) {
408
409 RuleBo newRule = new RuleBo();
410
411 newRule.setId(ruleIdIncrementer.getNewId());
412 newRule.setNamespace(existing.getNamespace());
413 newRule.setDescription(existing.getDescription());
414 newRule.setTypeId(existing.getTypeId());
415 newRule.setActive(true);
416
417 PropositionBo newProp = PropositionBo.copyProposition(existing.getProposition());
418 newProp.setRuleId(newRule.getId());
419 newRule.setProposition(newProp);
420
421 newRule.setAttributeBos(copyRuleAttributes(existing, newRule));
422 newRule.setActions(copyRuleActions(existing, newRule));
423
424 return newRule;
425 }
426
427
428
429
430
431
432
433 public RuleBo copyRule(String newRuleName) {
434 RuleBo copiedRule = RuleBo.copyRule(this);
435
436
437
438
439 copiedRule.setName(newRuleName);
440
441 return copiedRule;
442 }
443
444 public static List<RuleAttributeBo> copyRuleAttributes(RuleBo existing, RuleBo newRule) {
445 List<RuleAttributeBo> newAttributes = new ArrayList<RuleAttributeBo>();
446
447 for (RuleAttributeBo attr : existing.getAttributeBos()) {
448 RuleAttributeBo newAttr = new RuleAttributeBo();
449 newAttr.setId(ruleAttributeIdIncrementer.getNewId());
450 newAttr.setRule(newRule);
451 newAttr.setAttributeDefinition(attr.getAttributeDefinition());
452 newAttr.setValue(attr.getValue());
453 newAttributes.add(newAttr);
454 }
455
456 return newAttributes;
457 }
458
459 public static List<ActionAttributeBo> copyActionAttributes(ActionBo existing, ActionBo newAction) {
460 List<ActionAttributeBo> newAttributes = new ArrayList<ActionAttributeBo>();
461
462 for (ActionAttributeBo attr : existing.getAttributeBos()) {
463 ActionAttributeBo newAttr = new ActionAttributeBo();
464 newAttr.setId(actionAttributeIdIncrementer.getNewId());
465 newAttr.setAction(newAction);
466 newAttr.setAttributeDefinition(attr.getAttributeDefinition());
467 newAttr.setValue(attr.getValue());
468 newAttributes.add(newAttr);
469 }
470
471 return newAttributes;
472 }
473
474 public static List<ActionBo> copyRuleActions(RuleBo existing, RuleBo newRule) {
475 List<ActionBo> newActionList = new ArrayList<ActionBo>();
476
477 for (ActionBo action : existing.getActions()) {
478 ActionBo newAction = new ActionBo();
479 newAction.setId(actionIdIncrementer.getNewId());
480 newAction.setRule(newRule);
481 newAction.setDescription(action.getDescription());
482 newAction.setName(action.getName());
483 newAction.setNamespace(action.getNamespace());
484 newAction.setTypeId(action.getTypeId());
485 newAction.setSequenceNumber(action.getSequenceNumber());
486 newAction.setAttributeBos(copyActionAttributes(action, newAction));
487 newActionList.add(newAction);
488 }
489
490 return newActionList;
491 }
492
493 @Override
494 public String getId() {
495 return id;
496 }
497
498 public void setId(String id) {
499 this.id = id;
500 }
501
502 @Override
503 public String getNamespace() {
504 return namespace;
505 }
506
507 public void setNamespace(String namespace) {
508 this.namespace = namespace;
509 }
510
511 @Override
512 public String getDescription() {
513 return description;
514 }
515
516 public void setDescription(String description) {
517 this.description = description;
518 }
519
520 @Override
521 public String getName() {
522 return name;
523 }
524
525 public void setName(String name) {
526 this.name = name;
527 }
528
529 @Override
530 public String getTypeId() {
531 return typeId;
532 }
533
534 @Override
535 public String getPropId() {
536 if (proposition != null) {
537 return proposition.getId();
538 }
539
540 return null;
541 }
542
543 public boolean getActive() {
544 return active;
545 }
546
547 @Override
548 public boolean isActive() {
549 return active;
550 }
551
552 public void setActive(boolean active) {
553 this.active = active;
554 }
555
556 @Override
557 public Long getVersionNumber() {
558 return versionNumber;
559 }
560
561 public void setVersionNumber(Long versionNumber) {
562 this.versionNumber = versionNumber;
563 }
564
565 @Override
566 public List<ActionBo> getActions() {
567 return actions;
568 }
569
570 public void setActions(List<ActionBo> actions) {
571 this.actions = actions;
572 }
573
574 public List<RuleAttributeBo> getAttributeBos() {
575 return attributeBos;
576 }
577
578 public void setAttributeBos(List<RuleAttributeBo> attributeBos) {
579 this.attributeBos = attributeBos;
580 }
581
582 public void setPropositionSummary(String propositionSummary) {
583 this.propositionSummary = propositionSummary;
584 }
585
586 public String getSelectedPropositionId() {
587 return selectedPropositionId;
588 }
589
590 public void setSelectedPropositionId(String selectedPropositionId) {
591 this.selectedPropositionId = selectedPropositionId;
592 }
593
594 }