View Javadoc

1   /**
2    * Copyright 2010 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   */
15  
16  package org.kuali.student.r2.lum.lo.service.impl;
17  
18  import org.kuali.rice.core.api.criteria.QueryByCriteria;
19  import org.kuali.student.r1.common.dictionary.dto.ObjectStructureDefinition;
20  import org.kuali.student.r1.common.dictionary.service.DictionaryService;
21  import org.kuali.student.r2.common.dto.ContextInfo;
22  import org.kuali.student.r2.common.dto.DtoConstants;
23  import org.kuali.student.r2.common.dto.StatusInfo;
24  import org.kuali.student.r2.common.dto.ValidationResultInfo;
25  import org.kuali.student.r2.common.exceptions.*;
26  import org.kuali.student.r2.core.search.dto.*;
27  import org.kuali.student.r2.core.search.service.SearchManager;
28  import org.kuali.student.r2.common.validator.Validator;
29  import org.kuali.student.r2.common.validator.ValidatorFactory;
30  import org.kuali.student.r2.core.class1.type.dto.TypeInfo;
31  import org.kuali.student.r2.lum.lo.dao.LoDao;
32  import org.kuali.student.r2.lum.lo.dto.LoCategoryInfo;
33  import org.kuali.student.r2.lum.lo.dto.LoInfo;
34  import org.kuali.student.r2.lum.lo.dto.LoLoRelationInfo;
35  import org.kuali.student.r2.lum.lo.dto.LoRepositoryInfo;
36  import org.kuali.student.r2.lum.lo.entity.*;
37  import org.kuali.student.r2.lum.lo.service.LearningObjectiveService;
38  import org.springframework.transaction.annotation.Transactional;
39  
40  import javax.jws.WebParam;
41  import javax.jws.WebService;
42  import java.util.*;
43  
44  /*n
45   * @author Kuali Student team
46   *
47   */
48  @WebService(endpointInterface = "org.kuali.student.r2.lum.lo.service.LearningObjectiveService", serviceName = "LearningObjectiveService", portName = "LearningObjectiveService", targetNamespace = "http://student.kuali.org/wsdl/lo")
49  public class LearningObjectiveServiceImpl implements LearningObjectiveService {
50      private LoDao loDao;
51  	private SearchManager searchManager;
52      private DictionaryService dictionaryServiceDelegate;
53  	private ValidatorFactory validatorFactory;
54  
55  	public LoDao getLoDao() {
56          return loDao;
57      }
58  
59      public void setLoDao(LoDao dao) {
60          this.loDao = dao;
61      }
62  
63  	public void setSearchManager(SearchManager searchManager) {
64  		this.searchManager = searchManager;
65  	}
66  
67      public void setDictionaryServiceDelegate(DictionaryService dictionaryServiceDelegate) {
68          this.dictionaryServiceDelegate = dictionaryServiceDelegate;
69      }
70  
71  	public ValidatorFactory getValidatorFactory() {
72          return validatorFactory;
73      }
74  
75      public void setValidatorFactory(ValidatorFactory validatorFactory) {
76          this.validatorFactory = validatorFactory;
77      }
78  
79  
80  	@Override
81      @Transactional(readOnly=true)
82  	public List<LoRepositoryInfo> getLoRepositories(@WebParam(name = "contextInfo") ContextInfo contextInfo)
83              throws InvalidParameterException, MissingParameterException, OperationFailedException,
84              PermissionDeniedException {
85  	    List<LoRepository> repositories = loDao.find(LoRepository.class);
86    	
87  	   return LearningObjectiveServiceAssembler.toLoRepositoryInfos(repositories);
88  	}
89  
90  
91  	@Override
92      public List<String> getLoRepositoryKeysByType(@WebParam(name = "loRepositoryTypeKey") String loRepositoryTypeKey, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
93          return null;  //To change body of implemented methods use File | Settings | File Templates.
94      }
95  
96      @Override
97      public List<String> searchForLoRepositoryKeys(@WebParam(name = "criteria") QueryByCriteria criteria, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
98          return null;  //To change body of implemented methods use File | Settings | File Templates.
99      }
100 
101     @Override
102     public List<LoRepositoryInfo> searchForLoRepositories(@WebParam(name = "criteria") QueryByCriteria criteria, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
103         return null;  //To change body of implemented methods use File | Settings | File Templates.
104     }
105 
106     @Override
107     public List<ValidationResultInfo> validateLoRepository(@WebParam(name = "validationTypeKey") String validationTypeKey, @WebParam(name = "loRepositoryTypeKey") String loRepositoryTypeKey, @WebParam(name = "loRepositoryInfo") LoRepositoryInfo loRepositoryInfo, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
108         return null;  //To change body of implemented methods use File | Settings | File Templates.
109     }
110 
111     @Override
112     public LoRepositoryInfo createLoRepository(@WebParam(name = "loRepositoryKey") String loRepositoryKey, @WebParam(name = "loRepositoryTypeKey") String loRepositoryTypeKey, @WebParam(name = "loRepositoryInfo") LoRepositoryInfo loRepositoryInfo, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws AlreadyExistsException, DataValidationErrorException, DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException, ReadOnlyException {
113         return null;  //To change body of implemented methods use File | Settings | File Templates.
114     }
115 
116     @Override
117     public LoRepositoryInfo updateLoRepository(@WebParam(name = "loRepositoryKey") String loRepositoryKey, @WebParam(name = "loRepositoryInfo") LoRepositoryInfo loRepositoryInfo, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DataValidationErrorException, DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException, ReadOnlyException, VersionMismatchException {
118         return null;  //To change body of implemented methods use File | Settings | File Templates.
119     }
120 
121     @Override
122     public StatusInfo deleteLoRepository(@WebParam(name = "loRepositoryKey") String loRepositoryKey, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
123         return null;  //To change body of implemented methods use File | Settings | File Templates.
124     }
125 
126     /*
127       * (non-Javadoc)
128       * @see org.kuali.student.lum.lo.service.LearningObjectiveService#getLoRepository(java.lang.String)
129       */
130 	@Override
131     @Transactional(readOnly=true)
132 	public LoRepositoryInfo getLoRepository (String loRepositoryKey, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
133 	    checkForMissingParameter(loRepositoryKey, "loRepositoryKey");
134 	    return LearningObjectiveServiceAssembler.toLoRepositoryInfo(loDao.fetch(LoRepository.class, loRepositoryKey));
135 		
136 	}
137 
138     @Override
139     public List<LoRepositoryInfo> getLoRepositoriesByKeys(@WebParam(name = "loRepositoryKeys") List<String> loRepositoryKeys, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
140         return null;  //To change body of implemented methods use File | Settings | File Templates.
141     }
142 
143     /*
144 	 * (non-Javadoc)
145 	 * @see org.kuali.student.lum.lo.service.LearningObjectiveService#addLoCategoryToLo(java.lang.String, java.lang.String)
146 	 */
147 	@Override
148 	@Transactional(readOnly=false,noRollbackFor={DoesNotExistException.class},rollbackFor={Throwable.class})
149 	public StatusInfo  addLoCategoryToLo( String loCategoryId, String loId,  ContextInfo contextInfo) throws AlreadyExistsException, DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException, UnsupportedActionException
150     {
151 	    checkForMissingParameter(loCategoryId, "loCategoryId");
152 	    checkForMissingParameter(loId, "loId");
153         StatusInfo statusInfo = new StatusInfo();
154         statusInfo.setSuccess(loDao.addLoCategoryToLo(loCategoryId, loId));
155         return statusInfo;
156 	}
157 
158     @Override
159     public List<LoLoRelationInfo> getLoLoRelationsByIds(@WebParam(name = "loLoRelationIds") List<String> loLoRelationIds, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
160         return null;  //To change body of implemented methods use File | Settings | File Templates.
161     }
162 
163     @Override
164     public List<String> getLoLoRelationIdsByType(@WebParam(name = "loLoRelationTypeKey") String loLoRelationTypeKey, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
165         return null;  //To change body of implemented methods use File | Settings | File Templates.
166     }
167 
168     @Override
169     public List<String> searchForLoLoRelationIds(@WebParam(name = "criteria") QueryByCriteria criteria, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
170         return null;  //To change body of implemented methods use File | Settings | File Templates.
171     }
172 
173     @Override
174     public List<LoLoRelationInfo> searchForLoLoRelations(@WebParam(name = "criteria") QueryByCriteria criteria, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
175         return null;  //To change body of implemented methods use File | Settings | File Templates.
176     }
177 
178     /* (non-Javadoc)
179       * @see org.kuali.student.lum.lo.service.LearningObjectiveService#createLo(java.lang.String, java.lang.String, org.kuali.student.lum.lo.dto.LoInfo)
180       */
181 	@Override
182 	@Transactional(readOnly=false,noRollbackFor={DoesNotExistException.class},rollbackFor={Throwable.class})
183 	public LoInfo createLo (String repositoryId, String loType, LoInfo loInfo, ContextInfo contextInfo) throws DataValidationErrorException, DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException, ReadOnlyException {
184  
185         checkForMissingParameter(repositoryId, "repositoryId");
186 	    checkForMissingParameter(loType, "loType");
187 	    checkForMissingParameter(loInfo, "loInfo");
188 	    
189 	    
190 		// Validate LO
191 		List<ValidationResultInfo> val = validateLo("SYSTEM", loInfo,contextInfo);
192 		if(null != val && val.size() > 0) {
193 			for (ValidationResultInfo result : val) {
194 				System.err.println("Validation error. Element: " + result.getElement() + ",  Value: " + result.getMessage());
195 			}
196             
197 			throw new DataValidationErrorException("Validation error!", val);
198 			
199 		}
200 		
201 	    // make sure LoType and LoRepository exist before trying to create
202 	    // if checkForMissingParameter above did its job, we don't have to null-check these id's
203 	    LoType type = null;
204 	    LoRepository repository = null;
205 	   try {
206 
207 		   type = loDao.fetch(LoType.class, loType);
208 		   repository = loDao.fetch(LoRepository.class, repositoryId);
209 	    } catch (DoesNotExistException dnee) {
210 	    	throw new DoesNotExistException("Specified " + (null == type ? "LoType" : "LoRepository") + " does not exist", dnee);
211 	    }
212 
213        
214 	   loInfo.setLoRepositoryKey(repositoryId);
215 	   loInfo.setTypeKey(loType);
216 
217 	    Lo lo = null;
218 	    try {
219         lo = LearningObjectiveServiceAssembler.toLo(false, loInfo, loDao);
220 	    } catch (VersionMismatchException vme) {
221 	    	// should never happen in a create call, but
222 	    	throw new OperationFailedException("VersionMismatchException caught during Learning Objective creation");
223 	    }
224 	    lo.setLoType(type);
225 	    lo.setLoRepository(repository);
226 	    loDao.create(lo);
227 	   
228 		
229 	    return LearningObjectiveServiceAssembler.toLoInfo(lo);
230 	   
231 	}
232 
233 	/* (non-Javadoc)
234 	 * @see org.kuali.student.lum.lo.service.LearningObjectiveService#deleteLo(java.lang.String)
235 	 */
236 	@Override
237 	@Transactional(readOnly=false,noRollbackFor={DoesNotExistException.class},rollbackFor={Throwable.class})
238 	public StatusInfo deleteLo ( String loId,  ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException ,DependentObjectsExistException{
239 	    checkForMissingParameter(loId, "loId");
240 	    
241 	    StatusInfo returnStatus = new StatusInfo();
242 	    returnStatus.setSuccess(loDao.deleteLo(loId));
243 		return returnStatus;
244 	}
245 
246 	/* (non-Javadoc)
247 	 * @see org.kuali.student.lum.lo.service.LearningObjectiveService#deleteLoCategory(java.lang.String)
248 	 */
249 	@Override
250 	@Transactional(readOnly=false,noRollbackFor={DoesNotExistException.class},rollbackFor={Throwable.class})
251 	public StatusInfo deleteLoCategory(String loCategoryId,ContextInfo contextInfo)
252             throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException, DependentObjectsExistException {
253 	    checkForMissingParameter(loCategoryId, "loCategoryId");
254 	    
255 	    loDao.deleteLoCategory(loCategoryId);
256 	    
257 		return new StatusInfo();
258 	}
259 
260     @Override
261     public StatusInfo deleteLoCategoryByLo(@WebParam(name = "loId") String loId, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
262         return null;  //To change body of implemented methods use File | Settings | File Templates.
263     }
264 
265     /* (non-Javadoc)
266       * @see org.kuali.student.lum.lo.service.LearningObjectiveService#getLo(java.lang.String)
267       */
268 	@Override
269     @Transactional(readOnly=true)
270 	public LoInfo getLo(String loId,ContextInfo contextInfo) throws DoesNotExistException,
271 			InvalidParameterException, MissingParameterException,
272 			OperationFailedException {
273 	    checkForMissingParameter(loId, "loId");
274 	    return LearningObjectiveServiceAssembler.toLoInfo(loDao.fetch(Lo.class, loId));
275 		
276 	}
277 
278 	@Override
279     @Transactional(readOnly=true)
280     public List<LoInfo> getLosByIds(@WebParam(name = "loIds") List<String> loIds, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
281         checkForMissingParameter(loIds, "loId");
282         checkForEmptyList(loIds, "loId");
283         List<Lo> los = loDao.getLoByIdList(loIds);
284         return LearningObjectiveServiceAssembler.toLoInfos(los);
285     }
286 
287     @Override
288     public List<String> getLoIdsByType(@WebParam(name = "loTypeKey") String loTypeKey, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
289         return null;  //To change body of implemented methods use File | Settings | File Templates.
290     }
291 
292     @Override
293     @Transactional(readOnly=true)
294     public List<LoInfo> getLosByLoRepository(@WebParam(name = "loRepositoryKey") String loRepositoryKey, @WebParam(name = "loTypeKey") String loTypeKey, @WebParam(name = "loStateKey") String loStateKey, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
295         checkForMissingParameter(loRepositoryKey, "loRepositoryKey");
296         List<Lo> los = loDao.getLosByRepository(loRepositoryKey);
297         return LearningObjectiveServiceAssembler.toLoInfos(los);
298     }
299 
300 	/* (non-Javadoc)
301 	 * @see org.kuali.student.lum.lo.service.LearningObjectiveService#getLoCategory(java.lang.String)
302 	 */
303 	@Override
304     @Transactional(readOnly=true)
305 	public LoCategoryInfo getLoCategory(String loCategoryId,ContextInfo contextInfo)
306 			throws DoesNotExistException, InvalidParameterException,
307 			MissingParameterException, OperationFailedException {
308 	    checkForMissingParameter(loCategoryId, "loCategoryId");
309 	    
310  
311 	    return LearningObjectiveServiceAssembler.toLoCategoryInfo(loDao.fetch(LoCategory.class, loCategoryId)); 
312 	}
313 
314     @Override
315     public List<LoCategoryInfo> getLoCategoriesByIds(@WebParam(name = "loCategoryIds") List<String> loCategoryIds, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
316         return null;  //To change body of implemented methods use File | Settings | File Templates.
317     }
318 
319     @Override
320     public List<String> getLoCategoryIdsByType(@WebParam(name = "loCategoryTypeKey") String loCategoryTypeKey, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
321         return null;  //To change body of implemented methods use File | Settings | File Templates.
322     }
323 
324     @Override
325     @Transactional(readOnly=true)
326     public List<LoCategoryInfo> getLoCategoriesByLo(@WebParam(name = "loId") String loId, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
327         checkForMissingParameter(loId, "loId");
328         List<LoCategory> categories = loDao.getLoCategoriesForLo(loId);
329         return LearningObjectiveServiceAssembler.toLoCategoryInfos(categories);
330     }
331 
332     @Override
333     public List<String> searchForLoCategoryIds(@WebParam(name = "criteria") QueryByCriteria criteria, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
334         return null;  //To change body of implemented methods use File | Settings | File Templates.
335     }
336 
337     @Override
338     public List<LoCategoryInfo> searchForLoCategories(@WebParam(name = "criteria") QueryByCriteria criteria, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
339         return null;  //To change body of implemented methods use File | Settings | File Templates.
340     }
341 
342     /* (non-Javadoc)
343       * @see org.kuali.student.lum.lo.service.LearningObjectiveService#getLoParents(java.lang.String)
344      public List<LoInfo> getLoParents(String loId) throws DoesNotExistException,
345              InvalidParameterException, MissingParameterException,
346              OperationFailedException {
347          checkForMissingParameter(loId, "loId");
348          List<Lo> loParents = loDao.getLoParents(loId);
349          return LearningObjectiveServiceAssembler.toLoInfos(loParents);
350      }
351       */
352 
353 	/* (non-Javadoc)
354 	 * @see org.kuali.student.lum.lo.service.LearningObjectiveService#getLosByLoCategory(java.lang.String)
355 	 */
356 	@Override
357     @Transactional(readOnly=true)
358 	public List<LoInfo> getLosByLoCategory(String loCategoryId,ContextInfo contextInfo)
359 			throws DoesNotExistException, InvalidParameterException,
360 			MissingParameterException, OperationFailedException {
361 	    checkForMissingParameter(loCategoryId, "loCategoryId");
362 	    List<Lo> los = loDao.getLosByLoCategory(loCategoryId);
363 	    return LearningObjectiveServiceAssembler.toLoInfos(los);
364 	}
365 
366     @Override
367     public List<String> searchForLoIds(@WebParam(name = "criteria") QueryByCriteria criteria, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
368         return null;  //To change body of implemented methods use File | Settings | File Templates.
369     }
370 
371     @Override
372     public List<LoInfo> searchForLos(@WebParam(name = "criteria") QueryByCriteria criteria, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
373         return null;  //To change body of implemented methods use File | Settings | File Templates.
374     }
375 
376     /* (non-Javadoc)
377       * @see org.kuali.student.lum.lo.service.LearningObjectiveService#isDescendant(java.lang.String, java.lang.String)
378      @Override
379      public Boolean isDescendant(String loId, String descendantLoId)
380              throws DoesNotExistException, InvalidParameterException,
381              MissingParameterException, OperationFailedException {
382          checkForMissingParameter(loId, "loId");
383          checkForMissingParameter(descendantLoId, "descendantLoId");
384          return loDao.isDescendant(loId, descendantLoId);
385      }
386       */
387 
388 	/* (non-Javadoc)
389 	 * @see org.kuali.student.lum.lo.service.LearningObjectiveService#isEquivalent(java.lang.String, java.lang.String)
390 	@Override
391 	public Boolean isEquivalent(String loId, String equivalentLoId)
392 			throws DoesNotExistException, InvalidParameterException,
393 			MissingParameterException, OperationFailedException {
394 	    checkForMissingParameter(loId, "loId");
395 	    checkForMissingParameter(equivalentLoId, "equivalentLoId");
396 		return loDao.isEquivalent(loId, equivalentLoId);
397 	}
398 	 */
399 
400 	/* (non-Javadoc)
401 	 * @see org.kuali.student.lum.lo.service.LearningObjectiveService#removeChildLoFromLo(java.lang.String, java.lang.String)
402 	@Override
403 	@Transactional(readOnly=false,noRollbackFor={DoesNotExistException.class},rollbackFor={Throwable.class})
404 	public StatusInfo removeChildLoFromLo(String loId, String parentLoId)
405 			throws DependentObjectsExistException, DoesNotExistException,
406 			InvalidParameterException, MissingParameterException,
407 			OperationFailedException, PermissionDeniedException {
408 	    checkForMissingParameter(loId, "loId");
409 	    checkForMissingParameter(parentLoId, "parentLoId");
410 	    
411 	    StatusInfo statusInfo = new StatusInfo();
412 	    statusInfo.setSuccess(loDao.removeChildLoFromLo(loId, parentLoId));
413 		return statusInfo;
414 	}
415 	 */
416 
417 	/* (non-Javadoc)
418 	 * @see org.kuali.student.lum.lo.service.LearningObjectiveService#removeEquivalentLoFromLo(java.lang.String, java.lang.String)
419 	@Override
420 	@Transactional(readOnly=false,noRollbackFor={DoesNotExistException.class},rollbackFor={Throwable.class})
421 	public StatusInfo removeEquivalentLoFromLo(String loId,
422 			String equivalentLoId) throws DoesNotExistException,
423 			InvalidParameterException, MissingParameterException,
424 			OperationFailedException, PermissionDeniedException {
425 	    checkForMissingParameter(loId, "loId");
426 	    checkForMissingParameter(equivalentLoId, "equivalentLoId");
427 	    
428         StatusInfo statusInfo = new StatusInfo();
429         statusInfo.setSuccess(loDao.removeEquivalentLoFromLo(loId, equivalentLoId));
430         return statusInfo;
431 	}
432 	 */
433 
434 	/* (non-Javadoc)
435 	 * @see org.kuali.student.lum.lo.service.LearningObjectiveService#removeLoCategoryFromLo(java.lang.String, java.lang.String)
436 	 */
437 	@Override
438 	@Transactional(readOnly=false,noRollbackFor={DoesNotExistException.class},rollbackFor={Throwable.class})
439 	public StatusInfo removeLoCategoryFromLo(String loCategoryId, String loId,ContextInfo contextInfo)
440 			throws DoesNotExistException, InvalidParameterException,
441 			MissingParameterException, OperationFailedException,
442 			PermissionDeniedException, UnsupportedActionException {
443 	    checkForMissingParameter(loCategoryId, "loCategoryId");
444 	    checkForMissingParameter(loId, "loId");
445 	    
446         StatusInfo statusInfo = new StatusInfo();
447         statusInfo.setSuccess(loDao.removeLoCategoryFromLo(loCategoryId, loId));
448         return statusInfo;
449 	}
450 
451 	/* (non-Javadoc)
452 	 * @see org.kuali.student.lum.lo.service.LearningObjectiveService#updateLo(java.lang.String, org.kuali.student.lum.lo.dto.LoInfo)
453 	 */
454 	@Override
455 	@Transactional(readOnly=false,noRollbackFor={DoesNotExistException.class},rollbackFor={Throwable.class})
456 	public LoInfo updateLo(String loId, LoInfo loInfo,ContextInfo contextInfo)
457 			throws DataValidationErrorException, DoesNotExistException,
458 			InvalidParameterException, MissingParameterException,
459 			OperationFailedException, PermissionDeniedException,
460 			VersionMismatchException {
461 	    checkForMissingParameter(loId, "loId");
462 	    checkForMissingParameter(loInfo, "loInfo");
463 
464 		// Validate LO
465 		List<ValidationResultInfo> val = validateLo("SYSTEM", loInfo,contextInfo);
466 		if(null != val && val.size() > 0) {
467 			for (ValidationResultInfo result : val) {
468 				System.err.println("Validation error. Element: " + result.getElement() + ",  Value: " + result.getMessage());
469 			}
470 			 
471 			throw new DataValidationErrorException("Validation error!", val);
472 			
473 		}
474 		
475 	    Lo lo = loDao.fetch(Lo.class, loId);
476         
477         if (!String.valueOf(lo.getVersionNumber()).equals(loInfo.getMeta().getVersionInd())){
478             throw new VersionMismatchException("LO to be updated is not the current version");
479         }
480         
481         lo = LearningObjectiveServiceAssembler.toLo(true, lo, loInfo, loDao);
482         loDao.update(lo);
483         return LearningObjectiveServiceAssembler.toLoInfo(lo);
484 	}
485 
486 	/* (non-Javadoc)
487 	 * @see org.kuali.student.lum.lo.service.LearningObjectiveService#updateLoCategory(java.lang.String, org.kuali.student.lum.lo.dto.LoCategoryInfo)
488 	 */
489 	@Override
490 	@Transactional(readOnly=false,noRollbackFor={DoesNotExistException.class},rollbackFor={Throwable.class})
491 	public LoCategoryInfo updateLoCategory(String loCategoryId,
492 			LoCategoryInfo loCategoryInfo,ContextInfo contextInfo) throws DataValidationErrorException,
493 			DoesNotExistException, InvalidParameterException,
494 			MissingParameterException, OperationFailedException,
495 			PermissionDeniedException, VersionMismatchException {
496 	    checkForMissingParameter(loCategoryId, "loCategoryId");
497 	    checkForMissingParameter(loCategoryInfo, "loCategoryInfo");
498 	    
499 		// Validate LoCategory
500 		List<ValidationResultInfo> val = validateLoCategory("SYSTEM", loCategoryInfo,contextInfo);
501 
502 		//kslum-136 - don't allow dups w/ same name (case insensitive), type, state & repository
503 //TODO KSCM-448
504         if (doesLoCategoryExist(loCategoryInfo.getLoRepositoryKey(), loCategoryInfo, loCategoryId,contextInfo)) {
505             ValidationResultInfo vr = new ValidationResultInfo();
506             vr.setElement("LO Category Name");
507             vr.setError("LO Category already exists");
508             val.add(vr);
509         }
510         if(null != val && val.size() > 0) {
511             for (ValidationResultInfo result : val) {
512                 System.err.println("Validation error. Element: " + result.getElement() + ",  Value: " + result.getMessage());
513             }
514  
515             throw new DataValidationErrorException("Validation error!", val);
516 
517         }
518 	    LoCategory loCategory = loDao.fetch(LoCategory.class, loCategoryId);
519         
520         if (!String.valueOf(loCategory.getVersionNumber()).equals(loCategoryInfo.getMeta().getVersionInd())){
521             throw new VersionMismatchException("LoCategory to be updated is not the current version");
522         }
523         
524         // if state is changing from "active"
525         if (loCategory.getState().equals("active") && ( ! loCategoryInfo.getStateKey().equals("active") )) {
526     		// N.B. - ability to 'retire' LoCategory's that are still associated w/ active
527     		// LO's is configured and enforced on the atpService
528         	List<LoInfo> loInfos = getLosByLoCategory(loCategoryId,contextInfo);
529     		if (null != loInfos) {
530 				// remove associations of this LoCategory from active LO's
531     			for (LoInfo info : loInfos) {
532     				if ("active".equals(info.getStateKey()))  {
533 	    				try {
534 							removeLoCategoryFromLo(loCategoryId, info.getId(),contextInfo);
535 						} catch (UnsupportedActionException uaee) {
536 				    		throw new OperationFailedException("Unable to update LoCategory: could not remove association with active LearningObjective", uaee);
537 						}
538     				}
539     			}
540     		}
541         }
542         	
543         // if type is changing
544         if ( ! loCategory.getLoCategoryType().getId().equals(loCategoryInfo.getTypeKey()) ) {
545         	loCategory = cloneLoCategory(loCategory, loCategoryInfo,contextInfo);
546         } else {
547         	loCategory = LearningObjectiveServiceAssembler.toLoCategory(loCategory, loCategoryInfo, loDao);
548 	        loDao.update(loCategory);
549         }
550        return LearningObjectiveServiceAssembler.toLoCategoryInfo(loCategory);
551 
552 	}
553 
554     // inactivate current LoCategory & clone it w/ its relationships,
555 	// used when changing immutable type of LoCategory
556 	// https://test.kuali.org/confluence/display/KULSTG/DS+-+LO+Centrally+Maintain+Categories
557 	private LoCategory cloneLoCategory(LoCategory loCategory, LoCategoryInfo loCategoryInfo,ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, OperationFailedException {
558     	LoCategoryType catType = null;
559     	
560     	try {
561         	catType = loDao.fetch(LoCategoryType.class, loCategoryInfo.getTypeKey());
562     	} catch (DoesNotExistException dnee) {
563     		throw new DoesNotExistException("Attempt to set LoCategory's type to nonexistent LoCategoryType", dnee);
564     	}
565         	
566     	// clone the existing LO
567     	LoCategoryInfo newLoCategoryInfo = LearningObjectiveServiceAssembler.toLoCategoryInfo(loCategory);
568     	newLoCategoryInfo.setTypeKey(catType.getId());
569     	newLoCategoryInfo.setName(loCategoryInfo.getName());
570     	LoCategory newLoCategory = loDao.create(LearningObjectiveServiceAssembler.toLoCategory(newLoCategoryInfo, loDao));
571         	
572     	// clone Lo-LoCategory relations
573     	List<Lo> catsLos = loDao.getLosByLoCategory(loCategory.getId());         	
574     	for (Lo lo : catsLos) {
575     		try {
576     			// create the new one
577 				loDao.addLoCategoryToLo(newLoCategory.getId(), lo.getId());
578 				// remove the old one
579 				loDao.removeLoCategoryFromLo(loCategory.getId(), lo.getId());
580 			} catch (UnsupportedActionException uae) {
581 				throw new OperationFailedException(uae.getMessage(), uae);
582 			}
583     	}
584         	
585     	// suspend old LoCategory
586     	loCategory.setState("Suspended");
587     	loDao.update(loCategory);
588         	
589     	return newLoCategory;
590 	}
591 
592 	/* (non-Javadoc)
593 	 * @see org.kuali.student.lum.lo.service.LearningObjectiveService#validateLo(java.lang.String, org.kuali.student.lum.lo.dto.LoInfo)
594 	 */
595 	@Override
596 	public List<ValidationResultInfo> validateLo(String validationType,
597 			LoInfo loInfo,ContextInfo contextInfo) throws DoesNotExistException,
598 			InvalidParameterException, MissingParameterException,
599 			OperationFailedException {
600 	    checkForMissingParameter(validationType, "validationType");
601 	    checkForMissingParameter(loInfo, "loInfo");
602 
603      // this is the job of the validator not some hard coded value
604 //	    try{
605 //	    	String loDesc = loInfo.getDescr().getPlain();
606 //	    	checkForEmptyString(loDesc, "loInfo.Desc");
607 //	    } catch (NullPointerException e){
608 //			//do not checkForEmptyString
609 //		}
610 	    
611 	   ObjectStructureDefinition objStructure = this.getObjectStructure(LoInfo.class.getName(),contextInfo);
612 	    Validator validator = validatorFactory.getValidator();
613 	    return validator.validateObject(loInfo, objStructure,contextInfo);
614 	}
615 
616 	/* (non-Javadoc)
617 	 * @see org.kuali.student.lum.lo.service.LearningObjectiveService#validateLoCategory(java.lang.String, org.kuali.student.lum.lo.dto.LoCategoryInfo)
618 	 */
619 	@Override
620 	public List<ValidationResultInfo> validateLoCategory(String validationType,
621 			LoCategoryInfo loCategoryInfo,ContextInfo contextInfo) throws DoesNotExistException,
622 			InvalidParameterException, MissingParameterException,
623 			OperationFailedException {
624 	    checkForMissingParameter(validationType, "validationType");
625 	    checkForMissingParameter(loCategoryInfo, "loCategoryInfo");
626 
627      // this is the job of the validator not some hard coded logic
628 //	    try{
629 //	    	String catDesc = loCategoryInfo.getDesc().getPlain();
630 //	    	checkForEmptyString(catDesc, "loCategoryInfo.Desc");
631 //	    } catch (NullPointerException e){
632 //			//do not checkForEmptyString
633 //		}
634 
635 	   ObjectStructureDefinition objStructure = this.getObjectStructure(LoCategoryInfo.class.getName(),contextInfo);
636         Validator validator = validatorFactory.getValidator();
637         return validator.validateObject(loCategoryInfo, objStructure,contextInfo);
638 	}
639 
640 	@Override
641 	public List<ValidationResultInfo> validateLoLoRelation(
642 			String validationType, LoLoRelationInfo loLoRelationInfo,ContextInfo contextInfo)
643 			throws DoesNotExistException, InvalidParameterException,
644 			MissingParameterException, OperationFailedException {
645 
646 		ObjectStructureDefinition objStructure = this.getObjectStructure(LoLoRelationInfo.class.getName(),contextInfo);
647         Validator validator = validatorFactory.getValidator();
648         return validator.validateObject(loLoRelationInfo, objStructure,contextInfo);
649 	}
650 
651     /**
652      * Check for missing parameter and throw localized exception if missing
653      *
654      * @param param
655      * @param paramName
656      * @throws MissingParameterException
657      */
658     private void checkForMissingParameter(Object param, String paramName)
659             throws MissingParameterException {
660         if (param == null) {
661             throw new MissingParameterException(paramName + " can not be null");
662         }
663     }
664 
665     /**
666      * @param param
667      * @param paramName
668      * @throws MissingParameterException
669      */
670     private void checkForEmptyList(Object param, String paramName)
671             throws MissingParameterException {
672         if (param != null && param instanceof List && ((List<?>)param).size() == 0) {
673             throw new MissingParameterException(paramName + " can not be an empty list");
674         }
675     }
676 
677     // this is the job of the validator not some hard coded logic
678     // besides it should create a validation result not a missing parameter exeception
679     /**
680      * @param param
681      * @param paramName
682      * @throws MissingParameterException
683      */
684     private void checkForEmptyString(String param, String paramName)
685             throws MissingParameterException {
686         if (param != null && "".equals(param.trim())) {
687             throw new MissingParameterException(paramName + " can not be empty");
688         }
689     }
690 
691     /**
692      * @param loRepositoryKey
693      * @param loCategoryInfo
694      * @param loCategoryId
695      * @throws MissingParameterException,OperationFailedException
696      */
697     private boolean doesLoCategoryExist(String loRepositoryKey, LoCategoryInfo loCategoryInfo, String loCategoryId,ContextInfo contextInfo)
698             throws MissingParameterException, DataValidationErrorException, PermissionDeniedException, OperationFailedException, InvalidParameterException {
699     if (loCategoryInfo.getName() == null)
700     {
701      return false;
702     }
703         boolean exists = false;
704 	    SearchRequestInfo request = new SearchRequestInfo();
705 	    request.setSearchKey("lo.search.loCategoriesByNameRepoTypeState");
706 	    
707  		List<SearchParamInfo> searchParams = new ArrayList<SearchParamInfo>();
708 		SearchParamInfo qpv1 = new SearchParamInfo();
709 		qpv1.setKey("lo.queryParam.loCategoryName");
710 		qpv1.getValues().add(loCategoryInfo.getName().toLowerCase());
711 		searchParams.add(qpv1);
712 		SearchParamInfo qpv2 = new SearchParamInfo();
713 		qpv2.setKey("lo.queryParam.loCategoryRepo");
714 		qpv2.getValues().add(loRepositoryKey);
715 		searchParams.add(qpv2);
716 		SearchParamInfo qpv3 = new SearchParamInfo();
717 		qpv3.setKey("lo.queryParam.loCategoryType");
718 		qpv3.getValues().add(loCategoryInfo.getTypeKey());
719 		searchParams.add(qpv3);
720 		SearchParamInfo qpv4 = new SearchParamInfo();
721 		qpv4.setKey("lo.queryParam.loCategoryState");
722 		qpv4.getValues().add(loCategoryInfo.getStateKey());
723 		searchParams.add(qpv4);
724 		
725 		request.setParams(searchParams);
726 			
727 		SearchResultInfo result = search(request, contextInfo);
728 		
729 		if(loCategoryId != null && !loCategoryId.trim().equals("")){
730 			if (result.getRows().size() > 0) {
731 				for(SearchResultRowInfo srrow : result.getRows()){
732 					List<SearchResultCellInfo> srCells = srrow.getCells();
733 					if(srCells != null && srCells.size() > 0){
734 						for(SearchResultCellInfo srcell : srCells){
735 							if(!srcell.getValue().equals(loCategoryId)) {
736                                 exists = true;
737                             }
738 						}
739 					}
740 				}
741 			}
742 		}
743 		else{
744 			if (result.getRows().size() > 0) {
745                 exists = true;
746 			}
747 		}
748         return exists;
749     }
750     
751     //@Override
752     public ObjectStructureDefinition getObjectStructure(String objectTypeKey,ContextInfo contextInfo) {
753         return dictionaryServiceDelegate.getObjectStructure(objectTypeKey);
754     }
755 
756 //    @Override
757 //    public List<String> getObjectTypes() {
758 //        return dictionaryServiceDelegate.getObjectTypes();
759 //    }
760 
761 
762 	/* (non-Javadoc)
763 	 * @see org.kuali.student.common.search.service.SearchService#getSearchType(java.lang.String)
764 	 */
765     @Override
766     public TypeInfo getSearchType(String searchTypeKey, ContextInfo contextInfo)
767     throws DoesNotExistException, InvalidParameterException,
768     MissingParameterException, OperationFailedException {
769         checkForMissingParameter(searchTypeKey, "searchTypeKey");
770         return searchManager.getSearchType(searchTypeKey, contextInfo);
771     }
772 
773     /* (non-Javadoc)
774       * @see org.kuali.student.common.search.service.SearchService#getSearchTypes()
775       */
776     @Override
777     public List<TypeInfo> getSearchTypes(ContextInfo contextInfo)
778             throws OperationFailedException, InvalidParameterException, MissingParameterException {
779         return searchManager.getSearchTypes(contextInfo);
780     }
781 
782 
783 	@Override
784 	@Transactional(readOnly=false,noRollbackFor={DoesNotExistException.class},rollbackFor={Throwable.class})
785 	public LoLoRelationInfo  createLoLoRelation ( String loLoRelationTypeKey,  LoLoRelationInfo loLoRelationInfo,  ContextInfo contextInfo) throws DataValidationErrorException, DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException, ReadOnlyException {
786 		checkForMissingParameter(loLoRelationInfo, "loLoRelationInfo");
787 		checkForMissingParameter(loLoRelationTypeKey, "loLoRelationTypeKey");
788 		checkForMissingParameter(loLoRelationInfo.getLoId(), "loId");
789 	    checkForMissingParameter(loLoRelationInfo.getRelatedLoId(), "relatedLoId");
790 	    checkForMissingParameter(loLoRelationInfo.getTypeKey(), "loLoRelationType");
791 	   
792 		// Validate LoLoRelation
793 		List<ValidationResultInfo> val = validateLoLoRelation("SYSTEM", loLoRelationInfo,contextInfo);
794 		if(null != val && val.size() > 0) {
795 			for (ValidationResultInfo result : val) {
796 				System.err.println("Validation error. Element: " + result.getElement() + ",  Value: " + result.getMessage());
797 			}
798 		
799 			throw new DataValidationErrorException("Validation error!");
800 		}
801 	    
802 	    if (null == loLoRelationInfo.getStateKey()) {
803 	    	loLoRelationInfo.setStateKey(DtoConstants.STATE_DRAFT);
804 	    }
805 	    Lo lo = loDao.fetch(Lo.class, loLoRelationInfo.getLoId());
806 	    Lo relatedLo = loDao.fetch(Lo.class, loLoRelationInfo.getRelatedLoId());
807 	    LoLoRelationType type = loDao.fetch(LoLoRelationType.class, loLoRelationTypeKey);
808 	    loLoRelationInfo.setLoId(loLoRelationInfo.getLoId());
809 	    loLoRelationInfo.setRelatedLoId(loLoRelationInfo.getRelatedLoId());
810         loLoRelationInfo.setTypeKey(loLoRelationInfo.getTypeKey());
811 	    
812 	    LoLoRelation relation = null;
813 
814 	    try {
815 	    	relation = LearningObjectiveServiceAssembler.toLoLoRelation(false,  loLoRelationInfo, loDao);
816 	    } catch (VersionMismatchException vme) {
817 	    	// should never happen in a create call, but
818 	    	throw new OperationFailedException("VersionMismatchException caught during LoLoRelation creation");
819 	    }
820 	    relation.setLo(lo);
821 	    relation.setRelatedLo(relatedLo);
822 	    relation.setLoLoRelationType(type);
823 	    
824 	    relation = loDao.create(relation);
825 	    
826 	  return LearningObjectiveServiceAssembler.toLoLoRelationInfo(relation);
827 	
828 	}
829 	
830 	@Override
831 	@Transactional(readOnly=true)
832     public LoLoRelationInfo getLoLoRelation(@WebParam(name = "loLoRelationId") String loLoRelationId, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
833 	    checkForMissingParameter(loLoRelationId, "loLoRelationId");
834 	 return LearningObjectiveServiceAssembler.toLoLoRelationInfo(loDao.fetch(LoLoRelation.class, loLoRelationId));
835     }
836 	
837 	@Override
838 	@Transactional(readOnly=true)
839     public List<LoLoRelationInfo> getLoLoRelationsByLoId(@WebParam(name = "loId") String loId, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
840 	    List<LoLoRelation> llRelations = loDao.getLoLoRelationsByLoId(loId);
841 	    return LearningObjectiveServiceAssembler.toLoLoRelationInfos(llRelations);   
842     }
843 	
844 	@Override
845 	@Transactional(readOnly=true)
846     public List<LoInfo> getLosByRelatedLoId(@WebParam(name = "relatedLoId") String relatedLoId, @WebParam(name = "loLoRelationTypeKey") String loLoRelationTypeKey, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
847 	    List<Lo> relatedLos = loDao.getLosByRelatedLoId(relatedLoId, loLoRelationTypeKey);
848 	    return LearningObjectiveServiceAssembler.toLoInfos(relatedLos);
849     }
850 	
851 	@Override
852 	@Transactional(readOnly=true)
853     public List<LoInfo> getRelatedLosByLoId(@WebParam(name = "loId") String loId, @WebParam(name = "loLoRelationTypeKey") String loLoRelationTypeKey, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
854 		checkForMissingParameter(loId, "loId");
855 	    checkForMissingParameter(loLoRelationTypeKey, "loLoRelationTypeKey");
856 		List<Lo> relatedLos = loDao.getRelatedLosByLoId(loId, loLoRelationTypeKey);
857 	    return LearningObjectiveServiceAssembler.toLoInfos(relatedLos);
858     }
859 
860 	@Override
861 	@Transactional(readOnly=false,noRollbackFor={DoesNotExistException.class},rollbackFor={Throwable.class})
862 	public LoLoRelationInfo updateLoLoRelation ( String loLoRelationId,  LoLoRelationInfo loLoRelationInfo,  ContextInfo contextInfo)
863             throws DataValidationErrorException, DoesNotExistException, InvalidParameterException, MissingParameterException,
864             OperationFailedException, PermissionDeniedException, ReadOnlyException, VersionMismatchException {
865 		
866 
867 		// Validate LoLoRelation
868 		List<ValidationResultInfo> val = validateLoLoRelation("SYSTEM", loLoRelationInfo,contextInfo );
869 		if(null != val && val.size() > 0) {
870 
871 			throw new DataValidationErrorException("Validation error!", val);
872 
873 		}
874 
875 	    
876 		return null;
877 	}
878 
879     @Override
880     public StatusInfo deleteLoLoRelation(@WebParam(name = "loLoRelationId") String loLoRelationId, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
881         checkForMissingParameter(loLoRelationId, "loLoRelationId");
882         
883         loDao.deleteLoLoRelation(loLoRelationId);
884         
885         return new StatusInfo();
886     }
887 
888     @Override
889 	@Transactional(readOnly=false,noRollbackFor={DoesNotExistException.class},rollbackFor={Throwable.class})
890 	public LoCategoryInfo createLoCategory (String loCategoryTypeKey,  LoCategoryInfo loCategoryInfo,  ContextInfo contextInfo)
891             throws DataValidationErrorException, DoesNotExistException, InvalidParameterException, MissingParameterException,
892             OperationFailedException, PermissionDeniedException, ReadOnlyException {
893 	    checkForMissingParameter(loCategoryInfo.getLoRepositoryKey(), "loRepositoryKey");
894 	    checkForMissingParameter(loCategoryTypeKey, "loCategoryTypeKey");
895 	    checkForMissingParameter(loCategoryInfo, "loCategoryInfo");
896 	    
897 		// Validate LoCategory
898 		List<ValidationResultInfo> val = validateLoCategory("SYSTEM", loCategoryInfo,contextInfo);
899 
900         //kslum-136 - don't allow dups w/ same name (case insensitive), type, state & repository
901         if (doesLoCategoryExist(loCategoryInfo.getLoRepositoryKey(), loCategoryInfo, null,contextInfo)) {
902             ValidationResultInfo vr = new ValidationResultInfo();
903             vr.setElement("LO Category Name");
904             vr.setError("LO Category already exists");
905             val.add(vr);
906         }
907         if(null != val && val.size() > 0) {
908 			for (ValidationResultInfo result : val) {
909 				System.err.println("Validation error. Element: " + result.getElement() + ",  Value: " + result.getMessage());
910 			}
911 			throw new DataValidationErrorException("Validation error!", val);
912 			
913 		}
914         
915 	    LoCategory category = LearningObjectiveServiceAssembler.toLoCategory(loCategoryInfo,loDao);
916 	    LoCategoryType loCatType = loDao.fetch(LoCategoryType.class, loCategoryTypeKey);
917 	    category.setLoCategoryType(loCatType);
918 	    LoRepository loRepository = loDao.fetch(LoRepository.class, loCategoryInfo.getLoRepositoryKey() );
919 	    category.setLoRepository(loRepository);
920 	    loDao.create(category);
921 		return LearningObjectiveServiceAssembler.toLoCategoryInfo(category);
922 	}
923 
924     @Override
925     @Transactional(readOnly=true)
926     public TypeInfo getLoCategoryType(String loCategoryTypeKey,ContextInfo contextInfo)
927             throws DoesNotExistException, InvalidParameterException,
928             MissingParameterException, OperationFailedException {
929         checkForMissingParameter(loCategoryTypeKey, "loCategoryTypeKey");
930         LoCategoryType loCatType = loDao.fetch(LoCategoryType.class, loCategoryTypeKey);
931         return LearningObjectiveServiceAssembler.toGenericTypeInfo(loCatType);
932     }
933 
934     @Override
935     @Transactional(readOnly=true)
936     public List<TypeInfo> getLoCategoryTypes()
937             throws OperationFailedException {
938         List<LoCategoryType> categoryTypes = loDao.find(LoCategoryType.class);
939         return LearningObjectiveServiceAssembler.toGenericTypeInfoList(categoryTypes);
940     }
941 
942 	@Override
943     @Transactional(readOnly=true)
944 	public List<LoCategoryInfo> getLoCategoriesByLoRepository(
945 			String loRepositoryKey, ContextInfo contextInfo)
946 			throws DoesNotExistException, InvalidParameterException,
947 			MissingParameterException, OperationFailedException,
948 			PermissionDeniedException {
949         checkForMissingParameter(loRepositoryKey, "loRepositoryKey");
950         List<LoCategory> categories = loDao.getLoCategories(loRepositoryKey);
951         return LearningObjectiveServiceAssembler.toLoCategoryInfos(categories);
952 	}
953 
954     @Override
955     public SearchResultInfo search(SearchRequestInfo searchRequestInfo, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws MissingParameterException, OperationFailedException, PermissionDeniedException, InvalidParameterException {
956         checkForMissingParameter(searchRequestInfo, "searchRequest");
957         SearchResultInfo result =  searchManager.search(searchRequestInfo, contextInfo);
958         if("lo.search.loByCategory".equals(searchRequestInfo.getSearchKey())){
959         	for(SearchParamInfo param:searchRequestInfo.getParams()){
960         		if("lo.queryParam.groupCategories".equals(param.getKey())&&"true".equals(param.getValues().get(0))){
961         	groupCategories(result);
962         		}
963         	}
964         }
965         
966         return result;
967 	}
968 
969 	//Updates search results grouping category names as a comma delimited list
970 	private void groupCategories(SearchResultInfo result) {
971 		Map<String,SearchResultCellInfo> idToCellMap = new HashMap<String,SearchResultCellInfo>();
972 		for(Iterator<SearchResultRowInfo> iter = result.getRows().iterator();iter.hasNext();){
973 			SearchResultRowInfo row = iter.next();
974 			SearchResultCellInfo categoryCell = null;
975 			String loId = null;
976 			//Get search result cell values
977 			for(SearchResultCellInfo cell:row.getCells()){
978 				if("lo.resultColumn.categoryName".equals(cell.getKey())){
979 					categoryCell = cell;
980 					break;
981 				}else if("lo.resultColumn.loId".equals(cell.getKey())){
982 					loId = cell.getValue();
983 				}
984 			}
985 			//If a row exists with the same loId, append the category to the existing row and remove the current row.
986 			if(loId!=null){
987 				if(idToCellMap.containsKey(loId)){
988 					SearchResultCellInfo cell = idToCellMap.get(loId);
989 					if(cell == null){
990 						cell = new SearchResultCellInfo("lo.resultColumn.categoryName","");
991 						idToCellMap.put(loId, cell);
992 					}
993 					if(categoryCell!=null){
994 						if(cell.getValue()==null||cell.getValue().isEmpty()){
995 							cell.setValue(categoryCell.getValue());
996 						}else if(categoryCell.getValue()!=null && !categoryCell.getValue().isEmpty()){
997 							cell.setValue(cell.getValue()+", "+categoryCell.getValue());
998 						}
999 					}
1000 					//Remove this row since we alreay have a mapping to a row with this lo Id
1001 					iter.remove();
1002 				} else {
1003 					//Otherwise add a mapping and continue
1004 					idToCellMap.put(loId, categoryCell);
1005 				}
1006 			}
1007 		}
1008 	}
1009 	
1010 }