View Javadoc

1   /**
2    * Copyright 2005-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krms.impl.repository;
17  
18  import java.util.Collection;
19  import java.util.Collections;
20  import java.util.HashMap;
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Map.Entry;
25  import java.util.Set;
26  
27  import org.apache.commons.lang.StringUtils;
28  import org.kuali.rice.core.api.exception.RiceIllegalStateException;
29  import org.kuali.rice.krad.service.BusinessObjectService;
30  import org.kuali.rice.krad.service.KRADServiceLocator;
31  import org.kuali.rice.krad.service.SequenceAccessorService;
32  import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
33  import org.kuali.rice.krms.api.repository.agenda.AgendaItem;
34  import org.kuali.rice.krms.api.repository.type.KrmsAttributeDefinition;
35  import org.kuali.rice.krms.impl.util.KrmsImplConstants.PropertyNames;
36  
37  public final class AgendaBoServiceImpl implements AgendaBoService {
38  
39      // TODO: deal with active flag
40  
41      private BusinessObjectService businessObjectService;
42      private KrmsAttributeDefinitionService attributeDefinitionService;
43      private SequenceAccessorService sequenceAccessorService;
44  
45      /**
46       * This overridden method creates a KRMS Agenda in the repository
47       */
48      @Override
49      public AgendaDefinition createAgenda(AgendaDefinition agenda) {
50          if (agenda == null){
51              throw new IllegalArgumentException("agenda is null");
52          }
53          final String nameKey = agenda.getName();
54          final String contextId = agenda.getContextId();
55          final AgendaDefinition existing = getAgendaByNameAndContextId(nameKey, contextId);
56          if (existing != null){
57              throw new IllegalStateException("the agenda to create already exists: " + agenda);
58          }
59  
60          AgendaBo agendaBo = from(agenda);
61          businessObjectService.save(agendaBo);
62          return to(agendaBo);
63      }
64  
65      /**
66       * This overridden method updates an existing Agenda in the repository
67       */
68      @Override
69      public void updateAgenda(AgendaDefinition agenda) {
70          if (agenda == null){
71              throw new IllegalArgumentException("agenda is null");
72          }
73  
74          // must already exist to be able to update
75          final String agendaIdKey = agenda.getId();
76          final AgendaBo existing = businessObjectService.findBySinglePrimaryKey(AgendaBo.class, agendaIdKey);
77          if (existing == null) {
78              throw new IllegalStateException("the agenda does not exist: " + agenda);
79          }
80          final AgendaDefinition toUpdate;
81          if (existing.getId().equals(agenda.getId())) {
82              toUpdate = agenda;
83          } else {
84              // if passed in id does not match existing id, correct it
85              final AgendaDefinition.Builder builder = AgendaDefinition.Builder.create(agenda);
86              builder.setId(existing.getId());
87              toUpdate = builder.build();
88          }
89  
90          // copy all updateable fields to bo
91          AgendaBo boToUpdate = from(toUpdate);
92  
93          // delete any old, existing attributes
94          Map<String,String> fields = new HashMap<String,String>(1);
95          fields.put(PropertyNames.Agenda.AGENDA_ID, toUpdate.getId());
96          businessObjectService.deleteMatching(AgendaAttributeBo.class, fields);
97  
98          // update new agenda and create new attributes
99          businessObjectService.save(boToUpdate);
100     }
101 
102     /**
103      * This overridden method retrieves an Agenda from the repository
104      */
105     @Override
106     public AgendaDefinition getAgendaByAgendaId(String agendaId) {
107         if (StringUtils.isBlank(agendaId)){
108             throw new IllegalArgumentException("agenda id is null");
109         }
110         AgendaBo bo = businessObjectService.findBySinglePrimaryKey(AgendaBo.class, agendaId);
111         return to(bo);
112     }
113 
114     /**
115      * This overridden method retrieves an agenda from the repository
116      */
117     @Override
118     public AgendaDefinition getAgendaByNameAndContextId(String name, String contextId) {
119         if (StringUtils.isBlank(name)) {
120             throw new IllegalArgumentException("name is blank");
121         }
122         if (StringUtils.isBlank(contextId)) {
123             throw new IllegalArgumentException("contextId is blank");
124         }
125 
126         final Map<String, Object> map = new HashMap<String, Object>();
127         map.put("name", name);
128         map.put("contextId", contextId);
129 
130         AgendaBo myAgenda = businessObjectService.findByPrimaryKey(AgendaBo.class, Collections.unmodifiableMap(map));
131         return to(myAgenda);
132     }
133 
134     /**
135      * This overridden method retrieves a set of agendas from the repository
136      */
137     @Override
138     public Set<AgendaDefinition> getAgendasByContextId(String contextId) {
139         if (StringUtils.isBlank(contextId)){
140             throw new IllegalArgumentException("context ID is null or blank");
141         }
142         final Map<String, Object> map = new HashMap<String, Object>();
143         map.put("contextId", contextId);
144         Set<AgendaBo> bos = (Set<AgendaBo>) businessObjectService.findMatching(AgendaBo.class, map);
145         return convertListOfBosToImmutables(bos);
146     }
147 
148     /**
149      * This overridden method creates a new Agenda in the repository
150      */
151     @Override
152     public AgendaItem createAgendaItem(AgendaItem agendaItem) {
153         if (agendaItem == null){
154             throw new IllegalArgumentException("agendaItem is null");
155         }
156         if (agendaItem.getId() != null){
157             final AgendaDefinition existing = getAgendaByAgendaId(agendaItem.getId());
158             if (existing != null){
159                 throw new IllegalStateException("the agendaItem to create already exists: " + agendaItem);
160             }
161         }
162 
163         AgendaItemBo bo = AgendaItemBo.from(agendaItem);
164         businessObjectService.save(bo);
165         return AgendaItemBo.to(bo);
166     }
167 
168     /**
169      * This overridden method updates an existing Agenda in the repository
170      */
171     @Override
172     public void updateAgendaItem(AgendaItem agendaItem) {
173         if (agendaItem == null){
174             throw new IllegalArgumentException("agendaItem is null");
175         }
176         final String agendaItemIdKey = agendaItem.getId();
177         final AgendaItem existing = getAgendaItemById(agendaItemIdKey);
178         if (existing == null) {
179             throw new IllegalStateException("the agenda item does not exist: " + agendaItem);
180         }
181         final AgendaItem toUpdate;
182         if (existing.getId().equals(agendaItem.getId())) {
183             toUpdate = agendaItem;
184         } else {
185             final AgendaItem.Builder builder = AgendaItem.Builder.create(agendaItem);
186             builder.setId(existing.getId());
187             toUpdate = builder.build();
188         }
189 
190         businessObjectService.save(AgendaItemBo.from(toUpdate));
191     }
192 
193     /**
194      * This overridden method adds a new AgendaItem to the repository
195      */
196     @Override
197     public void addAgendaItem(AgendaItem agendaItem, String parentId, Boolean position) {
198         if (agendaItem == null){
199             throw new IllegalArgumentException("agendaItem is null");
200         }
201         AgendaItem parent = null;
202         if (parentId != null){
203             parent = getAgendaItemById(parentId);
204             if (parent == null){
205                 throw new IllegalStateException("parent agendaItem does not exist in repository. parentId = " + parentId);
206             }
207         }
208         // create new AgendaItem
209         final AgendaItem toCreate;
210         if (agendaItem.getId() == null) {
211             SequenceAccessorService sas = getSequenceAccessorService();
212             final AgendaItem.Builder builder = AgendaItem.Builder.create(agendaItem);
213             final String newId =sas.getNextAvailableSequenceNumber(
214                     "KRMS_AGENDA_ITM_S", AgendaItemBo.class).toString();
215             builder.setId(newId);
216             toCreate = builder.build();
217         } else {
218             toCreate = agendaItem;
219         }
220         createAgendaItem(toCreate);
221 
222         // link it to it's parent (for whenTrue/whenFalse, sibling for always
223         if (parentId != null) {
224             final AgendaItem.Builder builder = AgendaItem.Builder.create(parent);
225             if (position == null){
226                 builder.setAlwaysId( toCreate.getId() );
227             } else if (position.booleanValue()){
228                 builder.setWhenTrueId( toCreate.getId() );
229             } else if (!position.booleanValue()){
230                 builder.setWhenFalseId( toCreate.getId() );
231             }
232             final AgendaItem parentToUpdate = builder.build();
233             updateAgendaItem( parentToUpdate );
234         }
235     }
236 
237     /**
238      * This overridden method retrieves an AgendaItem from the repository
239      */
240     @Override
241     public AgendaItem getAgendaItemById(String id) {
242         if (StringUtils.isBlank(id)){
243             throw new IllegalArgumentException("agenda item id is null");
244         }
245         AgendaItemBo bo = businessObjectService.findBySinglePrimaryKey(AgendaItemBo.class, id);
246         return AgendaItemBo.to(bo);
247     }
248 
249     /**
250      * Sets the businessObjectService attribute value.
251      *
252      * @param businessObjectService The businessObjectService to set.
253      */
254     public void setBusinessObjectService(final BusinessObjectService businessObjectService) {
255         this.businessObjectService = businessObjectService;
256     }
257 
258     protected BusinessObjectService getBusinessObjectService() {
259         if ( businessObjectService == null ) {
260             businessObjectService = KRADServiceLocator.getBusinessObjectService();
261         }
262         return businessObjectService;
263     }
264 
265     /**
266      * Sets the sequenceAccessorService attribute value.
267      *
268      * @param sequenceAccessorService The sequenceAccessorService to set.
269      */
270     public void setSequenceAccessorService(final SequenceAccessorService sequenceAccessorService) {
271         this.sequenceAccessorService = sequenceAccessorService;
272     }
273 
274     protected SequenceAccessorService getSequenceAccessorService() {
275         if ( sequenceAccessorService == null ) {
276             sequenceAccessorService = KRADServiceLocator.getSequenceAccessorService();
277         }
278         return sequenceAccessorService;
279     }
280 
281     protected KrmsAttributeDefinitionService getAttributeDefinitionService() {
282         if (attributeDefinitionService == null) {
283             attributeDefinitionService = KrmsRepositoryServiceLocator.getKrmsAttributeDefinitionService();
284         }
285         return attributeDefinitionService;
286     }
287 
288     public void setAttributeDefinitionService(KrmsAttributeDefinitionService attributeDefinitionService) {
289         this.attributeDefinitionService = attributeDefinitionService;
290     }
291 
292     /**
293      * Converts a Set<AgendaBo> to an Unmodifiable Set<Agenda>
294      *
295      * @param agendaBos a mutable Set<AgendaBo> to made completely immutable.
296      * @return An unmodifiable Set<Agenda>
297      */
298     public Set<AgendaDefinition> convertListOfBosToImmutables(final Collection<AgendaBo> agendaBos) {
299         Set<AgendaDefinition> agendas = new HashSet<AgendaDefinition>();
300         if (agendaBos != null){
301             for (AgendaBo bo : agendaBos) {
302                 AgendaDefinition agenda = to(bo);
303                 agendas.add(agenda);
304             }
305         }
306         return Collections.unmodifiableSet(agendas);
307     }
308 
309     /**
310      * Converts a mutable bo to it's immutable counterpart
311      * @param bo the mutable business object
312      * @return the immutable object
313      */
314     @Override
315     public AgendaDefinition to(AgendaBo bo) {
316         if (bo == null) { return null; }
317         return org.kuali.rice.krms.api.repository.agenda.AgendaDefinition.Builder.create(bo).build();
318     }
319 
320 
321     /**
322      * Converts a immutable object to it's mutable bo counterpart
323      * @param im immutable object
324      * @return the mutable bo
325      */
326     @Override
327     public AgendaBo from(AgendaDefinition im) {
328         if (im == null) { return null; }
329 
330         AgendaBo bo = new AgendaBo();
331         bo.setId(im.getId());
332         bo.setName( im.getName() );
333         bo.setTypeId( im.getTypeId() );
334         bo.setContextId( im.getContextId() );
335         bo.setFirstItemId( im.getFirstItemId() );
336         bo.setVersionNumber( im.getVersionNumber() );
337         Set<AgendaAttributeBo> attributes = buildAgendaAttributeBo(im);
338 
339         bo.setAttributeBos(attributes);
340 
341         return bo;
342     }
343 
344     private Set<AgendaAttributeBo> buildAgendaAttributeBo(AgendaDefinition im) {
345         Set<AgendaAttributeBo> attributes = new HashSet<AgendaAttributeBo>();
346 
347         ContextBo context = getBusinessObjectService().findBySinglePrimaryKey(ContextBo.class, im.getContextId());
348 
349         // build a map from attribute name to definition
350         Map<String, KrmsAttributeDefinition> attributeDefinitionMap = new HashMap<String, KrmsAttributeDefinition>();
351 
352         List<KrmsAttributeDefinition> attributeDefinitions =
353                 getAttributeDefinitionService().findAttributeDefinitionsByType(im.getTypeId());
354 
355         for (KrmsAttributeDefinition attributeDefinition : attributeDefinitions) {
356             attributeDefinitionMap.put(attributeDefinition.getName(), attributeDefinition);
357         }
358 
359         // for each entry, build an AgendaAttributeBo and add it to the set
360         for (Entry<String,String> entry  : im.getAttributes().entrySet()){
361             KrmsAttributeDefinition attrDef = attributeDefinitionMap.get(entry.getKey());
362 
363             if (attrDef != null) {
364                 AgendaAttributeBo attributeBo = new AgendaAttributeBo();
365                 attributeBo.setAgendaId( im.getId() );
366                 attributeBo.setAttributeDefinitionId(attrDef.getId());
367                 attributeBo.setValue(entry.getValue());
368                 attributeBo.setAttributeDefinition(KrmsAttributeDefinitionBo.from(attrDef));
369                 attributes.add( attributeBo );
370             } else {
371                 throw new RiceIllegalStateException("there is no attribute definition with the name '" +
372                         entry.getKey() + "' that is valid for the agenda type with id = '" + im.getTypeId() +"'");
373             }
374         }
375         return attributes;
376     }
377 
378 }