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