001 /**
002 * Copyright 2005-2011 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 */
016 package org.kuali.rice.krms.impl.repository;
017
018 import java.util.Collection;
019 import java.util.Collections;
020 import java.util.HashMap;
021 import java.util.HashSet;
022 import java.util.List;
023 import java.util.Map;
024 import java.util.Map.Entry;
025 import java.util.Set;
026
027 import org.apache.commons.lang.StringUtils;
028 import org.kuali.rice.core.api.exception.RiceIllegalStateException;
029 import org.kuali.rice.krad.service.BusinessObjectService;
030 import org.kuali.rice.krad.service.KRADServiceLocator;
031 import org.kuali.rice.krad.service.SequenceAccessorService;
032 import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
033 import org.kuali.rice.krms.api.repository.agenda.AgendaItem;
034 import org.kuali.rice.krms.api.repository.type.KrmsAttributeDefinition;
035 import org.kuali.rice.krms.impl.util.KrmsImplConstants.PropertyNames;
036
037 public final class AgendaBoServiceImpl implements AgendaBoService {
038
039 // TODO: deal with active flag
040
041 private BusinessObjectService businessObjectService;
042 private KrmsAttributeDefinitionService attributeDefinitionService;
043 private SequenceAccessorService sequenceAccessorService;
044
045 /**
046 * This overridden method creates a KRMS Agenda in the repository
047 */
048 @Override
049 public AgendaDefinition createAgenda(AgendaDefinition agenda) {
050 if (agenda == null){
051 throw new IllegalArgumentException("agenda is null");
052 }
053 final String nameKey = agenda.getName();
054 final String contextId = agenda.getContextId();
055 final AgendaDefinition existing = getAgendaByNameAndContextId(nameKey, contextId);
056 if (existing != null){
057 throw new IllegalStateException("the agenda to create already exists: " + agenda);
058 }
059
060 AgendaBo agendaBo = from(agenda);
061 businessObjectService.save(agendaBo);
062 return to(agendaBo);
063 }
064
065 /**
066 * This overridden method updates an existing Agenda in the repository
067 */
068 @Override
069 public void updateAgenda(AgendaDefinition agenda) {
070 if (agenda == null){
071 throw new IllegalArgumentException("agenda is null");
072 }
073
074 // must already exist to be able to update
075 final String agendaIdKey = agenda.getId();
076 final AgendaBo existing = businessObjectService.findBySinglePrimaryKey(AgendaBo.class, agendaIdKey);
077 if (existing == null) {
078 throw new IllegalStateException("the agenda does not exist: " + agenda);
079 }
080 final AgendaDefinition toUpdate;
081 if (existing.getId().equals(agenda.getId())) {
082 toUpdate = agenda;
083 } else {
084 // if passed in id does not match existing id, correct it
085 final AgendaDefinition.Builder builder = AgendaDefinition.Builder.create(agenda);
086 builder.setId(existing.getId());
087 toUpdate = builder.build();
088 }
089
090 // copy all updateable fields to bo
091 AgendaBo boToUpdate = from(toUpdate);
092
093 // delete any old, existing attributes
094 Map<String,String> fields = new HashMap<String,String>(1);
095 fields.put(PropertyNames.Agenda.AGENDA_ID, toUpdate.getId());
096 businessObjectService.deleteMatching(AgendaAttributeBo.class, fields);
097
098 // update new agenda and create new attributes
099 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 }