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.resourceloader.GlobalResourceLoader;
22 import org.kuali.rice.core.api.uif.DataType;
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.bo.PersistableBusinessObject;
29 import org.kuali.rice.krad.maintenance.Maintainable;
30 import org.kuali.rice.krad.maintenance.MaintainableImpl;
31 import org.kuali.rice.krad.maintenance.MaintenanceDocument;
32 import org.kuali.rice.krad.service.BusinessObjectService;
33 import org.kuali.rice.krad.service.KRADServiceLocator;
34 import org.kuali.rice.krad.service.SequenceAccessorService;
35 import org.kuali.rice.krad.uif.container.CollectionGroup;
36 import org.kuali.rice.krad.uif.container.Container;
37 import org.kuali.rice.krad.uif.view.View;
38 import org.kuali.rice.krad.util.KRADConstants;
39 import org.kuali.rice.krad.util.ObjectUtils;
40 import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
41 import org.kuali.rice.krms.api.KrmsConstants;
42 import org.kuali.rice.krms.api.repository.action.ActionDefinition;
43 import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
44 import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition;
45 import org.kuali.rice.krms.api.repository.agenda.AgendaTreeDefinition;
46 import org.kuali.rice.krms.api.repository.context.ContextDefinition;
47 import org.kuali.rice.krms.api.repository.function.FunctionDefinition;
48 import org.kuali.rice.krms.api.repository.operator.CustomOperator;
49 import org.kuali.rice.krms.api.repository.proposition.PropositionDefinition;
50 import org.kuali.rice.krms.api.repository.proposition.PropositionParameterType;
51 import org.kuali.rice.krms.api.repository.rule.RuleDefinition;
52 import org.kuali.rice.krms.api.repository.term.TermDefinition;
53 import org.kuali.rice.krms.api.repository.term.TermResolverDefinition;
54 import org.kuali.rice.krms.api.repository.term.TermSpecificationDefinition;
55 import org.kuali.rice.krms.api.repository.type.KrmsAttributeDefinition;
56 import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
57 import org.kuali.rice.krms.impl.repository.ActionBo;
58 import org.kuali.rice.krms.impl.repository.AgendaBo;
59 import org.kuali.rice.krms.impl.repository.AgendaItemBo;
60 import org.kuali.rice.krms.impl.repository.ContextBoService;
61 import org.kuali.rice.krms.impl.repository.KrmsAttributeDefinitionService;
62 import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
63 import org.kuali.rice.krms.impl.repository.PropositionBo;
64 import org.kuali.rice.krms.impl.repository.PropositionParameterBo;
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
80
81
82
83
84 public class AgendaEditorMaintainable extends MaintainableImpl {
85
86 private static final long serialVersionUID = 1L;
87
88 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(
89 AgendaEditorMaintainable.class);
90
91 public static final String NEW_AGENDA_EDITOR_DOCUMENT_TEXT = "New Agenda Editor Document";
92
93 private transient SequenceAccessorService sequenceAccessorService;
94
95 private transient KrmsRetriever krmsRetriever = new KrmsRetriever();
96
97
98
99
100 public BusinessObjectService getBoService() {
101 return KRADServiceLocator.getBusinessObjectService();
102 }
103
104
105
106
107 private ContextBoService getContextBoService() {
108 return KrmsRepositoryServiceLocator.getContextBoService();
109 }
110
111 public List<RemotableAttributeField> retrieveAgendaCustomAttributes(View view, Object model, Container container) {
112 AgendaEditor agendaEditor = getAgendaEditor(model);
113 return krmsRetriever.retrieveAgendaCustomAttributes(agendaEditor);
114 }
115
116
117
118
119
120 public List<RemotableAttributeField> retrieveTermParameters(View view, Object model, Container container) {
121
122 List<RemotableAttributeField> results = new ArrayList<RemotableAttributeField>();
123
124 AgendaEditor agendaEditor = getAgendaEditor(model);
125
126
127 RuleBo rule = agendaEditor.getAgendaItemLine().getRule();
128 if (null != rule) {
129
130
131 Tree<RuleTreeNode, String> propositionTree = rule.getPropositionTree();
132 Node<RuleTreeNode, String> editedPropositionNode = findEditedProposition(propositionTree.getRootElement());
133
134 if (editedPropositionNode != null) {
135 PropositionBo propositionBo = editedPropositionNode.getData().getProposition();
136 if (StringUtils.isEmpty(propositionBo.getCompoundOpCode()) && CollectionUtils.size(
137 propositionBo.getParameters()) > 0) {
138
139 PropositionParameterBo param = propositionBo.getParameters().get(0);
140 if (param.getValue().startsWith(KrmsImplConstants.PARAMETERIZED_TERM_PREFIX)) {
141 String termSpecId = param.getValue().substring(
142 KrmsImplConstants.PARAMETERIZED_TERM_PREFIX.length());
143 TermResolverDefinition simplestResolver = getSimplestTermResolver(termSpecId,
144 rule.getNamespace());
145
146
147 if (simplestResolver != null) {
148 List<String> parameterNames = new ArrayList<String>(simplestResolver.getParameterNames());
149 Collections.sort(parameterNames);
150
151 for (String parameterName : parameterNames) {
152
153 RemotableTextInput.Builder controlBuilder = RemotableTextInput.Builder.create();
154 controlBuilder.setSize(64);
155
156 RemotableAttributeField.Builder builder = RemotableAttributeField.Builder.create(
157 parameterName);
158
159 builder.setRequired(true);
160 builder.setDataType(DataType.STRING);
161 builder.setControl(controlBuilder);
162 builder.setLongLabel(parameterName);
163 builder.setShortLabel(parameterName);
164 builder.setMinLength(Integer.valueOf(1));
165 builder.setMaxLength(Integer.valueOf(64));
166
167 results.add(builder.build());
168 }
169 }
170 }
171 }
172 }
173 }
174 return results;
175 }
176
177
178
179
180
181
182
183
184
185 static TermResolverDefinition getSimplestTermResolver(String termSpecId,
186 String namespace) {
187
188 List<TermResolverDefinition> resolvers =
189 KrmsRepositoryServiceLocator.getTermBoService().findTermResolversByOutputId(termSpecId, namespace);
190
191 TermResolverDefinition simplestResolver = null;
192
193 for (TermResolverDefinition resolver : resolvers) {
194 if (simplestResolver == null || simplestResolver.getParameterNames().size() < resolver.getParameterNames()
195 .size()) {
196 simplestResolver = resolver;
197 }
198 }
199
200 return simplestResolver;
201 }
202
203
204
205
206
207
208
209 private Node<RuleTreeNode, String> findEditedProposition(Node<RuleTreeNode, String> node) {
210 Node<RuleTreeNode, String> result = null;
211 if (node.getData() != null && node.getData().getProposition() != null && node.getData().getProposition()
212 .getEditMode()) {
213 result = node;
214 } else {
215 for (Node<RuleTreeNode, String> child : node.getChildren()) {
216 result = findEditedProposition(child);
217 if (result != null) {
218 break;
219 }
220 }
221 }
222 return result;
223 }
224
225
226
227
228
229
230
231 private AgendaEditor getAgendaEditor(Object model) {
232 MaintenanceDocumentForm maintenanceForm = (MaintenanceDocumentForm) model;
233 return (AgendaEditor) maintenanceForm.getDocument().getNewMaintainableObject().getDataObject();
234 }
235
236 public List<RemotableAttributeField> retrieveRuleActionCustomAttributes(View view, Object model,
237 Container container) {
238 AgendaEditor agendaEditor = getAgendaEditor((MaintenanceDocumentForm) model);
239 return krmsRetriever.retrieveRuleActionCustomAttributes(agendaEditor);
240 }
241
242
243
244
245 public List<RemotableAttributeField> retrieveRuleCustomAttributes(View view, Object model, Container container) {
246 AgendaEditor agendaEditor = getAgendaEditor((MaintenanceDocumentForm) model);
247 return krmsRetriever.retrieveRuleCustomAttributes(agendaEditor);
248 }
249
250 @Override
251 public Object retrieveObjectForEditOrCopy(MaintenanceDocument document, Map<String, String> dataObjectKeys) {
252 Object dataObject = null;
253
254 try {
255
256 AgendaEditor agendaEditor = new AgendaEditor();
257 AgendaBo agenda = getLookupService().findObjectBySearch(
258 ((AgendaEditor) getDataObject()).getAgenda().getClass(), dataObjectKeys);
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
293
294
295
296
297 private SequenceAccessorService getSequenceAccessorService() {
298 if (sequenceAccessorService == null) {
299 sequenceAccessorService = KRADServiceLocator.getSequenceAccessorService();
300 }
301 return sequenceAccessorService;
302 }
303
304
305
306
307 @Override
308 public void processAfterNew(MaintenanceDocument document, Map<String, String[]> requestParameters) {
309 super.processAfterNew(document, requestParameters);
310 document.getDocumentHeader().setDocumentDescription(NEW_AGENDA_EDITOR_DOCUMENT_TEXT);
311 }
312
313 @Override
314 public void processAfterEdit(MaintenanceDocument document, Map<String, String[]> requestParameters) {
315 super.processAfterEdit(document, requestParameters);
316 document.getDocumentHeader().setDocumentDescription("Modify Agenda Editor Document");
317 }
318
319 @Override
320 public void prepareForSave() {
321
322 AgendaEditor agendaEditor = (AgendaEditor) getDataObject();
323 agendaEditor.getAgenda().setAttributes(agendaEditor.getCustomAttributesMap());
324 }
325
326 @Override
327 public void saveDataObject() {
328 AgendaBo agendaBo = ((AgendaEditor) getDataObject()).getAgenda();
329
330
331 for (AgendaItemBo agendaItem : agendaBo.getItems()) {
332 PropositionBo propositionBo = agendaItem.getRule().getProposition();
333 if (propositionBo != null) {
334 saveNewParameterizedTerms(propositionBo);
335 processCustomOperators(propositionBo);
336 }
337 }
338
339 if (agendaBo instanceof PersistableBusinessObject) {
340 Map<String, String> primaryKeys = new HashMap<String, String>();
341 primaryKeys.put("id", agendaBo.getId());
342 AgendaBo dbAgendaBo = getBusinessObjectService().findByPrimaryKey(AgendaBo.class, primaryKeys);
343
344 if (ObjectUtils.isNotNull(dbAgendaBo)) {
345 Map<String, String> primaryKeyForFirstItem = new HashMap<String, String>();
346 primaryKeyForFirstItem.put("id", dbAgendaBo.getFirstItemId());
347 AgendaItemBo dbFirstAgendaItemBo = getBusinessObjectService().findByPrimaryKey(AgendaItemBo.class,
348 primaryKeyForFirstItem);
349
350 List<AgendaItemBo> deletionOrder = new ArrayList<AgendaItemBo>();
351 addItemsToListForDeletion(deletionOrder, dbFirstAgendaItemBo);
352
353 for (AgendaItemBo agendaItemToDelete : deletionOrder) {
354 getBusinessObjectService().delete(agendaItemToDelete);
355 }
356
357 dbAgendaBo.setItems(null);
358 getBusinessObjectService().delete(dbAgendaBo);
359 }
360
361 flushCacheBeforeSave();
362
363 getBusinessObjectService().linkAndSave(agendaBo);
364 } else {
365 throw new RuntimeException("Cannot save object of type: " + agendaBo + " with business object service");
366 }
367 }
368
369
370 private void addItemsToListForDeletion(List<AgendaItemBo> deletionOrder, AgendaItemBo agendaItemBo){
371 if (!deletionOrder.contains(agendaItemBo) && ObjectUtils.isNotNull(agendaItemBo)) {
372 deletionOrder.add(agendaItemBo);
373 }
374 if (ObjectUtils.isNotNull(agendaItemBo)) {
375 if (StringUtils.isNotBlank(agendaItemBo.getWhenTrueId()) &&
376 !deletionOrder.contains(agendaItemBo.getWhenTrue())) {
377 deletionOrder.add(agendaItemBo.getWhenTrue());
378 addItemsToListForDeletion (deletionOrder, agendaItemBo.getWhenTrue());
379 }
380 if (StringUtils.isNotBlank(agendaItemBo.getWhenFalseId()) &&
381 !deletionOrder.contains(agendaItemBo.getWhenFalse())) {
382 deletionOrder.add(agendaItemBo.getWhenFalse());
383 addItemsToListForDeletion (deletionOrder, agendaItemBo.getWhenFalse());
384 }
385 if (StringUtils.isNotBlank(agendaItemBo.getAlwaysId()) &&
386 !deletionOrder.contains(agendaItemBo.getAlways())) {
387 deletionOrder.add(agendaItemBo.getAlways());
388 addItemsToListForDeletion (deletionOrder,agendaItemBo.getAlways());
389 }
390 }
391 }
392
393 private void flushCacheBeforeSave(){
394
395 DistributedCacheManagerDecorator distributedCacheManagerDecorator =
396 GlobalResourceLoader.getService(KrmsConstants.KRMS_DISTRIBUTED_CACHE);
397
398 distributedCacheManagerDecorator.getCache(ActionDefinition.Cache.NAME).clear();
399 distributedCacheManagerDecorator.getCache(AgendaItemDefinition.Cache.NAME).clear();
400 distributedCacheManagerDecorator.getCache(AgendaTreeDefinition.Cache.NAME).clear();
401 distributedCacheManagerDecorator.getCache(AgendaDefinition.Cache.NAME).clear();
402 distributedCacheManagerDecorator.getCache(ContextDefinition.Cache.NAME).clear();
403 distributedCacheManagerDecorator.getCache(KrmsAttributeDefinition.Cache.NAME).clear();
404 distributedCacheManagerDecorator.getCache(KrmsTypeDefinition.Cache.NAME).clear();
405 distributedCacheManagerDecorator.getCache(RuleDefinition.Cache.NAME).clear();
406 distributedCacheManagerDecorator.getCache(PropositionDefinition.Cache.NAME).clear();
407 distributedCacheManagerDecorator.getCache(RuleDefinition.Cache.NAME).clear();
408 distributedCacheManagerDecorator.getCache(TermDefinition.Cache.NAME).clear();
409 distributedCacheManagerDecorator.getCache(TermResolverDefinition.Cache.NAME).clear();
410 distributedCacheManagerDecorator.getCache(TermSpecificationDefinition.Cache.NAME).clear();
411 }
412
413
414
415
416
417
418 private void saveNewParameterizedTerms(PropositionBo propositionBo) {
419 if (StringUtils.isBlank(propositionBo.getCompoundOpCode())) {
420
421 if (!propositionBo.getParameters().isEmpty() && propositionBo.getParameters().get(0).getValue().startsWith(
422 KrmsImplConstants.PARAMETERIZED_TERM_PREFIX)) {
423 String termId = propositionBo.getParameters().get(0).getValue();
424 String termSpecId = termId.substring(KrmsImplConstants.PARAMETERIZED_TERM_PREFIX.length());
425
426 TermBo newTerm = new TermBo();
427 newTerm.setDescription(propositionBo.getNewTermDescription());
428 newTerm.setSpecificationId(termSpecId);
429 newTerm.setId(KRADServiceLocator.getSequenceAccessorService().getNextAvailableSequenceNumber(
430 KrmsMaintenanceConstants.Sequences.TERM_SPECIFICATION, TermBo.class).toString());
431
432 List<TermParameterBo> params = new ArrayList<TermParameterBo>();
433 for (Map.Entry<String, String> entry : propositionBo.getTermParameters().entrySet()) {
434 TermParameterBo param = new TermParameterBo();
435 param.setTermId(newTerm.getId());
436 param.setName(entry.getKey());
437 param.setValue(entry.getValue());
438 param.setId(KRADServiceLocator.getSequenceAccessorService().getNextAvailableSequenceNumber(
439 KrmsMaintenanceConstants.Sequences.TERM_PARAMETER, TermParameterBo.class).toString());
440
441 params.add(param);
442 }
443
444 newTerm.setParameters(params);
445
446 KRADServiceLocator.getBusinessObjectService().linkAndSave(newTerm);
447 propositionBo.getParameters().get(0).setValue(newTerm.getId());
448 }
449 } else {
450
451 for (PropositionBo childProp : propositionBo.getCompoundComponents()) {
452 saveNewParameterizedTerms(childProp);
453 }
454 }
455 }
456
457
458
459
460
461
462 private void processCustomOperators(PropositionBo propositionBo) {
463 if (StringUtils.isBlank(propositionBo.getCompoundOpCode())) {
464
465 if (!propositionBo.getParameters().isEmpty() && propositionBo.getParameters().get(2).getValue().startsWith(
466 KrmsImplConstants.CUSTOM_OPERATOR_PREFIX)) {
467 PropositionParameterBo operatorParam = propositionBo.getParameters().get(2);
468
469 CustomOperator customOperator =
470 KrmsServiceLocatorInternal.getCustomOperatorUiTranslator().getCustomOperator(operatorParam.getValue());
471
472 FunctionDefinition operatorFunctionDefinition = customOperator.getOperatorFunctionDefinition();
473
474 operatorParam.setParameterType(PropositionParameterType.FUNCTION.getCode());
475 operatorParam.setValue(operatorFunctionDefinition.getId());
476 }
477 } else {
478
479 for (PropositionBo childProp : propositionBo.getCompoundComponents()) {
480 processCustomOperators(childProp);
481 }
482 }
483 }
484
485
486
487
488
489
490
491
492 private Map<String, KrmsAttributeDefinition> buildAttributeDefinitionMap(String agendaTypeId) {
493 KrmsAttributeDefinitionService attributeDefinitionService =
494 KrmsRepositoryServiceLocator.getKrmsAttributeDefinitionService();
495
496
497 Map<String, KrmsAttributeDefinition> attributeDefinitionMap = new HashMap<String, KrmsAttributeDefinition>();
498
499 List<KrmsAttributeDefinition> attributeDefinitions = attributeDefinitionService.findAttributeDefinitionsByType(
500 agendaTypeId);
501
502 for (KrmsAttributeDefinition attributeDefinition : attributeDefinitions) {
503 attributeDefinitionMap.put(attributeDefinition.getName(), attributeDefinition);
504 }
505 return attributeDefinitionMap;
506 }
507
508 @Override
509 public boolean isOldDataObjectInDocument() {
510 boolean isOldDataObjectInExistence = true;
511
512 if (getDataObject() == null) {
513 isOldDataObjectInExistence = false;
514 } else {
515
516 Map<String, ?> keyFieldValues = getDataObjectMetaDataService().getPrimaryKeyFieldValues(
517 ((AgendaEditor) getDataObject()).getAgenda());
518 for (Object keyValue : keyFieldValues.values()) {
519 if (keyValue == null) {
520 isOldDataObjectInExistence = false;
521 } else if ((keyValue instanceof String) && StringUtils.isBlank((String) keyValue)) {
522 isOldDataObjectInExistence = false;
523 }
524
525 if (!isOldDataObjectInExistence) {
526 break;
527 }
528 }
529 }
530
531 return isOldDataObjectInExistence;
532 }
533
534
535 @Override
536 public Class getDataObjectClass() {
537 return AgendaBo.class;
538 }
539
540 @Override
541 public boolean isLockable() {
542 return true;
543 }
544
545 @Override
546 public PersistableBusinessObject getPersistableBusinessObject() {
547 return ((AgendaEditor) getDataObject()).getAgenda();
548 }
549
550 @Override
551 protected void processBeforeAddLine(View view, CollectionGroup collectionGroup, Object model, Object addLine) {
552 AgendaEditor agendaEditor = getAgendaEditor(model);
553 if (addLine instanceof ActionBo) {
554 ((ActionBo) addLine).setNamespace(agendaEditor.getAgendaItemLine().getRule().getNamespace());
555 }
556
557 super.processBeforeAddLine(view, collectionGroup, model, addLine);
558 }
559 }