001 /** 002 * Copyright 2005-2012 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.AgendaItemDefinition; 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 AgendaItemDefinition createAgendaItem(AgendaItemDefinition 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(AgendaItemDefinition agendaItem) { 173 if (agendaItem == null){ 174 throw new IllegalArgumentException("agendaItem is null"); 175 } 176 final String agendaItemIdKey = agendaItem.getId(); 177 final AgendaItemDefinition existing = getAgendaItemById(agendaItemIdKey); 178 if (existing == null) { 179 throw new IllegalStateException("the agenda item does not exist: " + agendaItem); 180 } 181 final AgendaItemDefinition toUpdate; 182 if (existing.getId().equals(agendaItem.getId())) { 183 toUpdate = agendaItem; 184 } else { 185 final AgendaItemDefinition.Builder builder = AgendaItemDefinition.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 AgendaItemDefinition to the repository 195 */ 196 @Override 197 public void addAgendaItem(AgendaItemDefinition agendaItem, String parentId, Boolean position) { 198 if (agendaItem == null){ 199 throw new IllegalArgumentException("agendaItem is null"); 200 } 201 AgendaItemDefinition 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 AgendaItemDefinition 209 final AgendaItemDefinition toCreate; 210 if (agendaItem.getId() == null) { 211 SequenceAccessorService sas = getSequenceAccessorService(); 212 final AgendaItemDefinition.Builder builder = AgendaItemDefinition.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 AgendaItemDefinition.Builder builder = AgendaItemDefinition.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 AgendaItemDefinition parentToUpdate = builder.build(); 233 updateAgendaItem( parentToUpdate ); 234 } 235 } 236 237 /** 238 * This overridden method retrieves an AgendaItemDefinition from the repository 239 */ 240 @Override 241 public AgendaItemDefinition 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 }