1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krms.impl.ui;
17
18 import org.apache.commons.collections.CollectionUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException;
21 import org.kuali.rice.core.api.data.DataType;
22 import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
23 import org.kuali.rice.core.api.uif.RemotableAttributeField;
24 import org.kuali.rice.core.api.uif.RemotableTextInput;
25 import org.kuali.rice.core.api.util.tree.Node;
26 import org.kuali.rice.core.api.util.tree.Tree;
27 import org.kuali.rice.core.impl.cache.DistributedCacheManagerDecorator;
28 import org.kuali.rice.krad.maintenance.Maintainable;
29 import org.kuali.rice.krad.maintenance.MaintainableImpl;
30 import org.kuali.rice.krad.maintenance.MaintenanceDocument;
31 import org.kuali.rice.krad.uif.container.CollectionGroup;
32 import org.kuali.rice.krad.uif.container.Container;
33 import org.kuali.rice.krad.uif.view.View;
34 import org.kuali.rice.krad.uif.view.ViewModel;
35 import org.kuali.rice.krad.util.KRADConstants;
36 import org.kuali.rice.krad.util.ObjectUtils;
37 import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
38 import org.kuali.rice.krms.api.KrmsConstants;
39 import org.kuali.rice.krms.api.repository.action.ActionDefinition;
40 import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
41 import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition;
42 import org.kuali.rice.krms.api.repository.agenda.AgendaTreeDefinition;
43 import org.kuali.rice.krms.api.repository.context.ContextDefinition;
44 import org.kuali.rice.krms.api.repository.function.FunctionDefinition;
45 import org.kuali.rice.krms.api.repository.operator.CustomOperator;
46 import org.kuali.rice.krms.api.repository.proposition.PropositionDefinition;
47 import org.kuali.rice.krms.api.repository.proposition.PropositionParameterType;
48 import org.kuali.rice.krms.api.repository.rule.RuleDefinition;
49 import org.kuali.rice.krms.api.repository.term.TermDefinition;
50 import org.kuali.rice.krms.api.repository.term.TermResolverDefinition;
51 import org.kuali.rice.krms.api.repository.term.TermSpecificationDefinition;
52 import org.kuali.rice.krms.api.repository.type.KrmsAttributeDefinition;
53 import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
54 import org.kuali.rice.krms.impl.repository.ActionAttributeBo;
55 import org.kuali.rice.krms.impl.repository.ActionBo;
56 import org.kuali.rice.krms.impl.repository.AgendaBo;
57 import org.kuali.rice.krms.impl.repository.AgendaItemBo;
58 import org.kuali.rice.krms.impl.repository.ContextBoService;
59 import org.kuali.rice.krms.impl.repository.KrmsAttributeDefinitionService;
60 import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
61 import org.kuali.rice.krms.impl.repository.PropositionBo;
62 import org.kuali.rice.krms.impl.repository.PropositionParameterBo;
63 import org.kuali.rice.krms.impl.repository.RepositoryBoIncrementer;
64 import org.kuali.rice.krms.impl.repository.RuleAttributeBo;
65 import org.kuali.rice.krms.impl.repository.RuleBo;
66 import org.kuali.rice.krms.impl.repository.TermBo;
67 import org.kuali.rice.krms.impl.repository.TermParameterBo;
68 import org.kuali.rice.krms.impl.util.KrmsImplConstants;
69 import org.kuali.rice.krms.impl.util.KrmsRetriever;
70 import org.kuali.rice.krms.impl.util.KrmsServiceLocatorInternal;
71
72 import java.util.ArrayList;
73 import java.util.Collections;
74 import java.util.Date;
75 import java.util.HashMap;
76 import java.util.List;
77 import java.util.Map;
78
79 import static org.kuali.rice.krms.impl.repository.BusinessObjectServiceMigrationUtils.findSingleMatching;
80
81
82
83
84
85
86 public class AgendaEditorMaintainable extends MaintainableImpl {
87
88 private static final long serialVersionUID = 1L;
89
90 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(
91 AgendaEditorMaintainable.class);
92
93 public static final String NEW_AGENDA_EDITOR_DOCUMENT_TEXT = "New Agenda Editor Document";
94 private static final RepositoryBoIncrementer termIdIncrementer = new RepositoryBoIncrementer(TermBo.TERM_SEQ_NAME);
95 private static final RepositoryBoIncrementer termParameterIdIncrementer = new RepositoryBoIncrementer(TermParameterBo.TERM_PARM_SEQ_NAME);
96
97 private transient KrmsRetriever krmsRetriever = new KrmsRetriever();
98
99
100
101
102 private ContextBoService getContextBoService() {
103 return KrmsRepositoryServiceLocator.getContextBoService();
104 }
105
106 public List<RemotableAttributeField> retrieveAgendaCustomAttributes(View view, Object model, Container container) {
107 AgendaEditor agendaEditor = getAgendaEditor(model);
108 return krmsRetriever.retrieveAgendaCustomAttributes(agendaEditor);
109 }
110
111
112
113
114
115 public List<RemotableAttributeField> retrieveTermParameters(View view, Object model, Container container) {
116
117 List<RemotableAttributeField> results = new ArrayList<RemotableAttributeField>();
118
119 AgendaEditor agendaEditor = getAgendaEditor(model);
120
121
122 RuleBo rule = agendaEditor.getAgendaItemLine().getRule();
123 if (null != rule) {
124
125
126 Tree<RuleTreeNode, String> propositionTree = rule.getPropositionTree();
127 Node<RuleTreeNode, String> editedPropositionNode = findEditedProposition(propositionTree.getRootElement());
128
129 if (editedPropositionNode != null) {
130 PropositionBo propositionBo = editedPropositionNode.getData().getProposition();
131 if (StringUtils.isEmpty(propositionBo.getCompoundOpCode()) && CollectionUtils.size(
132 propositionBo.getParameters()) > 0) {
133
134 PropositionParameterBo param = propositionBo.getParameters().get(0);
135 if (StringUtils.isNotBlank(param.getValue()) &&
136 param.getValue().startsWith(KrmsImplConstants.PARAMETERIZED_TERM_PREFIX)) {
137 String termSpecId = param.getValue().substring(
138 KrmsImplConstants.PARAMETERIZED_TERM_PREFIX.length());
139 TermResolverDefinition simplestResolver = getSimplestTermResolver(termSpecId,
140 rule.getNamespace());
141
142
143 if (simplestResolver != null) {
144 List<String> parameterNames = new ArrayList<String>(simplestResolver.getParameterNames());
145 Collections.sort(parameterNames);
146
147 for (String parameterName : parameterNames) {
148
149 RemotableTextInput.Builder controlBuilder = RemotableTextInput.Builder.create();
150 controlBuilder.setSize(64);
151
152 RemotableAttributeField.Builder builder = RemotableAttributeField.Builder.create(
153 parameterName);
154
155 builder.setRequired(true);
156 builder.setDataType(DataType.STRING);
157 builder.setControl(controlBuilder);
158 builder.setLongLabel(parameterName);
159 builder.setShortLabel(parameterName);
160 builder.setMinLength(Integer.valueOf(1));
161 builder.setMaxLength(Integer.valueOf(64));
162
163 results.add(builder.build());
164 }
165 }
166 }
167 }
168 }
169 }
170 return results;
171 }
172
173
174
175
176
177
178
179
180
181 static TermResolverDefinition getSimplestTermResolver(String termSpecId,
182 String namespace) {
183
184 List<TermResolverDefinition> resolvers =
185 KrmsRepositoryServiceLocator.getTermBoService().findTermResolversByOutputId(termSpecId, namespace);
186
187 TermResolverDefinition simplestResolver = null;
188
189 for (TermResolverDefinition resolver : resolvers) {
190 if (simplestResolver == null || simplestResolver.getParameterNames().size() < resolver.getParameterNames()
191 .size()) {
192 simplestResolver = resolver;
193 }
194 }
195
196 return simplestResolver;
197 }
198
199
200
201
202
203
204
205 private Node<RuleTreeNode, String> findEditedProposition(Node<RuleTreeNode, String> node) {
206 Node<RuleTreeNode, String> result = null;
207 if (node.getData() != null && node.getData().getProposition() != null && node.getData().getProposition()
208 .getEditMode()) {
209 result = node;
210 } else {
211 for (Node<RuleTreeNode, String> child : node.getChildren()) {
212 result = findEditedProposition(child);
213 if (result != null) {
214 break;
215 }
216 }
217 }
218 return result;
219 }
220
221
222
223
224
225
226
227 private AgendaEditor getAgendaEditor(Object model) {
228 MaintenanceDocumentForm maintenanceForm = (MaintenanceDocumentForm) model;
229 return (AgendaEditor) maintenanceForm.getDocument().getNewMaintainableObject().getDataObject();
230 }
231
232 public List<RemotableAttributeField> retrieveRuleActionCustomAttributes(View view, Object model,
233 Container container) {
234 AgendaEditor agendaEditor = getAgendaEditor((MaintenanceDocumentForm) model);
235 return krmsRetriever.retrieveRuleActionCustomAttributes(agendaEditor);
236 }
237
238
239
240
241 public List<RemotableAttributeField> retrieveRuleCustomAttributes(View view, Object model, Container container) {
242 AgendaEditor agendaEditor = getAgendaEditor((MaintenanceDocumentForm) model);
243 return krmsRetriever.retrieveRuleCustomAttributes(agendaEditor);
244 }
245
246 @Override
247 public Object retrieveObjectForEditOrCopy(MaintenanceDocument document, Map<String, String> dataObjectKeys) {
248 Object dataObject = null;
249
250 try {
251
252 AgendaEditor agendaEditor = new AgendaEditor();
253 AgendaBo agenda = findSingleMatching(getDataObjectService(),
254 ((AgendaEditor) getDataObject()).getAgenda().getClass(), dataObjectKeys);
255
256
257 forceLoadLazyRelations(agenda);
258
259 if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(getMaintenanceAction())) {
260 String dateTimeStamp = (new Date()).getTime() + "";
261 String newAgendaName = AgendaItemBo.COPY_OF_TEXT + agenda.getName() + " " + dateTimeStamp;
262
263 AgendaBo copiedAgenda = agenda.copyAgenda(newAgendaName, dateTimeStamp);
264
265 document.getDocumentHeader().setDocumentDescription(NEW_AGENDA_EDITOR_DOCUMENT_TEXT);
266 document.setFieldsClearedOnCopy(true);
267 agendaEditor.setAgenda(copiedAgenda);
268 } else {
269
270
271 agendaEditor.setAgenda(agenda);
272 }
273 agendaEditor.setCustomAttributesMap(agenda.getAttributes());
274
275
276 agendaEditor.setNamespace(agenda.getContext().getNamespace());
277 agendaEditor.setContextName(agenda.getContext().getName());
278
279 dataObject = agendaEditor;
280 } catch (ClassNotPersistenceCapableException ex) {
281 if (!document.getOldMaintainableObject().isExternalBusinessObject()) {
282 throw new RuntimeException("Data Object Class: "
283 + getDataObjectClass()
284 + " is not persistable and is not externalizable - configuration error");
285 }
286
287 }
288
289 return dataObject;
290 }
291
292 private void forceLoadLazyRelations(AgendaBo agenda) {
293 for (AgendaItemBo item : agenda.getItems()) {
294 for (ActionBo action : item.getRule().getActions()) {
295 if (CollectionUtils.isEmpty(action.getAttributeBos())) { continue; }
296
297 for (ActionAttributeBo actionAttribute : action.getAttributeBos()) {
298 actionAttribute.getAttributeDefinition();
299 }
300 }
301
302 Tree propTree = item.getRule().refreshPropositionTree(true);
303 walkPropositionTree(item.getRule().getProposition());
304
305 for (RuleAttributeBo ruleAttribute : item.getRule().getAttributeBos()) {
306 ruleAttribute.getAttributeDefinition();
307 }
308 }
309 }
310
311 private void walkPropositionTree(PropositionBo prop) {
312 if (prop == null) { return; }
313
314 if (prop.getParameters() != null) for (PropositionParameterBo param : prop.getParameters()) {
315 param.getPropId();
316 }
317
318 if (prop.getCompoundComponents() != null) for (PropositionBo childProp : prop.getCompoundComponents()) {
319 walkPropositionTree(childProp);
320 }
321 }
322
323
324
325
326 @Override
327 public void processAfterNew(MaintenanceDocument document, Map<String, String[]> requestParameters) {
328 super.processAfterNew(document, requestParameters);
329 document.getDocumentHeader().setDocumentDescription(NEW_AGENDA_EDITOR_DOCUMENT_TEXT);
330 }
331
332 @Override
333 public void processAfterEdit(MaintenanceDocument document, Map<String, String[]> requestParameters) {
334 super.processAfterEdit(document, requestParameters);
335 document.getDocumentHeader().setDocumentDescription("Modify Agenda Editor Document");
336 }
337
338 @Override
339 public void processAfterCopy(MaintenanceDocument document,
340 Map<String, String[]> parameters) {
341 super.processAfterCopy(document, parameters);
342 AgendaBo agendaBo = ((AgendaEditor) document.getDocumentDataObject()).getAgenda();
343 agendaBo.setVersionNumber(null);
344
345 for (AgendaItemBo agendaItem : agendaBo.getItems()) {
346 agendaItem.setVersionNumber(null);
347 }
348 }
349 @Override
350 public void prepareForSave() {
351
352 AgendaEditor agendaEditor = (AgendaEditor) getDataObject();
353 agendaEditor.getAgenda().setAttributes(agendaEditor.getCustomAttributesMap());
354 }
355
356 @Override
357 public void saveDataObject() {
358 AgendaBo agendaBo = ((AgendaEditor) getDataObject()).getAgenda();
359
360
361 for (AgendaItemBo agendaItem : agendaBo.getItems()) {
362 PropositionBo propositionBo = agendaItem.getRule().getProposition();
363 if (propositionBo != null) {
364 saveNewParameterizedTerms(propositionBo);
365 processCustomOperators(propositionBo);
366 }
367 }
368
369 if (agendaBo != null) {
370 flushCacheBeforeSave();
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386 if(this.getMaintenanceAction() != null &&
387 this.getMaintenanceAction().equals(KRADConstants.MAINTENANCE_COPY_ACTION)){
388 List<AgendaItemBo> agendaItems = agendaBo.getItems();
389 agendaBo.setItems(new ArrayList<AgendaItemBo>());
390 getDataObjectService().save(agendaBo);
391
392 for(AgendaItemBo item : agendaItems) {
393 getDataObjectService().save(item);
394 getDataObjectService().flush(AgendaItemBo.class);
395 }
396
397 agendaBo.setItems(agendaItems);
398 }else{
399 getDataObjectService().save(agendaBo);
400 }
401 } else {
402 throw new RuntimeException("Cannot save object of type: " + agendaBo + " with business object service");
403 }
404 }
405
406
407 private void addItemsToListForDeletion(List<AgendaItemBo> deletionOrder, AgendaItemBo agendaItemBo){
408 if (!deletionOrder.contains(agendaItemBo) && ObjectUtils.isNotNull(agendaItemBo)) {
409 deletionOrder.add(agendaItemBo);
410 }
411 if (ObjectUtils.isNotNull(agendaItemBo)) {
412 if (StringUtils.isNotBlank(agendaItemBo.getWhenTrueId()) &&
413 !deletionOrder.contains(agendaItemBo.getWhenTrue())) {
414 deletionOrder.add(agendaItemBo.getWhenTrue());
415 addItemsToListForDeletion (deletionOrder, agendaItemBo.getWhenTrue());
416 }
417 if (StringUtils.isNotBlank(agendaItemBo.getWhenFalseId()) &&
418 !deletionOrder.contains(agendaItemBo.getWhenFalse())) {
419 deletionOrder.add(agendaItemBo.getWhenFalse());
420 addItemsToListForDeletion (deletionOrder, agendaItemBo.getWhenFalse());
421 }
422 if (StringUtils.isNotBlank(agendaItemBo.getAlwaysId()) &&
423 !deletionOrder.contains(agendaItemBo.getAlways())) {
424 deletionOrder.add(agendaItemBo.getAlways());
425 addItemsToListForDeletion (deletionOrder,agendaItemBo.getAlways());
426 }
427 }
428 }
429
430 private void flushCacheBeforeSave(){
431
432 DistributedCacheManagerDecorator distributedCacheManagerDecorator =
433 GlobalResourceLoader.getService(KrmsConstants.KRMS_DISTRIBUTED_CACHE);
434
435 distributedCacheManagerDecorator.getCache(ActionDefinition.Cache.NAME).clear();
436 distributedCacheManagerDecorator.getCache(AgendaItemDefinition.Cache.NAME).clear();
437 distributedCacheManagerDecorator.getCache(AgendaTreeDefinition.Cache.NAME).clear();
438 distributedCacheManagerDecorator.getCache(AgendaDefinition.Cache.NAME).clear();
439 distributedCacheManagerDecorator.getCache(ContextDefinition.Cache.NAME).clear();
440 distributedCacheManagerDecorator.getCache(KrmsAttributeDefinition.Cache.NAME).clear();
441 distributedCacheManagerDecorator.getCache(KrmsTypeDefinition.Cache.NAME).clear();
442 distributedCacheManagerDecorator.getCache(RuleDefinition.Cache.NAME).clear();
443 distributedCacheManagerDecorator.getCache(PropositionDefinition.Cache.NAME).clear();
444 distributedCacheManagerDecorator.getCache(RuleDefinition.Cache.NAME).clear();
445 distributedCacheManagerDecorator.getCache(TermDefinition.Cache.NAME).clear();
446 distributedCacheManagerDecorator.getCache(TermResolverDefinition.Cache.NAME).clear();
447 distributedCacheManagerDecorator.getCache(TermSpecificationDefinition.Cache.NAME).clear();
448 }
449
450
451
452
453
454
455 private void saveNewParameterizedTerms(PropositionBo propositionBo) {
456 if (StringUtils.isBlank(propositionBo.getCompoundOpCode())) {
457
458 if (!propositionBo.getParameters().isEmpty() && propositionBo.getParameters().get(0).getValue().startsWith(
459 KrmsImplConstants.PARAMETERIZED_TERM_PREFIX)) {
460 String termId = propositionBo.getParameters().get(0).getValue();
461 String termSpecId = termId.substring(KrmsImplConstants.PARAMETERIZED_TERM_PREFIX.length());
462
463 TermBo newTerm = new TermBo();
464 newTerm.setDescription(propositionBo.getNewTermDescription());
465 newTerm.setSpecificationId(termSpecId);
466 newTerm.setId(termIdIncrementer.getNewId());
467
468 List<TermParameterBo> params = new ArrayList<TermParameterBo>();
469 for (Map.Entry<String, String> entry : propositionBo.getTermParameters().entrySet()) {
470 TermParameterBo param = new TermParameterBo();
471 param.setTerm(newTerm);
472 param.setName(entry.getKey());
473 param.setValue(entry.getValue());
474 param.setId(termParameterIdIncrementer.getNewId());
475
476 params.add(param);
477 }
478
479 newTerm.setParameters(params);
480
481 getLegacyDataAdapter().linkAndSave(newTerm);
482 propositionBo.getParameters().get(0).setValue(newTerm.getId());
483 }
484 } else {
485
486 for (PropositionBo childProp : propositionBo.getCompoundComponents()) {
487 saveNewParameterizedTerms(childProp);
488 }
489 }
490 }
491
492
493
494
495
496
497 private void processCustomOperators(PropositionBo propositionBo) {
498 if (StringUtils.isBlank(propositionBo.getCompoundOpCode())) {
499
500 if (!propositionBo.getParameters().isEmpty() && propositionBo.getParameters().get(2).getValue().startsWith(
501 KrmsImplConstants.CUSTOM_OPERATOR_PREFIX)) {
502 PropositionParameterBo operatorParam = propositionBo.getParameters().get(2);
503
504 CustomOperator customOperator =
505 KrmsServiceLocatorInternal.getCustomOperatorUiTranslator().getCustomOperator(operatorParam.getValue());
506
507 FunctionDefinition operatorFunctionDefinition = customOperator.getOperatorFunctionDefinition();
508
509 operatorParam.setParameterType(PropositionParameterType.FUNCTION.getCode());
510 operatorParam.setValue(operatorFunctionDefinition.getId());
511 }
512 } else {
513
514 for (PropositionBo childProp : propositionBo.getCompoundComponents()) {
515 processCustomOperators(childProp);
516 }
517 }
518 }
519
520
521
522
523
524
525
526
527 private Map<String, KrmsAttributeDefinition> buildAttributeDefinitionMap(String agendaTypeId) {
528 KrmsAttributeDefinitionService attributeDefinitionService =
529 KrmsRepositoryServiceLocator.getKrmsAttributeDefinitionService();
530
531
532 Map<String, KrmsAttributeDefinition> attributeDefinitionMap = new HashMap<String, KrmsAttributeDefinition>();
533
534 List<KrmsAttributeDefinition> attributeDefinitions = attributeDefinitionService.findAttributeDefinitionsByType(
535 agendaTypeId);
536
537 for (KrmsAttributeDefinition attributeDefinition : attributeDefinitions) {
538 attributeDefinitionMap.put(attributeDefinition.getName(), attributeDefinition);
539 }
540 return attributeDefinitionMap;
541 }
542
543 @Override
544 public boolean isOldDataObjectInDocument() {
545 boolean isOldDataObjectInExistence = true;
546
547 if (getDataObject() == null) {
548 isOldDataObjectInExistence = false;
549 } else {
550
551 Map<String, ?> keyFieldValues = getLegacyDataAdapter().getPrimaryKeyFieldValues(
552 ((AgendaEditor) getDataObject()).getAgenda());
553 for (Object keyValue : keyFieldValues.values()) {
554 if (keyValue == null) {
555 isOldDataObjectInExistence = false;
556 } else if ((keyValue instanceof String) && StringUtils.isBlank((String) keyValue)) {
557 isOldDataObjectInExistence = false;
558 }
559
560 if (!isOldDataObjectInExistence) {
561 break;
562 }
563 }
564 }
565
566 return isOldDataObjectInExistence;
567 }
568
569
570 @Override
571 public Class getDataObjectClass() {
572 return AgendaBo.class;
573 }
574
575 @Override
576 public boolean isLockable() {
577 return true;
578 }
579
580 @Override
581 public void processBeforeAddLine(ViewModel model, Object addLine, String collectionId, String collectionPath) {
582 AgendaEditor agendaEditor = getAgendaEditor(model);
583 if (addLine instanceof ActionBo) {
584 ((ActionBo) addLine).setNamespace(agendaEditor.getAgendaItemLine().getRule().getNamespace());
585 }
586
587 super.processBeforeAddLine(model, addLine, collectionId, collectionPath);
588 }
589 }