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 org.apache.commons.lang.StringUtils;
19 import org.kuali.rice.core.api.criteria.Predicate;
20 import org.kuali.rice.core.api.criteria.QueryByCriteria;
21 import org.kuali.rice.core.api.criteria.QueryResults;
22 import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
23 import org.kuali.rice.core.api.exception.RiceIllegalStateException;
24 import org.kuali.rice.core.api.mo.ModelObjectUtils;
25 import org.kuali.rice.krad.data.DataObjectService;
26 import org.kuali.rice.krad.data.PersistenceOption;
27 import org.kuali.rice.krad.service.KRADServiceLocator;
28 import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
29 import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition;
30 import org.kuali.rice.krms.api.repository.type.KrmsAttributeDefinition;
31 import org.springframework.util.CollectionUtils;
32
33 import java.util.ArrayList;
34 import java.util.Collection;
35 import java.util.Collections;
36 import java.util.HashMap;
37 import java.util.HashSet;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Map.Entry;
41 import java.util.Set;
42
43 import static org.kuali.rice.core.api.criteria.PredicateFactory.in;
44 import static org.kuali.rice.krms.impl.repository.BusinessObjectServiceMigrationUtils.*;
45
46
47
48
49
50
51
52 public class AgendaBoServiceImpl implements AgendaBoService {
53
54
55
56
57 private static final ModelObjectUtils.Transformer<AgendaItemBo, AgendaItemDefinition> toAgendaItemDefinition =
58 new ModelObjectUtils.Transformer<AgendaItemBo, AgendaItemDefinition>() {
59 public AgendaItemDefinition transform(AgendaItemBo input) {
60 return AgendaItemBo.to(input);
61 };
62 };
63
64 private static final ModelObjectUtils.Transformer<AgendaBo, AgendaDefinition> toAgendaDefinition =
65 new ModelObjectUtils.Transformer<AgendaBo, AgendaDefinition>() {
66 public AgendaDefinition transform(AgendaBo input) {
67 return AgendaBo.to(input);
68 };
69 };
70
71 private DataObjectService dataObjectService;
72 private KrmsAttributeDefinitionService attributeDefinitionService;
73
74
75
76
77 @Override
78 public AgendaDefinition createAgenda(AgendaDefinition agenda) {
79 if (agenda == null) {
80 throw new RiceIllegalArgumentException("agenda is null");
81 }
82 final String nameKey = agenda.getName();
83 final String contextId = agenda.getContextId();
84 final AgendaDefinition existing = getAgendaByNameAndContextId(nameKey, contextId);
85 if (existing != null) {
86 throw new IllegalStateException("the agenda to create already exists: " + agenda);
87 }
88
89 AgendaBo agendaBo = from(agenda);
90 agendaBo = getDataObjectService().save(agendaBo, PersistenceOption.FLUSH);
91 return to(agendaBo);
92 }
93
94
95
96
97 @Override
98 public AgendaDefinition updateAgenda(AgendaDefinition agendaDefinition) {
99 if (agendaDefinition == null) {
100 throw new RiceIllegalArgumentException("agenda is null");
101 }
102
103
104 final String agendaDefinitionId = agendaDefinition.getId();
105
106
107 final AgendaBo agendaBoExisting = getDataObjectService().find(AgendaBo.class, agendaDefinitionId);
108 if (agendaBoExisting == null) {
109 throw new IllegalStateException("the agenda does not exist: " + agendaDefinition);
110 }
111
112 final AgendaDefinition agendaDefinitionToUpdate;
113 if (agendaBoExisting.getId().equals(agendaDefinition.getId())) {
114 agendaDefinitionToUpdate = agendaDefinition;
115 } else {
116
117 final AgendaDefinition.Builder builder = AgendaDefinition.Builder.create(agendaDefinition);
118 builder.setId(agendaBoExisting.getId());
119 agendaDefinitionToUpdate = builder.build();
120 }
121
122
123 AgendaBo agendaBoToUpdate = from(agendaDefinitionToUpdate);
124
125
126 agendaBoToUpdate.setItems(agendaBoExisting.getItems());
127 if (StringUtils.isNotBlank(agendaDefinition.getFirstItemId())) {
128 agendaBoToUpdate.setFirstItem(getDataObjectService().find(AgendaItemBo.class, agendaDefinition.getFirstItemId()));
129 }
130
131
132 Map<String, String> fields = new HashMap<String, String>(1);
133 fields.put("agenda.id", agendaDefinitionToUpdate.getId());
134
135 deleteMatching(getDataObjectService(), AgendaAttributeBo.class, fields);
136
137
138 ArrayList<String> agendaItemsIds = new ArrayList<String>();
139
140
141 HashMap<String, AgendaItemBo> mapIdToBo = new HashMap<String, AgendaItemBo>();
142
143
144 ArrayList<String> agendaItemIdsReferenced = new ArrayList<String>();
145 List<AgendaItemBo> items = agendaBoToUpdate.getItems();
146 for (AgendaItemBo agendaItemBo : items) {
147 agendaItemsIds.add(agendaItemBo.getId());
148 mapIdToBo.put(agendaItemBo.getId(), agendaItemBo);
149
150 if (agendaItemBo.getAlwaysId() != null) {
151 agendaItemIdsReferenced.add(agendaItemBo.getAlwaysId());
152 }
153
154 if (agendaItemBo.getWhenTrueId() != null) {
155 agendaItemIdsReferenced.add(agendaItemBo.getWhenTrueId());
156 }
157
158 if (agendaItemBo.getWhenFalseId() != null) {
159 agendaItemIdsReferenced.add(agendaItemBo.getWhenFalseId());
160 }
161 }
162
163
164 AgendaBo agendaBoUpdated = getDataObjectService().save(agendaBoToUpdate, PersistenceOption.FLUSH);
165
166
167 ArrayList<String> agendaItemIdsActuallyUsed = new ArrayList<String>();
168 if (agendaBoUpdated.getFirstItem() != null) {
169 AgendaItemBo agendaItemBoTop = agendaBoUpdated.getFirstItem();
170
171 AgendaItemBo agendaItemBoCurrent = agendaItemBoTop;
172 agendaItemIdsActuallyUsed.add(agendaItemBoCurrent.getId());
173
174
175 while (agendaItemBoCurrent != null) {
176 if (StringUtils.isNotEmpty(agendaItemBoCurrent.getAlwaysId())) {
177 agendaItemIdsActuallyUsed.add(agendaItemBoCurrent.getAlwaysId());
178 }
179
180 agendaItemBoCurrent = agendaItemBoCurrent.getAlways();
181 }
182
183
184 agendaItemBoCurrent = agendaItemBoTop;
185 while (agendaItemBoCurrent != null) {
186 if (StringUtils.isNotEmpty(agendaItemBoCurrent.getWhenTrueId())) {
187 agendaItemIdsActuallyUsed.add(agendaItemBoCurrent.getWhenTrueId());
188 }
189
190 agendaItemBoCurrent = agendaItemBoCurrent.getWhenTrue();
191 }
192
193
194 agendaItemBoCurrent = agendaItemBoTop;
195 while (agendaItemBoCurrent != null) {
196 if (StringUtils.isNotEmpty(agendaItemBoCurrent.getWhenFalseId())) {
197 agendaItemIdsActuallyUsed.add(agendaItemBoCurrent.getWhenFalseId());
198 }
199
200 agendaItemBoCurrent = agendaItemBoCurrent.getWhenFalse();
201 }
202 }
203
204
205 for (String sIdActuallyUsed : agendaItemIdsActuallyUsed) {
206 if (agendaItemsIds.contains(sIdActuallyUsed)) {
207 agendaItemsIds.remove(sIdActuallyUsed);
208 }
209 }
210
211
212
213 for (String sAiboId : agendaItemsIds) {
214 boolean bReferenced = agendaItemIdsReferenced.contains(sAiboId);
215 if (bReferenced == false) {
216 AgendaItemBo aibo = mapIdToBo.get(sAiboId);
217 getDataObjectService().delete(aibo);
218 }
219 }
220
221 return to(agendaBoUpdated);
222 }
223
224 @Override
225 public void deleteAgenda(String agendaId) {
226 if (agendaId == null) {
227 throw new RiceIllegalArgumentException("agendaId is null");
228 }
229
230 final AgendaBo bo = getDataObjectService().find(AgendaBo.class, agendaId);
231
232 if (bo == null) {
233 throw new IllegalStateException("the Agenda to delete does not exist: " + agendaId);
234 }
235
236
237 AgendaItemBo firstAgendaItem = bo.getFirstItem();
238
239 if (firstAgendaItem != null) {
240 getDataObjectService().delete(firstAgendaItem);
241 getDataObjectService().flush(AgendaItemBo.class);
242
243 bo.setFirstItem(null);
244 bo.setItems(null);
245 }
246
247 getDataObjectService().delete(bo);
248 }
249
250
251
252
253 @Override
254 public AgendaDefinition getAgendaByAgendaId(String agendaId) {
255 if (StringUtils.isBlank(agendaId)) {
256 throw new RiceIllegalArgumentException("agenda id is null or blank");
257 }
258 AgendaBo bo = getDataObjectService().find(AgendaBo.class, agendaId);
259 return to(bo);
260 }
261
262
263
264
265 @Override
266 public AgendaDefinition getAgendaByNameAndContextId(String name, String contextId) {
267 if (StringUtils.isBlank(name)) {
268 throw new RiceIllegalArgumentException("name is blank");
269 }
270 if (StringUtils.isBlank(contextId)) {
271 throw new RiceIllegalArgumentException("contextId is blank");
272 }
273
274 final Map<String, Object> map = new HashMap<String, Object>();
275 map.put("name", name);
276 map.put("contextId", contextId);
277
278 AgendaBo myAgenda = findSingleMatching(getDataObjectService(), AgendaBo.class, map);
279 return to(myAgenda);
280 }
281
282
283
284
285 @Override
286 public List<AgendaDefinition> getAgendasByContextId(String contextId) {
287 if (StringUtils.isBlank(contextId)) {
288 throw new RiceIllegalArgumentException("context ID is null or blank");
289 }
290 final Map<String, Object> map = new HashMap<String, Object>();
291 map.put("contextId", contextId);
292 List<AgendaBo> bos = findMatching(getDataObjectService(), AgendaBo.class, map);
293
294 return convertAgendaBosToImmutables(bos);
295 }
296
297
298
299
300 @Override
301 public AgendaItemDefinition createAgendaItem(AgendaItemDefinition agendaItem) {
302 if (agendaItem == null) {
303 throw new RiceIllegalArgumentException("agendaItem is null");
304 }
305 if (agendaItem.getId() != null) {
306 final AgendaDefinition existing = getAgendaByAgendaId(agendaItem.getId());
307 if (existing != null) {
308 throw new IllegalStateException("the agendaItem to create already exists: " + agendaItem);
309 }
310 }
311
312 AgendaItemBo bo = AgendaItemBo.from(agendaItem);
313 if (StringUtils.isNotBlank(agendaItem.getRuleId()) && agendaItem.getRule() == null ) {
314 bo.setRule(getDataObjectService().find(RuleBo.class, agendaItem.getRuleId()));
315 }
316
317 if (StringUtils.isNotBlank(agendaItem.getAlwaysId()) && agendaItem.getAlways() == null ) {
318 bo.setAlways(getDataObjectService().find(AgendaItemBo.class, agendaItem.getAlwaysId()));
319 }
320
321 if (StringUtils.isNotBlank(agendaItem.getWhenTrueId()) && agendaItem.getWhenTrue() == null ) {
322 bo.setWhenTrue(getDataObjectService().find(AgendaItemBo.class, agendaItem.getWhenTrueId()));
323 }
324
325 if (StringUtils.isNotBlank(agendaItem.getWhenFalseId()) && agendaItem.getWhenFalse() == null ) {
326 bo.setWhenFalse(getDataObjectService().find(AgendaItemBo.class, agendaItem.getWhenFalseId()));
327 }
328
329 bo = getDataObjectService().save(bo, PersistenceOption.FLUSH);
330 return AgendaItemBo.to(bo);
331 }
332
333
334
335
336 @Override
337 public AgendaItemDefinition updateAgendaItem(AgendaItemDefinition agendaItem) {
338 if (agendaItem == null) {
339 throw new RiceIllegalArgumentException("agendaItem is null");
340 }
341 final String agendaItemIdKey = agendaItem.getId();
342 final AgendaItemDefinition existing = getAgendaItemById(agendaItemIdKey);
343 if (existing == null) {
344 throw new IllegalStateException("the agenda item does not exist: " + agendaItem);
345 }
346 final AgendaItemDefinition toUpdate;
347 if (existing.getId().equals(agendaItem.getId())) {
348 toUpdate = agendaItem;
349 } else {
350 final AgendaItemDefinition.Builder builder = AgendaItemDefinition.Builder.create(agendaItem);
351 builder.setId(existing.getId());
352 toUpdate = builder.build();
353 }
354
355 AgendaItemBo aiBo = AgendaItemBo.from(toUpdate);
356 final AgendaItemBo updatedData = getDataObjectService().save(aiBo, PersistenceOption.FLUSH);
357 return AgendaItemBo.to(updatedData);
358 }
359
360
361
362
363 @Override
364 public void addAgendaItem(AgendaItemDefinition agendaItem, String parentId, Boolean position) {
365 if (agendaItem == null) {
366 throw new RiceIllegalArgumentException("agendaItem is null");
367 }
368 AgendaItemDefinition parent = null;
369 if (parentId != null) {
370 parent = getAgendaItemById(parentId);
371 if (parent == null) {
372 throw new IllegalStateException(
373 "parent agendaItem does not exist in repository. parentId = " + parentId);
374 }
375 }
376
377 final AgendaItemDefinition toCreate;
378 if (agendaItem.getId() == null) {
379 final AgendaItemDefinition.Builder builder = AgendaItemDefinition.Builder.create(agendaItem);
380 builder.setId(AgendaItemBo.agendaItemIdIncrementer.getNewId());
381 toCreate = builder.build();
382 } else {
383 toCreate = agendaItem;
384 }
385 createAgendaItem(toCreate);
386
387
388 if (parentId != null) {
389 final AgendaItemDefinition.Builder builder = AgendaItemDefinition.Builder.create(parent);
390 if (position == null) {
391 builder.setAlwaysId(toCreate.getId());
392 } else if (position.booleanValue()) {
393 builder.setWhenTrueId(toCreate.getId());
394 } else if (!position.booleanValue()) {
395 builder.setWhenFalseId(toCreate.getId());
396 }
397 final AgendaItemDefinition parentToUpdate = builder.build();
398 updateAgendaItem(parentToUpdate);
399 }
400 }
401
402
403
404
405 @Override
406 public AgendaItemDefinition getAgendaItemById(String id) {
407 if (StringUtils.isBlank(id)) {
408 throw new RiceIllegalArgumentException("agenda item id is null or blank");
409 }
410
411 AgendaItemBo bo = getDataObjectService().find(AgendaItemBo.class, id);
412
413 return AgendaItemBo.to(bo);
414 }
415
416 @Override
417 public List<AgendaItemDefinition> getAgendaItemsByAgendaId(String agendaId) {
418 if (StringUtils.isBlank(agendaId)) {
419 throw new RiceIllegalArgumentException("agenda id is null or null");
420 }
421 List<AgendaItemDefinition> results = null;
422
423 Collection<AgendaItemBo> bos = findMatching(getDataObjectService(), AgendaItemBo.class, Collections.singletonMap(
424 "agendaId", agendaId));
425
426 if (CollectionUtils.isEmpty(bos)) {
427 results = Collections.emptyList();
428 } else {
429 results = Collections.unmodifiableList(ModelObjectUtils.transform(bos, toAgendaItemDefinition));
430 }
431
432 return results;
433 }
434
435 @Override
436 public List<AgendaDefinition> getAgendasByType(String typeId) throws RiceIllegalArgumentException {
437 if (StringUtils.isBlank(typeId)) {
438 throw new RiceIllegalArgumentException("type ID is null or blank");
439 }
440
441 final Map<String, Object> map = new HashMap<String, Object>();
442 map.put("typeId", typeId);
443 List<AgendaBo> bos = findMatching(getDataObjectService(), AgendaBo.class, map);
444
445 return convertAgendaBosToImmutables(bos);
446 }
447
448 @Override
449 public List<AgendaDefinition> getAgendasByTypeAndContext(String typeId, String contextId)
450 throws RiceIllegalArgumentException {
451 if (StringUtils.isBlank(typeId)) {
452 throw new RiceIllegalArgumentException("type ID is null or blank");
453 }
454 if (StringUtils.isBlank(contextId)) {
455 throw new RiceIllegalArgumentException("context ID is null or blank");
456 }
457 final Map<String, Object> map = new HashMap<String, Object>();
458 map.put("typeId", typeId);
459 map.put("contextId", contextId);
460 Collection<AgendaBo> bos = findMatching(getDataObjectService(), AgendaBo.class, map);
461
462 return convertAgendaBosToImmutables(bos);
463 }
464
465 @Override
466 public List<AgendaItemDefinition> getAgendaItemsByType(String typeId) throws RiceIllegalArgumentException {
467 return findAgendaItemsForAgendas(getAgendasByType(typeId));
468 }
469
470 @Override
471 public List<AgendaItemDefinition> getAgendaItemsByContext(String contextId) throws RiceIllegalArgumentException {
472 return findAgendaItemsForAgendas(getAgendasByContextId(contextId));
473 }
474
475 @Override
476 public List<AgendaItemDefinition> getAgendaItemsByTypeAndContext(String typeId, String contextId)
477 throws RiceIllegalArgumentException {
478 return findAgendaItemsForAgendas(getAgendasByTypeAndContext(typeId, contextId));
479 }
480
481 @Override
482 public void deleteAgendaItem(String agendaItemId) throws RiceIllegalArgumentException {
483 if (StringUtils.isBlank(agendaItemId)) {
484 throw new RiceIllegalArgumentException("agendaItemId must not be blank or null");
485 }
486
487 deleteMatching(getDataObjectService(), AgendaItemBo.class, Collections.singletonMap("id", agendaItemId));
488 }
489
490 private List<AgendaItemDefinition> findAgendaItemsForAgendas(List<AgendaDefinition> agendaDefinitions) {
491 List<AgendaItemDefinition> results = null;
492
493 if (!CollectionUtils.isEmpty(agendaDefinitions)) {
494 List<AgendaItemBo> boResults = new ArrayList<AgendaItemBo>(agendaDefinitions.size());
495
496 List<String> agendaIds = new ArrayList<String>(20);
497 for (AgendaDefinition agendaDefinition : agendaDefinitions) {
498 agendaIds.add(agendaDefinition.getId());
499
500 if (agendaIds.size() == 20) {
501
502
503 Predicate predicate = in("agendaId", agendaIds.toArray());
504 QueryByCriteria criteria = QueryByCriteria.Builder.fromPredicates(predicate);
505 QueryResults<AgendaItemBo> batch = getDataObjectService().findMatching(AgendaItemBo.class,
506 criteria);
507
508 boResults.addAll(batch.getResults());
509
510
511 agendaIds.clear();
512 }
513 }
514
515 if (agendaIds.size() > 0) {
516 Predicate predicate = in("agendaId", agendaIds.toArray());
517 QueryByCriteria criteria = QueryByCriteria.Builder.fromPredicates(predicate);
518 QueryResults<AgendaItemBo> batch = getDataObjectService().findMatching(AgendaItemBo.class, criteria);
519
520 boResults.addAll(batch.getResults());
521 }
522
523 results = Collections.unmodifiableList(ModelObjectUtils.transform(boResults, toAgendaItemDefinition));
524 } else {
525 results = Collections.emptyList();
526 }
527
528 return results;
529 }
530
531
532
533
534
535
536
537 public List<AgendaDefinition> convertAgendaBosToImmutables(final Collection<AgendaBo> agendaBos) {
538 if (CollectionUtils.isEmpty(agendaBos)) {
539 return Collections.emptyList();
540 }
541 return Collections.unmodifiableList(ModelObjectUtils.transform(agendaBos, toAgendaDefinition));
542 }
543
544
545
546
547
548
549
550 @Override
551 public AgendaDefinition to(AgendaBo bo) {
552 if (bo == null) {
553 return null;
554 }
555 return org.kuali.rice.krms.api.repository.agenda.AgendaDefinition.Builder.create(bo).build();
556 }
557
558
559
560
561
562
563
564 @Override
565 public AgendaBo from(AgendaDefinition im) {
566 if (im == null) {
567 return null;
568 }
569
570 AgendaBo bo = new AgendaBo();
571 bo.setId(im.getId());
572 bo.setName(im.getName());
573 bo.setTypeId(im.getTypeId());
574 bo.setContextId(im.getContextId());
575 bo.setFirstItemId(im.getFirstItemId());
576 bo.setVersionNumber(im.getVersionNumber());
577 bo.setActive(im.isActive());
578 Set<AgendaAttributeBo> attributes = buildAgendaAttributeBo(im, bo);
579
580 bo.setAttributeBos(attributes);
581
582 return bo;
583 }
584
585 private Set<AgendaAttributeBo> buildAgendaAttributeBo(AgendaDefinition im, AgendaBo agendaBo) {
586 Set<AgendaAttributeBo> attributes = new HashSet<AgendaAttributeBo>();
587
588
589 Map<String, KrmsAttributeDefinition> attributeDefinitionMap = new HashMap<String, KrmsAttributeDefinition>();
590
591 List<KrmsAttributeDefinition> attributeDefinitions =
592 getAttributeDefinitionService().findAttributeDefinitionsByType(im.getTypeId());
593
594 for (KrmsAttributeDefinition attributeDefinition : attributeDefinitions) {
595 attributeDefinitionMap.put(attributeDefinition.getName(), attributeDefinition);
596 }
597
598
599 for (Entry<String, String> entry : im.getAttributes().entrySet()) {
600 KrmsAttributeDefinition attrDef = attributeDefinitionMap.get(entry.getKey());
601
602 if (attrDef != null) {
603 AgendaAttributeBo attributeBo = new AgendaAttributeBo();
604 attributeBo.setAgenda(agendaBo);
605 attributeBo.setValue(entry.getValue());
606 attributeBo.setAttributeDefinition(KrmsAttributeDefinitionBo.from(attrDef));
607 attributes.add(attributeBo);
608 } else {
609 throw new RiceIllegalStateException("there is no attribute definition with the name '" +
610 entry.getKey() + "' that is valid for the agenda type with id = '" + im.getTypeId() + "'");
611 }
612 }
613 return attributes;
614 }
615
616
617
618
619
620
621 public DataObjectService getDataObjectService() {
622 if (dataObjectService == null) {
623 dataObjectService = KRADServiceLocator.getDataObjectService();
624 }
625
626 return dataObjectService;
627 }
628
629
630
631
632
633
634 public void setDataObjectService(final DataObjectService dataObjectService) {
635 this.dataObjectService = dataObjectService;
636 }
637
638
639
640
641
642
643 public KrmsAttributeDefinitionService getAttributeDefinitionService() {
644 if (attributeDefinitionService == null) {
645 attributeDefinitionService = KrmsRepositoryServiceLocator.getKrmsAttributeDefinitionService();
646 }
647
648 return attributeDefinitionService;
649 }
650
651
652
653
654
655
656 public void setAttributeDefinitionService(KrmsAttributeDefinitionService attributeDefinitionService) {
657 this.attributeDefinitionService = attributeDefinitionService;
658 }
659
660 }