001/**
002 * Copyright 2005-2017 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krms.impl.repository;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.core.api.criteria.Predicate;
020import org.kuali.rice.core.api.criteria.QueryByCriteria;
021import org.kuali.rice.core.api.criteria.QueryResults;
022import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
023import org.kuali.rice.core.api.exception.RiceIllegalStateException;
024import org.kuali.rice.core.api.mo.ModelObjectUtils;
025import org.kuali.rice.krad.data.DataObjectService;
026import org.kuali.rice.krad.data.PersistenceOption;
027import org.kuali.rice.krad.service.KRADServiceLocator;
028import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
029import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition;
030import org.kuali.rice.krms.api.repository.type.KrmsAttributeDefinition;
031import org.springframework.util.CollectionUtils;
032
033import java.util.ArrayList;
034import java.util.Collection;
035import java.util.Collections;
036import java.util.HashMap;
037import java.util.HashSet;
038import java.util.List;
039import java.util.Map;
040import java.util.Map.Entry;
041import java.util.Set;
042
043import static org.kuali.rice.core.api.criteria.PredicateFactory.in;
044import static org.kuali.rice.krms.impl.repository.BusinessObjectServiceMigrationUtils.*;
045
046/**
047 * Implementation of the interface for accessing KRMS repository Agenda related
048 * business objects.
049 *
050 * @author Kuali Rice Team (rice.collab@kuali.org)
051 */
052public class AgendaBoServiceImpl implements AgendaBoService {
053
054    // TODO: deal with active flag
055
056    // used for converting lists of BOs to model objects
057    private static final ModelObjectUtils.Transformer<AgendaItemBo, AgendaItemDefinition> toAgendaItemDefinition =
058            new ModelObjectUtils.Transformer<AgendaItemBo, AgendaItemDefinition>() {
059                public AgendaItemDefinition transform(AgendaItemBo input) {
060                    return AgendaItemBo.to(input);
061                };
062            };
063    // used for converting lists of BOs to model objects
064    private static final ModelObjectUtils.Transformer<AgendaBo, AgendaDefinition> toAgendaDefinition =
065            new ModelObjectUtils.Transformer<AgendaBo, AgendaDefinition>() {
066                public AgendaDefinition transform(AgendaBo input) {
067                    return AgendaBo.to(input);
068                };
069            };
070
071    private DataObjectService dataObjectService;
072    private KrmsAttributeDefinitionService attributeDefinitionService;
073
074    /**
075     * This overridden method creates a KRMS Agenda in the repository
076     */
077    @Override
078    public AgendaDefinition createAgenda(AgendaDefinition agenda) {
079        if (agenda == null) {
080            throw new RiceIllegalArgumentException("agenda is null");
081        }
082        final String nameKey = agenda.getName();
083        final String contextId = agenda.getContextId();
084        final AgendaDefinition existing = getAgendaByNameAndContextId(nameKey, contextId);
085        if (existing != null) {
086            throw new IllegalStateException("the agenda to create already exists: " + agenda);
087        }
088
089        AgendaBo agendaBo = from(agenda);
090        agendaBo = getDataObjectService().save(agendaBo, PersistenceOption.FLUSH);
091        return to(agendaBo);
092    }
093
094    /**
095     * This overridden method updates an existing Agenda in the repository
096     */
097    @Override
098    public AgendaDefinition updateAgenda(AgendaDefinition agendaDefinition) {
099        if (agendaDefinition == null) {
100            throw new RiceIllegalArgumentException("agenda is null");
101        }
102
103        // must already exist to be able to update
104        final String agendaDefinitionId = agendaDefinition.getId();
105
106        // All AgendaItemDefinitions for the specified Agenda ID will end up in the "items" property.
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            // if passed in id does not match existing id, correct it
117            final AgendaDefinition.Builder builder = AgendaDefinition.Builder.create(agendaDefinition);
118            builder.setId(agendaBoExisting.getId());
119            agendaDefinitionToUpdate = builder.build();
120        }
121
122        // copy all updateable fields to bo
123        AgendaBo agendaBoToUpdate = from(agendaDefinitionToUpdate);
124
125        // move over AgendaBo members that don't get populated from AgendaDefinition
126        agendaBoToUpdate.setItems(agendaBoExisting.getItems());
127        if (StringUtils.isNotBlank(agendaDefinition.getFirstItemId())) {
128            agendaBoToUpdate.setFirstItem(getDataObjectService().find(AgendaItemBo.class, agendaDefinition.getFirstItemId()));
129        }
130
131        // delete any old, existing attributes
132        Map<String, String> fields = new HashMap<String, String>(1);
133        fields.put("agenda.id", agendaDefinitionToUpdate.getId());
134        // deletes the record(s) in krms_agenda_attr_t specified by agenda_id col
135        deleteMatching(getDataObjectService(), AgendaAttributeBo.class, fields);
136
137        // Will get used to determine which "previous" AgendaItems can get deleted
138        ArrayList<String> agendaItemsIds = new ArrayList<String>();
139
140        // Will get used for a quick AgendaItem ID to AgendaItemBo lookup
141        HashMap<String, AgendaItemBo> mapIdToBo = new HashMap<String, AgendaItemBo>();
142
143        // Get all AgendaItems which have the specified Agenda ID.  Make a "referenced" list as well.
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        // update new agenda and create new attributes
164        AgendaBo agendaBoUpdated = getDataObjectService().save(agendaBoToUpdate, PersistenceOption.FLUSH);
165
166        // Walk the "always", "whenTrue", and "whenFalse" lists.
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            // always list
175            while (agendaItemBoCurrent != null) {
176                if (StringUtils.isNotEmpty(agendaItemBoCurrent.getAlwaysId())) {
177                    agendaItemIdsActuallyUsed.add(agendaItemBoCurrent.getAlwaysId());
178                }
179
180                agendaItemBoCurrent = agendaItemBoCurrent.getAlways();
181            }
182
183            // whenTrue list
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            // whenFalse list
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        // Compare what is used by the updated Agenda to all AgendaItem IDs for this Agenda ID
205        for (String sIdActuallyUsed : agendaItemIdsActuallyUsed) {
206            if (agendaItemsIds.contains(sIdActuallyUsed)) {
207                agendaItemsIds.remove(sIdActuallyUsed);
208            }
209        }
210
211        // Anything remaining is an orphan. Only delete an AgendaItem which is not referenced,
212        // and that will cascade
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        // delete orphan agenda items, if needed
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     * This overridden method retrieves an Agenda from the repository
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     * This overridden method retrieves an agenda from the repository
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     * This overridden method retrieves a set of agendas from the repository
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     * This overridden method creates a new Agenda in the repository
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     * This overridden method updates an existing Agenda in the repository
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     * This overridden method adds a new AgendaItemDefinition to the repository
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        // create new AgendaItemDefinition
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        // link it to it's parent (for whenTrue/whenFalse, sibling for always
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     * This overridden method retrieves an AgendaItemDefinition from the repository
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                    // fetch batch
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                    // reset agendaIds
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     * Converts a Set<AgendaBo> to an Unmodifiable Set<Agenda>
533     *
534     * @param agendaBos a mutable Set<AgendaBo> to made completely immutable.
535     * @return An unmodifiable Set<Agenda>
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     * Converts a mutable bo to it's immutable counterpart
546     *
547     * @param bo the mutable business object
548     * @return the immutable object
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     * Converts a immutable object to it's mutable bo counterpart
560     *
561     * @param im immutable object
562     * @return the mutable bo
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        // build a map from attribute name to definition
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        // for each entry, build an AgendaAttributeBo and add it to the set
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     * Gets the {@link DataObjectService}.
618     *
619     * @return the {@link DataObjectService}
620     */
621    public DataObjectService getDataObjectService() {
622        if (dataObjectService == null) {
623            dataObjectService = KRADServiceLocator.getDataObjectService();
624        }
625
626        return dataObjectService;
627    }
628
629    /**
630     * Sets the {@link DataObjectService}.
631     *
632     * @param dataObjectService the {@link DataObjectService} to set
633     */
634    public void setDataObjectService(final DataObjectService dataObjectService) {
635        this.dataObjectService = dataObjectService;
636    }
637
638    /**
639     * Gets the {@link KrmsAttributeDefinitionService}.
640     *
641     * @return the {@link KrmsAttributeDefinitionService}
642     */
643    public KrmsAttributeDefinitionService getAttributeDefinitionService() {
644        if (attributeDefinitionService == null) {
645            attributeDefinitionService = KrmsRepositoryServiceLocator.getKrmsAttributeDefinitionService();
646        }
647
648        return attributeDefinitionService;
649    }
650
651    /**
652     * Sets the {@link KrmsAttributeDefinitionService}.
653     *
654     * @param attributeDefinitionService the {@link KrmsAttributeDefinitionService} to set
655     */
656    public void setAttributeDefinitionService(KrmsAttributeDefinitionService attributeDefinitionService) {
657        this.attributeDefinitionService = attributeDefinitionService;
658    }
659
660}