View Javadoc

1   package org.kuali.student.r2.lum.course.service.impl;
2   
3   import java.util.ArrayList;
4   import java.util.Date;
5   import java.util.List;
6   
7   import javax.jws.WebParam;
8   
9   import org.apache.log4j.Logger;
10  import org.kuali.rice.core.api.criteria.QueryByCriteria;
11  import org.kuali.student.common.conversion.util.R1R2ConverterUtil;
12  import org.kuali.student.r2.lum.course.service.assembler.CourseAssembler;
13  import org.kuali.student.r2.lum.course.service.assembler.CourseAssemblerConstants;
14  import org.kuali.student.r1.common.assembly.BaseDTOAssemblyNode;
15  import org.kuali.student.r1.common.assembly.BaseDTOAssemblyNode.NodeOperation;
16  import org.kuali.student.r1.common.assembly.BusinessServiceMethodInvoker;
17  import org.kuali.student.r1.common.dictionary.dto.ObjectStructureDefinition;
18  import org.kuali.student.r1.common.dictionary.service.DictionaryService;
19  import org.kuali.student.r1.common.validator.ValidatorUtils;
20  import org.kuali.student.r1.core.statement.dto.StatementTreeViewInfo;
21  import org.kuali.student.r1.core.statement.service.StatementService;
22  import org.kuali.student.r2.common.assembler.AssemblyException;
23  import org.kuali.student.r2.common.dto.ContextInfo;
24  import org.kuali.student.r2.common.dto.StatusInfo;
25  import org.kuali.student.r2.common.dto.ValidationResultInfo;
26  import org.kuali.student.r2.common.exceptions.AlreadyExistsException;
27  import org.kuali.student.r2.common.exceptions.CircularReferenceException;
28  import org.kuali.student.r2.common.exceptions.CircularRelationshipException;
29  import org.kuali.student.r2.common.exceptions.DataValidationErrorException;
30  import org.kuali.student.r2.common.exceptions.DependentObjectsExistException;
31  import org.kuali.student.r2.common.exceptions.DoesNotExistException;
32  import org.kuali.student.r2.common.exceptions.IllegalVersionSequencingException;
33  import org.kuali.student.r2.common.exceptions.InvalidParameterException;
34  import org.kuali.student.r2.common.exceptions.MissingParameterException;
35  import org.kuali.student.r2.common.exceptions.OperationFailedException;
36  import org.kuali.student.r2.common.exceptions.PermissionDeniedException;
37  import org.kuali.student.r2.common.exceptions.ReadOnlyException;
38  import org.kuali.student.r2.common.exceptions.UnsupportedActionException;
39  import org.kuali.student.r2.common.exceptions.VersionMismatchException;
40  import org.kuali.student.r2.common.validator.Validator;
41  import org.kuali.student.r2.common.validator.ValidatorFactory;
42  import org.kuali.student.r1.core.statement.dto.RefStatementRelationInfo;
43  import org.kuali.student.r2.core.versionmanagement.dto.VersionDisplayInfo;
44  import org.kuali.student.r2.lum.clu.dto.CluInfo;
45  import org.kuali.student.r2.lum.clu.service.CluService;
46  import org.kuali.student.r2.lum.course.dto.ActivityInfo;
47  import org.kuali.student.r2.lum.course.dto.CourseInfo;
48  import org.kuali.student.r2.lum.course.dto.FormatInfo;
49  import org.kuali.student.r2.lum.course.dto.LoDisplayInfo;
50  import org.kuali.student.r2.lum.course.service.CourseService;
51  import org.kuali.student.r2.lum.util.constants.CluServiceConstants;
52  import org.kuali.student.r2.lum.util.constants.CourseServiceConstants;
53  import org.springframework.transaction.annotation.Transactional;
54  
55  /**
56   * CourseServiceImpl implements CourseService Interface by mapping DTOs in CourseInfo to underlying entity DTOs like CluInfo
57   * and CluCluRelationInfo. For Credits, there are three credit types that are set with a combination of type and dynamic
58   * attributes To set a variable(range) credit option, set the ResultComponentInfo type to
59   * CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_VARIABLE and add the dynamic attributes
60   * CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_MIN_CREDIT_VALUE and
61   * CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_MAX_CREDIT_VALUE with respective credit min and max values. To set a
62   * fixed credit option, set the ResultComponentInfo type to CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_FIXED and
63   * add the dynamic attribute CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_FIXED_CREDIT_VALUE with the fixed credit value
64   * To Set multiple credit options, set the ResultComponentInfo type to
65   * CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_MULTIPLE and add each credit as a numeric ResultValue on the
66   * ResultComponentInfo for each credit you desire
67   * 
68   * @author Kuali Student Team
69   */
70  public class CourseServiceImpl implements CourseService {
71  
72      final static Logger LOG = Logger.getLogger(CourseServiceImpl.class);
73  
74      private CluService cluService;
75      private CourseAssembler courseAssembler;
76      private BusinessServiceMethodInvoker courseServiceMethodInvoker;
77      private DictionaryService dictionaryServiceDelegate;
78      private ValidatorFactory validatorFactory;
79      private StatementService statementService;
80  
81      @Override
82      @Transactional(readOnly = false, noRollbackFor = {DoesNotExistException.class}, rollbackFor = {Throwable.class})
83      public CourseInfo createCourse(CourseInfo courseInfo, ContextInfo contextInfo) throws DataValidationErrorException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException, VersionMismatchException {
84  
85          checkForMissingParameter(courseInfo, "CourseInfo");
86  
87          // Validate
88          List<ValidationResultInfo> validationResults = validateCourse("OBJECT", courseInfo, contextInfo);
89          if (ValidatorUtils.hasErrors(validationResults)) {
90              throw new DataValidationErrorException("Validation error!", validationResults);
91          }
92  
93          try {
94              return processCourseInfo(courseInfo, NodeOperation.CREATE, contextInfo);
95          } catch (AssemblyException e) {
96              LOG.error("Error disassembling course", e);
97              throw new OperationFailedException("Error disassembling course");
98          } catch (Exception e) {
99              LOG.error("Error disassembling course", e);
100             throw new OperationFailedException("Error disassembling course");
101         }
102     }
103 
104     @Override
105     @Transactional(readOnly = false, noRollbackFor = {DoesNotExistException.class}, rollbackFor = {Throwable.class})
106     public CourseInfo updateCourse(String courseId, CourseInfo courseInfo, ContextInfo contextInfo) throws DataValidationErrorException, DoesNotExistException, InvalidParameterException, MissingParameterException, VersionMismatchException, OperationFailedException, PermissionDeniedException, UnsupportedActionException, DependentObjectsExistException, AlreadyExistsException, CircularRelationshipException, CircularReferenceException, ReadOnlyException {
107 
108         checkForMissingParameter(courseInfo, "CourseInfo");
109 
110         // Validate
111         List<ValidationResultInfo> validationResults = validateCourse("OBJECT", courseInfo, contextInfo);
112         if (ValidatorUtils.hasErrors(validationResults)) {
113             throw new DataValidationErrorException("Validation error!", validationResults);
114         }
115 
116         try {
117 
118             return processCourseInfo(courseInfo, NodeOperation.UPDATE, contextInfo);
119 
120         } catch (VersionMismatchException vme) {
121             // Re-instantiate this exception with more descriptive error.
122             throw new VersionMismatchException("Course to be updated is not the current version.");
123 
124         } catch (AssemblyException e) {
125             LOG.error("Error disassembling course", e);
126             throw new OperationFailedException("Error disassembling course");
127         }
128     }
129 
130     @Override
131     @Transactional(readOnly = false, noRollbackFor = {DoesNotExistException.class}, rollbackFor = {Throwable.class})
132     public StatusInfo deleteCourse(String courseId, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException, VersionMismatchException, DataValidationErrorException, AlreadyExistsException, UnsupportedActionException, DependentObjectsExistException, CircularRelationshipException, CircularReferenceException, ReadOnlyException {
133 
134         try {
135             CourseInfo course = getCourse(courseId, contextInfo);
136 
137             processCourseInfo(course, NodeOperation.DELETE, contextInfo);
138 
139             StatusInfo status = new StatusInfo();
140             status.setSuccess(true);
141             return status;
142 
143         } catch (AssemblyException e) {
144             LOG.error("Error disassembling course", e);
145             throw new OperationFailedException("Error disassembling course");
146         }
147     }
148 
149     @Override
150     @Transactional(readOnly = true)
151     public CourseInfo getCourse(String courseId, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
152 
153         CluInfo clu = cluService.getClu(courseId, contextInfo);
154 
155         CourseInfo course;
156 
157         try {
158             course = courseAssembler.assemble(clu, null, false, contextInfo);
159 
160         } catch (AssemblyException e) {
161             LOG.error("Error assembling course", e);
162             throw new OperationFailedException("Error assembling course");
163         }
164 
165         return course;
166 
167     }
168 
169     @Transactional(readOnly = true)
170     public List<ActivityInfo> getCourseActivities(String formatId) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
171         throw new UnsupportedOperationException("GetCourseActivities");
172     }
173 
174     @Transactional(readOnly = true)
175     public List<FormatInfo> getCourseFormats(String courseId) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
176         throw new UnsupportedOperationException("GetCourseFormats");
177     }
178 
179     @Transactional(readOnly = true)
180     public List<LoDisplayInfo> getCourseLos(String courseId) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
181         throw new UnsupportedOperationException("GetCourseLos");
182     }
183 
184     @Override
185     @Transactional(readOnly = true)
186     public List<StatementTreeViewInfo> getCourseStatements(String courseId, String nlUsageTypeKey, String language, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
187         checkForMissingParameter(courseId, "courseId");
188 
189         CluInfo clu = cluService.getClu(courseId, contextInfo);
190         if (!CourseAssemblerConstants.COURSE_TYPE.equals(clu.getTypeKey())) {
191             throw new DoesNotExistException("Specified CLU is not a Course");
192         }
193         List<RefStatementRelationInfo> relations = R1R2ConverterUtil.convertLists(statementService.getRefStatementRelationsByRef(CourseAssemblerConstants.COURSE_TYPE, clu.getId()), RefStatementRelationInfo.class);
194         if (relations == null) {
195             return new ArrayList<StatementTreeViewInfo>(0);
196         }
197 
198         List<StatementTreeViewInfo> tree = new ArrayList<StatementTreeViewInfo>(relations.size());
199         for (RefStatementRelationInfo relation : relations) {
200             tree.add(statementService.getStatementTreeView(relation.getStatementId()));
201         }
202         return tree;
203     }
204 
205     @Transactional(readOnly = true)
206     public List<ValidationResultInfo> validateCourse(String validationType, CourseInfo courseInfo, ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException {
207 
208         ObjectStructureDefinition objStructure = this.getObjectStructure(CourseInfo.class.getName());
209         Validator defaultValidator = validatorFactory.getValidator();
210         List<ValidationResultInfo> validationResults = defaultValidator.validateObject(courseInfo, objStructure, contextInfo);
211         return validationResults;
212     }
213 
214     @Override
215     @Transactional(readOnly = false, noRollbackFor = {DoesNotExistException.class}, rollbackFor = {Throwable.class})
216     public StatementTreeViewInfo createCourseStatement(String courseId, StatementTreeViewInfo statementTreeViewInfo, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException, DataValidationErrorException {
217         checkForMissingParameter(courseId, "courseId");
218         checkForMissingParameter(statementTreeViewInfo, "statementTreeViewInfo");
219 
220         // Validate
221         List<ValidationResultInfo> validationResults = validateCourseStatement(courseId, statementTreeViewInfo, contextInfo);
222         if (ValidatorUtils.hasErrors(validationResults)) {
223             throw new DataValidationErrorException("Validation error!", validationResults);
224         }
225 
226         if (findStatementReference(courseId, statementTreeViewInfo, contextInfo) != null) {
227             throw new InvalidParameterException("Statement is already referenced by this course");
228         }
229 
230         try {
231             StatementTreeViewInfo tree = statementService.createStatementTreeView(statementTreeViewInfo);
232             RefStatementRelationInfo relation = new RefStatementRelationInfo();
233             relation.setRefObjectId(courseId);
234             relation.setRefObjectTypeKey(CourseAssemblerConstants.COURSE_TYPE);
235             relation.setStatementId(tree.getId());
236             relation.setType(CourseAssemblerConstants.COURSE_REFERENCE_TYPE);
237             relation.setState(CourseAssemblerConstants.ACTIVE);
238             statementService.createRefStatementRelation(R1R2ConverterUtil.convert(relation, org.kuali.student.r1.core.statement.dto.RefStatementRelationInfo.class));
239         } catch (Exception e) {
240             throw new OperationFailedException("Unable to create clu/tree relation", e);
241         }
242         return statementTreeViewInfo;
243     }
244 
245 	@Override
246     @Transactional(readOnly = false, noRollbackFor = {DoesNotExistException.class}, rollbackFor = {Throwable.class})
247     public StatusInfo deleteCourseStatement(String courseId, StatementTreeViewInfo statementTreeViewInfo, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
248         checkForMissingParameter(courseId, "courseId");
249         checkForMissingParameter(statementTreeViewInfo, "statementTreeViewInfo");
250 
251         RefStatementRelationInfo relation = findStatementReference(courseId, statementTreeViewInfo, contextInfo);
252         if (relation != null) {
253             statementService.deleteRefStatementRelation(relation.getId());
254             statementService.deleteStatementTreeView(statementTreeViewInfo.getId());
255             StatusInfo result = new StatusInfo();
256             return result;
257         }
258 
259         throw new DoesNotExistException("Course does not have this StatemenTree");
260     }
261 
262     @Override
263     @Transactional(readOnly = false, noRollbackFor = {DoesNotExistException.class}, rollbackFor = {Throwable.class})
264     public StatementTreeViewInfo updateCourseStatement(String courseId, String statementId, StatementTreeViewInfo statementTreeViewInfo, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException, DataValidationErrorException, VersionMismatchException {
265         checkForMissingParameter(courseId, "courseId");
266         checkForMissingParameter(statementTreeViewInfo, "statementTreeViewInfo");
267 
268         // Validate
269         List<ValidationResultInfo> validationResults = validateCourseStatement(courseId, statementTreeViewInfo, contextInfo);
270         if (ValidatorUtils.hasErrors(validationResults)) {
271             throw new DataValidationErrorException("Validation error!", validationResults);
272         }
273 
274         if (findStatementReference(courseId, statementTreeViewInfo, contextInfo) == null) {
275             throw new InvalidParameterException("Statement is not part of this course");
276         }
277 
278         try {
279             return statementService.updateStatementTreeView(statementTreeViewInfo.getId(), statementTreeViewInfo);
280         } catch (CircularReferenceException e) {
281             e.printStackTrace();
282         }
283         return null;
284     }
285 
286     @Transactional(readOnly = true)
287     public List<ValidationResultInfo> validateCourseStatement(String courseId, StatementTreeViewInfo statementTreeViewInfo, ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
288         checkForMissingParameter(courseId, "courseId");
289         checkForMissingParameter(statementTreeViewInfo, "statementTreeViewInfo");
290 
291         try {
292             CluInfo clu = cluService.getClu(courseId, contextInfo);
293         } catch (DoesNotExistException e) {
294             throw new InvalidParameterException("course does not exist");
295         }
296 
297         ObjectStructureDefinition objStructure = this.getObjectStructure(StatementTreeViewInfo.class.getName());
298         Validator defaultValidator = validatorFactory.getValidator();
299         List<ValidationResultInfo> validationResults = defaultValidator.validateObject(statementTreeViewInfo, objStructure, contextInfo);
300         return validationResults;
301     }
302 
303     @Override
304     public ObjectStructureDefinition getObjectStructure(String objectTypeKey){
305         return dictionaryServiceDelegate.getObjectStructure(objectTypeKey);
306     }
307 
308     @Override
309     public List<String> getObjectTypes(){
310         return dictionaryServiceDelegate.getObjectTypes();
311     }
312 
313     public CourseAssembler getCourseAssembler() {
314         return courseAssembler;
315     }
316 
317     public void setCourseAssembler(CourseAssembler courseAssembler) {
318         this.courseAssembler = courseAssembler;
319     }
320 
321     public BusinessServiceMethodInvoker getCourseServiceMethodInvoker() {
322         return courseServiceMethodInvoker;
323     }
324 
325     public void setCourseServiceMethodInvoker(BusinessServiceMethodInvoker courseServiceMethodInvoker) {
326         this.courseServiceMethodInvoker = courseServiceMethodInvoker;
327     }
328 
329     public DictionaryService getDictionaryServiceDelegate() {
330         return dictionaryServiceDelegate;
331     }
332 
333     public void setDictionaryServiceDelegate(DictionaryService dictionaryServiceDelegate) {
334         this.dictionaryServiceDelegate = dictionaryServiceDelegate;
335     }
336 
337     private CourseInfo processCourseInfo(CourseInfo courseInfo, NodeOperation operation, ContextInfo contextInfo) throws DataValidationErrorException, DoesNotExistException, InvalidParameterException, MissingParameterException, VersionMismatchException, OperationFailedException, PermissionDeniedException, AssemblyException, UnsupportedActionException, DependentObjectsExistException, AlreadyExistsException, CircularRelationshipException, CircularReferenceException, ReadOnlyException {
338 
339         BaseDTOAssemblyNode<CourseInfo, CluInfo> results = courseAssembler.disassemble(courseInfo, operation, contextInfo);
340 
341         // Use the results to make the appropriate service calls here
342         courseServiceMethodInvoker.invokeServiceCalls(results, contextInfo);
343 
344         return results.getBusinessDTORef();
345     }
346 
347     public ValidatorFactory getValidatorFactory() {
348         return validatorFactory;
349     }
350 
351     public void setValidatorFactory(ValidatorFactory validatorFactory) {
352         this.validatorFactory = validatorFactory;
353     }
354 
355     public CluService getCluService() {
356         return cluService;
357     }
358 
359     public void setCluService(CluService cluService) {
360         this.cluService = cluService;
361     }
362 
363     public StatementService getStatementService() {
364         return statementService;
365     }
366 
367     public void setStatementService(StatementService statementService) {
368         this.statementService = statementService;
369     }
370 
371 	@Override
372     @Transactional(readOnly = false, noRollbackFor = {DoesNotExistException.class}, rollbackFor = {Throwable.class})
373     public CourseInfo createNewCourseVersion(String versionIndCourseId, String versionComment, ContextInfo contextInfo) throws DataValidationErrorException, DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException, VersionMismatchException, ReadOnlyException {
374 
375         // step one, get the original course
376         VersionDisplayInfo currentVersion = cluService.getCurrentVersion(CluServiceConstants.CLU_NAMESPACE_URI, versionIndCourseId, contextInfo);
377         CourseInfo originalCourse = getCourse((String) currentVersion.getId(), contextInfo);
378 
379         // Version the Clu
380         CluInfo newVersionClu = cluService.createNewCluVersion(versionIndCourseId, versionComment, contextInfo);
381 
382         try {
383             BaseDTOAssemblyNode<CourseInfo, CluInfo> results;
384 
385             // Clear Ids from the original course
386             CourseServiceUtils.resetIds(originalCourse);
387 
388             // Integrate changes into the original course. (should this just be just the id?)
389             courseAssembler.assemble(newVersionClu, originalCourse, true, contextInfo);
390 
391             // Clear dates since they need to be set anyway
392             originalCourse.setStartTerm(null);
393             originalCourse.setEndTerm(null);
394 
395             // Disassemble the new course
396             results = courseAssembler.disassemble(originalCourse, NodeOperation.UPDATE, contextInfo);
397 
398             // Use the results to make the appropriate service calls here
399             courseServiceMethodInvoker.invokeServiceCalls(results, contextInfo);
400 
401             // copy statements
402             CourseServiceUtils.copyStatements((String) currentVersion.getId(), results.getBusinessDTORef().getId(), results.getBusinessDTORef().getStateKey(), statementService, cluService, this, contextInfo);
403 
404             return results.getBusinessDTORef();
405 
406         } catch (AlreadyExistsException e) {
407             throw new OperationFailedException("Error creating new course version", e);
408         } catch (DependentObjectsExistException e) {
409             throw new OperationFailedException("Error creating new course version", e);
410         } catch (CircularRelationshipException e) {
411             throw new OperationFailedException("Error creating new course version", e);
412         } catch (UnsupportedActionException e) {
413             throw new OperationFailedException("Error creating new course version", e);
414         } catch (AssemblyException e) {
415             throw new OperationFailedException("Error creating new course version", e);
416         } catch (UnsupportedOperationException e) {
417             throw new OperationFailedException("Error creating new course version", e);
418         } catch (CircularReferenceException e) {
419             throw new OperationFailedException("Error creating new course version", e);
420         }
421 
422     }
423 
424     @Override
425     @Transactional(readOnly = false, noRollbackFor = {DoesNotExistException.class}, rollbackFor = {Throwable.class})
426     public StatusInfo setCurrentCourseVersion(String courseVersionId, Date currentVersionStart, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, IllegalVersionSequencingException, OperationFailedException, PermissionDeniedException, DataValidationErrorException {
427         return cluService.setCurrentCluVersion(courseVersionId, currentVersionStart, contextInfo);
428     }
429 
430     @Transactional(readOnly = true)
431     public VersionDisplayInfo getCurrentVersion(String refObjectTypeURI, String refObjectId, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
432         if (CourseServiceConstants.COURSE_NAMESPACE_URI.equals(refObjectTypeURI)) {
433             return cluService.getCurrentVersion(CluServiceConstants.CLU_NAMESPACE_URI, refObjectId, contextInfo);
434         }
435         throw new InvalidParameterException("Object type: " + refObjectTypeURI + " is not known to this implementation");
436     }
437 
438     @Transactional(readOnly = true)
439     public VersionDisplayInfo getCurrentVersionOnDate(String refObjectTypeURI, String refObjectId, Date date, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
440         if (CourseServiceConstants.COURSE_NAMESPACE_URI.equals(refObjectTypeURI)) {
441             return cluService.getCurrentVersionOnDate(CluServiceConstants.CLU_NAMESPACE_URI, refObjectId, date, contextInfo);
442         }
443         throw new InvalidParameterException("Object type: " + refObjectTypeURI + " is not known to this implementation");
444     }
445 
446     @Transactional(readOnly = true)
447     public VersionDisplayInfo getFirstVersion(String refObjectTypeURI, String refObjectId, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
448         if (CourseServiceConstants.COURSE_NAMESPACE_URI.equals(refObjectTypeURI)) {
449             return cluService.getFirstVersion(CluServiceConstants.CLU_NAMESPACE_URI, refObjectId, contextInfo);
450         }
451         throw new InvalidParameterException("Object type: " + refObjectTypeURI + " is not known to this implementation");
452 
453     }
454 
455     @Transactional(readOnly = true)
456     public VersionDisplayInfo getLatestVersion(String refObjectTypeURI, String refObjectId, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
457         if (CourseServiceConstants.COURSE_NAMESPACE_URI.equals(refObjectTypeURI)) {
458             return cluService.getLatestVersion(CluServiceConstants.CLU_NAMESPACE_URI, refObjectId, contextInfo);
459         }
460         throw new InvalidParameterException("Object type: " + refObjectTypeURI + " is not known to this implementation");
461 
462     }
463 
464     @Transactional(readOnly = true)
465     public VersionDisplayInfo getVersionBySequenceNumber(String refObjectTypeURI, String refObjectId, Long sequence, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
466         if (CourseServiceConstants.COURSE_NAMESPACE_URI.equals(refObjectTypeURI)) {
467             return cluService.getVersionBySequenceNumber(CluServiceConstants.CLU_NAMESPACE_URI, refObjectId, sequence, contextInfo);
468         }
469         throw new InvalidParameterException("Object type: " + refObjectTypeURI + " is not known to this implementation");
470     }
471 
472     @Transactional(readOnly = true)
473     public List<VersionDisplayInfo> getVersions(String refObjectTypeURI, String refObjectId, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
474         if (CourseServiceConstants.COURSE_NAMESPACE_URI.equals(refObjectTypeURI)) {
475             return cluService.getVersions(CluServiceConstants.CLU_NAMESPACE_URI, refObjectId, contextInfo);
476         }
477         throw new InvalidParameterException("Object type: " + refObjectTypeURI + " is not known to this implementation");
478     }
479 
480     @Transactional(readOnly = true)
481     public List<VersionDisplayInfo> getVersionsInDateRange(String refObjectTypeURI, String refObjectId, Date from, Date to, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
482         if (CourseServiceConstants.COURSE_NAMESPACE_URI.equals(refObjectTypeURI)) {
483             return cluService.getVersionsInDateRange(CluServiceConstants.CLU_NAMESPACE_URI, refObjectId, from, to, contextInfo);
484         }
485         throw new InvalidParameterException("Object type: " + refObjectTypeURI + " is not known to this implementation");
486     }
487 
488     /**
489      * Check for missing parameter and throw localized exception if missing
490      * 
491      * @param param
492      * @param paramName
493      * @throws MissingParameterException
494      */
495     private void checkForMissingParameter(Object param, String paramName) throws MissingParameterException {
496         if (param == null) {
497             throw new MissingParameterException(paramName + " can not be null");
498         }
499     }
500 
501     /**
502      * @param courseId
503      * @param statementTreeViewInfo
504      * @return reference exists
505      * @throws InvalidParameterException
506      * @throws MissingParameterException
507      * @throws OperationFailedException
508      * @throws DoesNotExistException
509      */
510     private RefStatementRelationInfo findStatementReference(String courseId, StatementTreeViewInfo statementTreeViewInfo, ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, DoesNotExistException {
511         List<RefStatementRelationInfo> course = R1R2ConverterUtil.convertLists(statementService.getRefStatementRelationsByRef(CourseAssemblerConstants.COURSE_TYPE, courseId), RefStatementRelationInfo.class);
512         if (course != null) {
513             for (RefStatementRelationInfo refRelation : course) {
514                 if (refRelation.getStatementId().equals(statementTreeViewInfo.getId())) {
515                     return refRelation;
516                 }
517             }
518         }
519         return null;
520     }
521 
522     @Override
523     public List<CourseInfo> getCoursesByIds(@WebParam(name = "courseIds") List<String> courseIds, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
524         // TODO KSCM-429
525         throw new UnsupportedOperationException("getCoursesByIds");
526         // To change body of implemented methods use File | Settings | File Templates.
527     }
528 
529     @Override
530     public List<String> searchForCourseIds(@WebParam(name = "criteria") QueryByCriteria criteria, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
531         // TODO KSCM-429
532         throw new UnsupportedOperationException("searchForCourseIds");
533         // To change body of implemented methods use File | Settings | File Templates.
534     }
535 
536     @Override
537     public List<CourseInfo> searchForCourses(@WebParam(name = "criteria") QueryByCriteria criteria, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
538         // TODO KSCM-429
539         throw new UnsupportedOperationException("searchForCourses");
540         // To change body of implemented methods use File | Settings | File Templates.
541     }
542 
543     // TODO KSCM-429 Service Method Comparison Implementation
544     @Override
545     public List<FormatInfo> getCourseFormatsByCourse(@WebParam(name = "courseId") String courseId, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
546         return this.getCourseFormats(courseId);
547     }
548 
549     // TODO KSCM-429 Service Method Comparison Implementation
550     @Override
551     public List<ActivityInfo> getCourseActivitiesByCourseFormat(@WebParam(name = "formatId") String formatId, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
552         return this.getCourseActivities(formatId);
553     }
554 
555     // TODO KSCM-429 replaced implementation with ENR
556     @Override
557     public List<LoDisplayInfo> getCourseLearningObjectivesByCourse(@WebParam(name = "courseId") String courseId, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
558         return this.getCourseLos(courseId);
559     }
560 
561 }