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