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