View Javadoc

1   package org.kuali.student.lum.program.service.impl;
2   
3   import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
4   
5   import java.util.ArrayList;
6   import java.util.Date;
7   import java.util.List;
8   
9   import org.apache.log4j.Logger;
10  import org.kuali.student.common.assembly.BaseDTOAssemblyNode;
11  import org.kuali.student.common.assembly.BusinessServiceMethodInvoker;
12  import org.kuali.student.common.assembly.BaseDTOAssemblyNode.NodeOperation;
13  import org.kuali.student.common.assembly.data.AssemblyException;
14  import org.kuali.student.common.dictionary.dto.DataType;
15  import org.kuali.student.common.dictionary.dto.ObjectStructureDefinition;
16  import org.kuali.student.common.dictionary.service.DictionaryService;
17  import org.kuali.student.common.dto.DtoConstants;
18  import org.kuali.student.common.dto.StatusInfo;
19  import org.kuali.student.common.exceptions.AlreadyExistsException;
20  import org.kuali.student.common.exceptions.CircularReferenceException;
21  import org.kuali.student.common.exceptions.CircularRelationshipException;
22  import org.kuali.student.common.exceptions.DataValidationErrorException;
23  import org.kuali.student.common.exceptions.DependentObjectsExistException;
24  import org.kuali.student.common.exceptions.DoesNotExistException;
25  import org.kuali.student.common.exceptions.IllegalVersionSequencingException;
26  import org.kuali.student.common.exceptions.InvalidParameterException;
27  import org.kuali.student.common.exceptions.MissingParameterException;
28  import org.kuali.student.common.exceptions.OperationFailedException;
29  import org.kuali.student.common.exceptions.PermissionDeniedException;
30  import org.kuali.student.common.exceptions.UnsupportedActionException;
31  import org.kuali.student.common.exceptions.VersionMismatchException;
32  import org.kuali.student.common.search.dto.SearchCriteriaTypeInfo;
33  import org.kuali.student.common.search.dto.SearchRequest;
34  import org.kuali.student.common.search.dto.SearchResult;
35  import org.kuali.student.common.search.dto.SearchResultTypeInfo;
36  import org.kuali.student.common.search.dto.SearchTypeInfo;
37  import org.kuali.student.common.search.service.SearchManager;
38  import org.kuali.student.common.validation.dto.ValidationResultInfo;
39  import org.kuali.student.common.validator.ServerDateParser;
40  import org.kuali.student.common.validator.Validator;
41  import org.kuali.student.common.validator.ValidatorFactory;
42  import org.kuali.student.common.validator.ValidatorUtils;
43  import org.kuali.student.common.versionmanagement.dto.VersionDisplayInfo;
44  import org.kuali.student.core.atp.dto.AtpInfo;
45  import org.kuali.student.core.atp.service.AtpService;
46  import org.kuali.student.core.document.dto.RefDocRelationInfo;
47  import org.kuali.student.core.document.service.DocumentService;
48  import org.kuali.student.core.statement.dto.ReqCompFieldInfo;
49  import org.kuali.student.core.statement.dto.ReqComponentInfo;
50  import org.kuali.student.core.statement.dto.StatementTreeViewInfo;
51  import org.kuali.student.lum.course.dto.LoDisplayInfo;
52  import org.kuali.student.lum.lu.dto.CluCluRelationInfo;
53  import org.kuali.student.lum.lu.dto.CluInfo;
54  import org.kuali.student.lum.lu.dto.CluSetInfo;
55  import org.kuali.student.lum.lu.dto.LuTypeInfo;
56  import org.kuali.student.lum.lu.service.LuService;
57  import org.kuali.student.lum.lu.service.LuServiceConstants;
58  import org.kuali.student.lum.program.dto.CoreProgramInfo;
59  import org.kuali.student.lum.program.dto.CredentialProgramInfo;
60  import org.kuali.student.lum.program.dto.HonorsProgramInfo;
61  import org.kuali.student.lum.program.dto.MajorDisciplineInfo;
62  import org.kuali.student.lum.program.dto.MinorDisciplineInfo;
63  import org.kuali.student.lum.program.dto.ProgramRequirementInfo;
64  import org.kuali.student.lum.program.dto.ProgramVariationInfo;
65  import org.kuali.student.lum.program.service.ProgramService;
66  import org.kuali.student.lum.program.service.ProgramServiceConstants;
67  import org.kuali.student.lum.program.service.assembler.CoreProgramAssembler;
68  import org.kuali.student.lum.program.service.assembler.CredentialProgramAssembler;
69  import org.kuali.student.lum.program.service.assembler.MajorDisciplineAssembler;
70  import org.kuali.student.lum.program.service.assembler.ProgramAssemblerConstants;
71  import org.kuali.student.lum.statement.typekey.ReqComponentFieldTypes;
72  import org.springframework.transaction.annotation.Transactional;
73  
74  @Transactional(readOnly=true,noRollbackFor={DoesNotExistException.class},rollbackFor={Throwable.class})
75  public class ProgramServiceImpl implements ProgramService {
76  	final static Logger LOG = Logger.getLogger(ProgramServiceImpl.class);
77  
78      private LuService luService;
79      private ValidatorFactory validatorFactory;
80      private BusinessServiceMethodInvoker programServiceMethodInvoker;
81      private DictionaryService dictionaryService;
82      private SearchManager searchManager;
83      private MajorDisciplineAssembler majorDisciplineAssembler;
84      private ProgramRequirementAssembler programRequirementAssembler;
85      private CredentialProgramAssembler credentialProgramAssembler;
86      private CoreProgramAssembler coreProgramAssembler;
87  //    private StatementService statementService;
88      private AtpService atpService;
89      private DocumentService documentService;
90      
91      
92      @Override
93      @Transactional(readOnly=false)
94  	public CredentialProgramInfo createCredentialProgram(
95              CredentialProgramInfo credentialProgramInfo)
96              throws AlreadyExistsException, DataValidationErrorException,
97              InvalidParameterException, MissingParameterException,
98              OperationFailedException, PermissionDeniedException {
99  
100         checkForMissingParameter(credentialProgramInfo, "CredentialProgramInfo");
101 
102         // Validate
103         List<ValidationResultInfo> validationResults = validateCredentialProgram("OBJECT", credentialProgramInfo);
104         if (null != validationResults && validationResults.size() > 0) {
105             throw new DataValidationErrorException("Validation error!", validationResults);
106         }
107 
108         try {
109             return processCredentialProgramInfo(credentialProgramInfo, NodeOperation.CREATE);
110         } catch (AssemblyException e) {
111             LOG.error("Error disassembling Credential Program", e);
112             throw new OperationFailedException("Error disassembling Credential Program");
113         }
114     }
115 
116     @Override
117     @Transactional(readOnly=false)
118 	public HonorsProgramInfo createHonorsProgram(
119             HonorsProgramInfo honorsProgramInfo) throws AlreadyExistsException,
120             DataValidationErrorException, InvalidParameterException,
121             MissingParameterException, OperationFailedException,
122             PermissionDeniedException {
123         // TODO Auto-generated method stub
124         return null;
125     }
126 
127     @Override
128     @Transactional(readOnly=false)
129 	public ProgramRequirementInfo createProgramRequirement(
130             ProgramRequirementInfo programRequirementInfo)
131             throws AlreadyExistsException, DataValidationErrorException,
132             InvalidParameterException, MissingParameterException,
133             OperationFailedException, PermissionDeniedException {
134         checkForMissingParameter(programRequirementInfo, "programRequirementInfo");
135 
136         // Validate
137         List<ValidationResultInfo> validationResults = validateProgramRequirement("OBJECT", programRequirementInfo);
138         if (isNotEmpty(validationResults)) {
139         	throw new DataValidationErrorException("Validation error!", validationResults);
140         }
141 
142         try {
143             return processProgramRequirement(programRequirementInfo, NodeOperation.CREATE);
144         } catch (AssemblyException e) {
145             LOG.error("Error disassembling Program Requirement", e);
146             throw new OperationFailedException("Error disassembling Program Requirement", e);
147         }
148     }
149 
150     @Override
151     @Transactional(readOnly=false)
152 	public MajorDisciplineInfo createMajorDiscipline(
153             MajorDisciplineInfo majorDisciplineInfo)
154             throws AlreadyExistsException, DataValidationErrorException,
155             InvalidParameterException, MissingParameterException,
156             OperationFailedException, PermissionDeniedException {
157 
158         checkForMissingParameter(majorDisciplineInfo, "MajorDisciplineInfo");
159 
160         // Validate
161         List<ValidationResultInfo> validationResults = validateMajorDiscipline("OBJECT", majorDisciplineInfo);
162         if (null != validationResults && validationResults.size() > 0) {
163             throw new DataValidationErrorException("Validation error!", validationResults);
164         }
165 
166         try {
167             return processMajorDisciplineInfo(majorDisciplineInfo, NodeOperation.CREATE);
168         } catch (AssemblyException e) {
169             LOG.error("Error creating Major Discipline", e);
170             throw new OperationFailedException("Error creating Major Discipline");
171         }
172     }
173     
174     @Override
175 	@Transactional(readOnly=false)
176 	public MajorDisciplineInfo createNewMajorDisciplineVersion(
177 			String majorDisciplineVerIndId, String versionComment)
178 			throws DoesNotExistException, InvalidParameterException,
179 			MissingParameterException, OperationFailedException,
180 			PermissionDeniedException, VersionMismatchException, DataValidationErrorException {
181 		//step one, get the original
182 		VersionDisplayInfo currentVersion = luService.getCurrentVersion(LuServiceConstants.CLU_NAMESPACE_URI, majorDisciplineVerIndId);
183 		MajorDisciplineInfo originalMajorDicipline = getMajorDiscipline(currentVersion.getId());
184 
185 		//Version the Clu
186 		CluInfo newVersionClu = luService.createNewCluVersion(majorDisciplineVerIndId, versionComment);
187 
188 		try {
189 	        BaseDTOAssemblyNode<MajorDisciplineInfo, CluInfo> results;
190 
191 	        //Integrate changes into the original. (should this just be just the id?)
192 			majorDisciplineAssembler.assemble(newVersionClu, originalMajorDicipline, true);
193 
194 			//Clear Ids from the original so it will make a copy and do other processing
195 			processCopy(originalMajorDicipline, currentVersion.getId());
196 
197 			//Disassemble the new
198 			results = majorDisciplineAssembler.disassemble(originalMajorDicipline, NodeOperation.UPDATE);
199 
200 			// Use the results to make the appropriate service calls here
201 			programServiceMethodInvoker.invokeServiceCalls(results);
202 
203 			return results.getBusinessDTORef();
204 		} catch(AssemblyException e) {
205 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
206 		} catch (AlreadyExistsException e) {
207 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
208 		} catch (DependentObjectsExistException e) {
209 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
210 		} catch (CircularRelationshipException e) {
211 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
212 		} catch (UnsupportedActionException e) {
213 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
214 		} catch (CircularReferenceException e) {
215 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
216 		}
217 	}
218     
219     
220 	/**
221 	 * Recurses through the statement tree and clears out ids so the tree can be copied.
222 	 * Also creates copies of clusets since they are single use
223 	 * 
224 	 * @param statementTreeView
225 	 * @throws OperationFailedException
226 	 */
227 	private void clearStatementTreeViewIdsRecursively(StatementTreeViewInfo statementTreeView) throws OperationFailedException{
228 		if(statementTreeView!=null){
229 			statementTreeView.setId(null);
230 			for(ReqComponentInfo reqComp:statementTreeView.getReqComponents()){
231 				reqComp.setId(null);
232 				for(ReqCompFieldInfo field:reqComp.getReqCompFields()){
233 					field.setId(null);
234 					//copy any clusets that are adhoc'd and set the field value to the new cluset
235 					if(ReqComponentFieldTypes.COURSE_CLUSET_KEY.getId().equals(field.getType())||
236 					   ReqComponentFieldTypes.PROGRAM_CLUSET_KEY.getId().equals(field.getType())||
237 					   ReqComponentFieldTypes.CLUSET_KEY.getId().equals(field.getType())){
238 						try {
239 							CluSetInfo cluSet = luService.getCluSetInfo(field.getValue());
240 							cluSet.setId(null);
241 							cluSet = luService.createCluSet(cluSet.getType(), cluSet);
242 							field.setValue(cluSet.getId());
243 						} catch (Exception e) {
244 							throw new OperationFailedException("Error copying clusets.", e);
245 						}
246 					}
247 					
248 				}
249 			}
250 			//Recurse through the children
251 			for(StatementTreeViewInfo child: statementTreeView.getStatements()){
252 				clearStatementTreeViewIdsRecursively(child);
253 			}
254 		}
255 	}
256 
257 	/**
258      * Clears out any ids so that a subsequent call to create will copy complex structures. 
259      * Also updates VersionInfo on variations to match VersionInfo on parent.
260      * 
261      * @param majorDiscipline
262 	 * @throws PermissionDeniedException 
263 	 * @throws OperationFailedException 
264 	 * @throws MissingParameterException 
265 	 * @throws InvalidParameterException 
266 	 * @throws DoesNotExistException 
267 	 * @throws DataValidationErrorException 
268 	 * @throws AlreadyExistsException 
269 	 * @throws VersionMismatchException 
270 	 * @throws CircularRelationshipException 
271      */
272     private void processCopy(MajorDisciplineInfo majorDiscipline,String originalId) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException, AlreadyExistsException, DataValidationErrorException, VersionMismatchException, CircularRelationshipException {
273 		//Clear Los
274 		for(LoDisplayInfo lo:majorDiscipline.getLearningObjectives()){
275 			resetLoRecursively(lo);
276 		}
277 		//Clear OrgCoreProgram
278 		if(majorDiscipline.getOrgCoreProgram()!=null){
279 			majorDiscipline.getOrgCoreProgram().setId(null);
280 		
281 			if(majorDiscipline.getOrgCoreProgram().getLearningObjectives()!=null){
282 				for(LoDisplayInfo lo:majorDiscipline.getOrgCoreProgram().getLearningObjectives()){
283 					resetLoRecursively(lo);
284 				}
285 			}
286 		}
287 		//Clear Variations
288 		for(ProgramVariationInfo variation:majorDiscipline.getVariations()){
289 			//Create new variation version
290 			String variationVersionIndId = variation.getVersionInfo().getVersionIndId();
291 			CluInfo newVariationClu = luService.createNewCluVersion(variationVersionIndId, "Variation version for MajorDiscipline version " + majorDiscipline.getVersionInfo().getSequenceNumber());	
292 			
293 			//Create relation b/w new major discipline and new variation
294 			CluCluRelationInfo relation = new CluCluRelationInfo();
295 	        relation.setCluId(majorDiscipline.getId());
296 	        relation.setRelatedCluId(newVariationClu.getId());
297 	        relation.setType(ProgramAssemblerConstants.HAS_PROGRAM_VARIATION);
298 	        relation.setState(DtoConstants.STATE_ACTIVE);
299 			luService.createCluCluRelation(relation.getCluId(), relation.getRelatedCluId(), relation.getType(), relation);
300 	        
301 			//Set variation id & versionInfo to new variation clu
302 			variation.setId(newVariationClu.getId());
303 			variation.setMetaInfo(newVariationClu.getMetaInfo());
304 						
305 			//Set state to parent program's state
306 			variation.setState(majorDiscipline.getState());
307 			//Clear Los
308 			for(LoDisplayInfo lo:variation.getLearningObjectives()){
309 				resetLoRecursively(lo);
310 			}
311 			//Copy Requirements for variation
312 			copyProgramRequirements(variation.getProgramRequirements(),majorDiscipline.getState());
313 		}
314 		
315 		//Copy requirements for majorDicipline
316 		copyProgramRequirements(majorDiscipline.getProgramRequirements(),majorDiscipline.getState());
317 
318 		//Copy documents(create new relations to the new version)
319 		List<RefDocRelationInfo> docRelations = documentService.getRefDocRelationsByRef("kuali.org.RefObjectType.ProposalInfo", originalId);
320 		if(docRelations!=null){
321 			for(RefDocRelationInfo docRelation:docRelations){
322 				docRelation.setId(null);
323 				docRelation.setRefObjectId(majorDiscipline.getId());
324 				documentService.createRefDocRelation("kuali.org.RefObjectType.ProposalInfo", majorDiscipline.getId(), docRelation.getDocumentId(), docRelation.getType(), docRelation);
325 			}
326 		}
327 	}
328 
329 	private void processCopy(CredentialProgramInfo originaCredentialProgram,
330 			String originalId) throws OperationFailedException, AlreadyExistsException, DataValidationErrorException, InvalidParameterException, MissingParameterException, PermissionDeniedException, DoesNotExistException {
331 		//Clear Los
332 		if (originaCredentialProgram.getLearningObjectives() != null){
333 			for(LoDisplayInfo lo:originaCredentialProgram.getLearningObjectives()){
334 				resetLoRecursively(lo);
335 			}
336 		}
337 
338 		//Copy requirements for majorDicipline
339 		copyProgramRequirements(originaCredentialProgram.getProgramRequirements(),originaCredentialProgram.getState());
340 
341 		//Copy documents(create new relations to the new version)
342 		List<RefDocRelationInfo> docRelations = documentService.getRefDocRelationsByRef("kuali.org.RefObjectType.ProposalInfo", originalId);
343 		if(docRelations!=null){
344 			for(RefDocRelationInfo docRelation:docRelations){
345 				docRelation.setId(null);
346 				docRelation.setRefObjectId(originaCredentialProgram.getId());
347 				documentService.createRefDocRelation("kuali.org.RefObjectType.ProposalInfo", originaCredentialProgram.getId(), docRelation.getDocumentId(), docRelation.getType(), docRelation);
348 			}
349 		}
350 	}
351     
352     private void processCopy(CoreProgramInfo originalCoreProgram, String originalId) throws OperationFailedException, AlreadyExistsException, DataValidationErrorException, InvalidParameterException, MissingParameterException, PermissionDeniedException, DoesNotExistException {
353 		//Clear Los
354 		for(LoDisplayInfo lo:originalCoreProgram.getLearningObjectives()){
355 			resetLoRecursively(lo);
356 		}
357 		//Copy requirements for majorDicipline
358 		copyProgramRequirements(originalCoreProgram.getProgramRequirements(),originalCoreProgram.getState());
359 
360 		//Copy documents(create new relations to the new version)
361 		List<RefDocRelationInfo> docRelations = documentService.getRefDocRelationsByRef("kuali.org.RefObjectType.ProposalInfo", originalId);
362 		if(docRelations!=null){
363 			for(RefDocRelationInfo docRelation:docRelations){
364 				docRelation.setId(null);
365 				docRelation.setRefObjectId(originalCoreProgram.getId());
366 				documentService.createRefDocRelation("kuali.org.RefObjectType.ProposalInfo", originalCoreProgram.getId(), docRelation.getDocumentId(), docRelation.getType(), docRelation);
367 			}
368 		}
369 	}
370     
371     /**
372      * Copy requirements (these exist external to the program save process and are referenced by id)
373      * @param originalProgramRequirementIds
374      * @param state
375      * @throws OperationFailedException
376      * @throws AlreadyExistsException
377      * @throws DataValidationErrorException
378      * @throws InvalidParameterException
379      * @throws MissingParameterException
380      * @throws PermissionDeniedException
381      * @throws DoesNotExistException
382      */
383     private void copyProgramRequirements(List<String> originalProgramRequirementIds,String state) throws OperationFailedException, AlreadyExistsException, DataValidationErrorException, InvalidParameterException, MissingParameterException, PermissionDeniedException, DoesNotExistException{
384 		//Pull out the current requirement ids to be replaced by the ids of the new copies 
385 		List<String> programRequirementIds = new ArrayList<String>(originalProgramRequirementIds);
386 		originalProgramRequirementIds.clear();
387 		
388 		for(String programRequirementId:programRequirementIds){
389 			//Grab the original 
390 			ProgramRequirementInfo programRequirementInfo = getProgramRequirement(programRequirementId, null, null);
391 			//Clear the id
392 			programRequirementInfo.setId(null);
393 			
394 			programRequirementInfo.setState(state);
395 			//Clear statement tree ids
396 			clearStatementTreeViewIdsRecursively(programRequirementInfo.getStatement());
397 			//Clear learning objectives
398 			for(LoDisplayInfo lo:programRequirementInfo.getLearningObjectives()){
399 				resetLoRecursively(lo);
400 			}
401 			//Create the new copy
402 			ProgramRequirementInfo createdProgramRequirement = createProgramRequirement(programRequirementInfo);
403 			//add the copy's id back to the majorDicipline's list of requirements
404 			originalProgramRequirementIds.add(createdProgramRequirement.getId());
405 		}
406     }
407     
408 	/**
409 	 * Recursively clears out the ids in a Lo and in its child Los
410 	 * @param lo
411 	 */
412 	private void resetLoRecursively(LoDisplayInfo lo){
413 		lo.getLoInfo().setId(null);
414 		for(LoDisplayInfo nestedLo:lo.getLoDisplayInfoList()){
415 			resetLoRecursively(nestedLo);
416 		}
417 	}
418 
419 	@Override
420 	@Transactional(readOnly=false)
421 	public StatusInfo setCurrentMajorDisciplineVersion(
422 			String majorDisciplineId, Date currentVersionStart)
423 			throws DoesNotExistException, InvalidParameterException,
424 			MissingParameterException, IllegalVersionSequencingException,
425 			OperationFailedException, PermissionDeniedException {
426 		StatusInfo status = luService.setCurrentCluVersion(majorDisciplineId, currentVersionStart);
427 		
428 		//Update the variations to be current as well
429 		List<ProgramVariationInfo> variationList = getVariationsByMajorDisciplineId(majorDisciplineId);
430 		for (ProgramVariationInfo variationInfo:variationList){
431 			String variationId = variationInfo.getId();
432 			//If null set to current (non-null value means version is first and is already current)
433 			if (variationInfo.getVersionInfo().getCurrentVersionStart() == null){
434 				luService.setCurrentCluVersion(variationId, currentVersionStart);
435 			}
436 		}
437 		
438 		return status;
439 	}
440 
441 	@Override
442     @Transactional(readOnly=false)
443 	public MinorDisciplineInfo createMinorDiscipline(
444             MinorDisciplineInfo minorDisciplineInfo)
445             throws AlreadyExistsException, DataValidationErrorException,
446             InvalidParameterException, MissingParameterException,
447             OperationFailedException, PermissionDeniedException {
448         // TODO Auto-generated method stub
449         return null;
450     }
451 
452     @Override
453     @Transactional(readOnly=false)
454 	public StatusInfo deleteCredentialProgram(String credentialProgramId)
455             throws DoesNotExistException, InvalidParameterException,
456             MissingParameterException, OperationFailedException,
457             PermissionDeniedException {
458 
459 //        try {
460 //        	CredentialProgramInfo credentialProgram = getCredentialProgram(credentialProgramId);
461 //
462 //            processCredentialProgramInfo(credentialProgram, NodeOperation.DELETE);
463 //
464 //            return getStatus();
465 //
466 //        } catch (AssemblyException e) {
467 //            LOG.error("Error disassembling CredentialProgram", e);
468 //            throw new OperationFailedException("Error disassembling CredentialProgram");
469 //        }
470     	throw new OperationFailedException("Deletion of CredentialProgram is not supported."); 
471     }
472 
473     @Override
474     @Transactional(readOnly=false)
475 	public StatusInfo deleteHonorsProgram(String honorsProgramId)
476             throws DoesNotExistException, InvalidParameterException,
477             MissingParameterException, OperationFailedException,
478             PermissionDeniedException {
479         // TODO Auto-generated method stub
480         return null;
481     }
482 
483     @Override
484     @Transactional(readOnly=false)
485 	public StatusInfo deleteMajorDiscipline(String majorDisciplineId)
486             throws DoesNotExistException, InvalidParameterException,
487             MissingParameterException, OperationFailedException,
488             PermissionDeniedException {
489 
490         try {
491             MajorDisciplineInfo majorDiscipline = getMajorDiscipline(majorDisciplineId);
492 
493             processMajorDisciplineInfo(majorDiscipline, NodeOperation.DELETE);
494 
495             return getStatus();
496 
497         } catch (AssemblyException e) {
498             LOG.error("Error disassembling MajorDiscipline", e);
499             throw new OperationFailedException("Error disassembling MajorDiscipline");
500         }
501     }
502 
503     @Override
504     @Transactional(readOnly=false)
505 	public StatusInfo deleteMinorDiscipline(String minorDisciplineId)
506             throws DoesNotExistException, InvalidParameterException,
507             MissingParameterException, OperationFailedException,
508             PermissionDeniedException {
509         // TODO Auto-generated method stub
510         return null;
511     }
512 
513     @Override
514     @Transactional(readOnly=false)
515 	public StatusInfo deleteProgramRequirement(String programRequirementId)
516             throws DoesNotExistException, InvalidParameterException,
517             MissingParameterException, OperationFailedException,
518             PermissionDeniedException {
519     	checkForMissingParameter(programRequirementId, "programRequirementId");
520         try {
521         	ProgramRequirementInfo programRequirement = getProgramRequirement(programRequirementId, null, null);
522 
523         	processProgramRequirement(programRequirement, NodeOperation.DELETE);
524 
525             return getStatus();
526 
527         } catch (AssemblyException e) {
528             LOG.error("Error disassembling MajorDiscipline", e);
529             throw new OperationFailedException("Error disassembling ProgramRequirement", e);
530         }
531 
532     }
533 
534     @Override
535     public CredentialProgramInfo getCredentialProgram(String credentialProgramId)
536             throws DoesNotExistException, InvalidParameterException,
537             MissingParameterException, OperationFailedException,
538             PermissionDeniedException {
539 
540     	CredentialProgramInfo credentialProgramInfo = null;
541 
542         try {
543             CluInfo clu = luService.getClu(credentialProgramId);
544 
545             if ( ! ProgramAssemblerConstants.CREDENTIAL_PROGRAM_TYPES.contains(clu.getType()) ) {
546                 throw new DoesNotExistException("Specified CLU is not a Credential Program");
547             }
548 
549             credentialProgramInfo = credentialProgramAssembler.assemble(clu, null, false);
550         } catch (AssemblyException e) {
551             LOG.error("Error assembling CredentialProgram", e);
552             throw new OperationFailedException("Error assembling CredentialProgram");
553         }
554         return credentialProgramInfo;
555 
556 		// comment out the above, and uncomment below to get auto-generated data
557         // (and vice-versa)
558 //		try {
559 //			return new CredentialProgramDataGenerator(ProgramAssemblerConstants.BACCALAUREATE_PROGRAM).getCPTestData();
560 //		} catch (Exception e) {
561 //			return null;
562 //		}
563     }
564 
565     @Override
566     public LuTypeInfo getCredentialProgramType(String credentialProgramTypeKey)
567             throws DoesNotExistException, InvalidParameterException,
568             MissingParameterException, OperationFailedException {
569         // TODO Auto-generated method stub
570         return null;
571     }
572 
573     @Override
574     public List<LuTypeInfo> getCredentialProgramTypes()
575             throws OperationFailedException {
576         // TODO Auto-generated method stub
577         return null;
578     }
579 
580     @Override
581     public List<String> getHonorsByCredentialProgramType(String programType)
582             throws DoesNotExistException, InvalidParameterException,
583             MissingParameterException, OperationFailedException {
584         // TODO Auto-generated method stub
585         return null;
586     }
587 
588     @Override
589     public HonorsProgramInfo getHonorsProgram(String honorsProgramId)
590             throws DoesNotExistException, InvalidParameterException,
591             MissingParameterException, OperationFailedException,
592             PermissionDeniedException {
593         // TODO Auto-generated method stub
594         return null;
595     }
596 
597     @Override
598     public MajorDisciplineInfo getMajorDiscipline(String majorDisciplineId)
599             throws DoesNotExistException, InvalidParameterException,
600             MissingParameterException, OperationFailedException,
601             PermissionDeniedException {
602 
603 
604         MajorDisciplineInfo majorDiscipline = null;
605 
606         try {
607             CluInfo clu = luService.getClu(majorDisciplineId);
608             if ( ! ProgramAssemblerConstants.MAJOR_DISCIPLINE.equals(clu.getType()) ) {
609                 throw new DoesNotExistException("Specified CLU is not a Major Discipline");
610             }
611             majorDiscipline = majorDisciplineAssembler.assemble(clu, null, false);
612         } catch (AssemblyException e) {
613             LOG.error("Error assembling MajorDiscipline", e);
614             throw new OperationFailedException("Error assembling MajorDiscipline");
615         }
616         return majorDiscipline;
617 		// comment out the above, and uncomment below to get auto-generated data
618         // (and vice-versa)
619 //		try {
620 //			return new MajorDisciplineDataGenerator().getMajorDisciplineInfoTestData();
621 //		} catch (Exception e) {
622 //			return null;
623 //		}
624 	}
625 
626 	@Override
627 	public List<String> getMajorIdsByCredentialProgramType(String programType)
628 			throws DoesNotExistException, InvalidParameterException,
629 			MissingParameterException, OperationFailedException {
630 		// TODO Auto-generated method stub
631 		return null;
632 	}
633 
634 	@Override
635 	public MinorDisciplineInfo getMinorDiscipline(String minorDisciplineId)
636 			throws DoesNotExistException, InvalidParameterException,
637 			MissingParameterException, OperationFailedException,
638 			PermissionDeniedException {
639 		// TODO Auto-generated method stub
640 		return null;
641 	}
642 
643 	@Override
644 	public List<String> getMinorsByCredentialProgramType(String programType)
645 			throws DoesNotExistException, InvalidParameterException,
646 			MissingParameterException, OperationFailedException {
647 		// TODO Auto-generated method stub
648 		return null;
649 	}
650 
651 	@Override
652 	public ProgramRequirementInfo getProgramRequirement(String programRequirementId, String nlUsageTypeKey, String language) throws DoesNotExistException,
653 			InvalidParameterException, MissingParameterException,
654 			OperationFailedException, PermissionDeniedException {
655 
656 		checkForMissingParameter(programRequirementId, "programRequirementId");
657 
658 		CluInfo clu = luService.getClu(programRequirementId);
659 		if (!ProgramAssemblerConstants.PROGRAM_REQUIREMENT.equals(clu.getType())) {
660 			throw new DoesNotExistException("Specified CLU is not a Program Requirement");
661 		}
662 		try {
663 			ProgramRequirementInfo progReqInfo = programRequirementAssembler.assemble(clu, null, false);
664 			StatementTreeViewInfo statement = progReqInfo.getStatement();
665 //			if (nlUsageTypeKey != null && language != null) {
666 //				statement.setNaturalLanguageTranslation(statementService.getNaturalLanguageForStatement(statement.getId(), nlUsageTypeKey, language));
667 //			}
668 			return progReqInfo;
669 		} catch (AssemblyException e) {
670             LOG.error("Error assembling program requirement", e);
671             throw new OperationFailedException("Error assembling program requirement: " + e.getMessage(), e);
672 		}
673 	}
674 
675 	@Override
676 	public List<ProgramVariationInfo> getVariationsByMajorDisciplineId(
677 			String majorDisciplineId) throws DoesNotExistException,
678 			InvalidParameterException, MissingParameterException,
679 			OperationFailedException {
680     	List<ProgramVariationInfo> pvInfos = new ArrayList<ProgramVariationInfo>();
681 
682     	try {
683     			List<CluInfo> clus = luService.getRelatedClusByCluId(majorDisciplineId, ProgramAssemblerConstants.HAS_PROGRAM_VARIATION);
684 
685 		        if(clus != null && clus.size() > 0){
686 		        	for(CluInfo clu : clus){
687 		        		ProgramVariationInfo pvInfo = majorDisciplineAssembler.getProgramVariationAssembler().assemble(clu, null, false);
688 		        		if(pvInfo != null){
689 		        			pvInfos.add(pvInfo);
690 		        		}
691 		        	}
692 		        }
693 		    } catch (AssemblyException e) {
694 		        LOG.error("Error assembling ProgramVariation", e);
695 		        throw new OperationFailedException("Error assembling ProgramVariation");
696 		    }
697 
698         return pvInfos;
699     }
700 
701     @Override
702     @Transactional(readOnly=false)
703 	public CredentialProgramInfo updateCredentialProgram(
704             CredentialProgramInfo credentialProgramInfo)
705             throws DataValidationErrorException, DoesNotExistException,
706             InvalidParameterException, MissingParameterException,
707             VersionMismatchException, OperationFailedException,
708             PermissionDeniedException {
709 
710         checkForMissingParameter(credentialProgramInfo, "CredentialProgramInfo");
711 
712         // Validate
713         List<ValidationResultInfo> validationResults = validateCredentialProgram("OBJECT", credentialProgramInfo);
714         if (null != validationResults && validationResults.size() > 0) {
715             throw new DataValidationErrorException("Validation error!", validationResults);
716         }
717 
718         try {
719 
720             return processCredentialProgramInfo(credentialProgramInfo, NodeOperation.UPDATE);
721 
722         } catch (AssemblyException e) {
723             LOG.error("Error disassembling Credential Program", e);
724             throw new OperationFailedException("Error disassembling Credential Program");
725         }
726     }
727 
728     @Override
729     @Transactional(readOnly=false)
730 	public HonorsProgramInfo updateHonorsProgram(
731             HonorsProgramInfo honorsProgramInfo)
732             throws DataValidationErrorException, DoesNotExistException,
733             InvalidParameterException, MissingParameterException,
734             VersionMismatchException, OperationFailedException,
735             PermissionDeniedException {
736         // TODO Auto-generated method stub
737         return null;
738     }
739 
740     @Override
741     @Transactional(readOnly=false)
742 	public MajorDisciplineInfo updateMajorDiscipline(
743             MajorDisciplineInfo majorDisciplineInfo)
744             throws DataValidationErrorException, DoesNotExistException,
745             InvalidParameterException, MissingParameterException,
746             VersionMismatchException, OperationFailedException,
747             PermissionDeniedException {
748 
749         checkForMissingParameter(majorDisciplineInfo, "MajorDisciplineInfo");
750 
751         // Validate
752         List<ValidationResultInfo> validationResults = validateMajorDiscipline("OBJECT", majorDisciplineInfo);
753         if (null != validationResults && validationResults.size() > 0) {
754             throw new DataValidationErrorException("Validation error!", validationResults);
755         }
756 
757         try {
758 
759             return processMajorDisciplineInfo(majorDisciplineInfo, NodeOperation.UPDATE);
760 
761         } catch (AssemblyException e) {
762             LOG.error("Error disassembling majorDiscipline", e);
763             throw new OperationFailedException("Error disassembling majorDiscipline");
764         }
765     }
766 
767     @Override
768     @Transactional(readOnly=false)
769 	public MinorDisciplineInfo updateMinorDiscipline(
770             MinorDisciplineInfo minorDisciplineInfo)
771             throws DataValidationErrorException, DoesNotExistException,
772             InvalidParameterException, MissingParameterException,
773             VersionMismatchException, OperationFailedException,
774             PermissionDeniedException {
775         // TODO Auto-generated method stub
776         return null;
777     }
778 
779     @Override
780     @Transactional(readOnly=false)
781 	public ProgramRequirementInfo updateProgramRequirement(
782             ProgramRequirementInfo programRequirementInfo)
783             throws DataValidationErrorException, DoesNotExistException,
784             InvalidParameterException, MissingParameterException,
785             VersionMismatchException, OperationFailedException,
786             PermissionDeniedException {
787     	checkForMissingParameter(programRequirementInfo, "programRequirementInfo");
788         // Validate
789         List<ValidationResultInfo> validationResults = validateProgramRequirement("OBJECT", programRequirementInfo);
790         if (isNotEmpty(validationResults)) {
791         	throw new DataValidationErrorException("Validation error!", validationResults);
792         }
793 
794         try {
795 			return processProgramRequirement(programRequirementInfo, NodeOperation.UPDATE);
796 		} catch (AssemblyException e) {
797 			throw new OperationFailedException("Unable to update ProgramRequirement", e);
798 		}
799     }
800 
801     @Override
802     public List<ValidationResultInfo> validateCredentialProgram(
803             String validationType, CredentialProgramInfo credentialProgramInfo)
804             throws InvalidParameterException,
805             MissingParameterException, OperationFailedException {
806 
807         List<ValidationResultInfo> validationResults = new ArrayList<ValidationResultInfo>();
808 //        if ( ! ProgramAssemblerConstants.DRAFT.equals(credentialProgramInfo.getState()) ) {
809             ObjectStructureDefinition objStructure = this.getObjectStructure(CredentialProgramInfo.class.getName());
810             Validator validator = validatorFactory.getValidator();
811             validationResults.addAll(validator.validateObject(credentialProgramInfo, objStructure));
812 //        }
813 
814         return validationResults;
815     }
816 
817     @Override
818     public List<ValidationResultInfo> validateHonorsProgram(
819             String validationType, HonorsProgramInfo honorsProgramInfo)
820             throws InvalidParameterException,
821             MissingParameterException, OperationFailedException {
822         // TODO Auto-generated method stub
823         return null;
824     }
825 
826     @Override
827     public List<ValidationResultInfo> validateMajorDiscipline(
828             String validationType, MajorDisciplineInfo majorDisciplineInfo)
829             throws InvalidParameterException,
830             MissingParameterException, OperationFailedException {
831 
832         List<ValidationResultInfo> validationResults = new ArrayList<ValidationResultInfo>();
833 //        if ( ! ProgramAssemblerConstants.DRAFT.equalsIgnoreCase(majorDisciplineInfo.getState()) ) {
834             ObjectStructureDefinition objStructure = this.getObjectStructure(MajorDisciplineInfo.class.getName());
835             Validator validator = validatorFactory.getValidator();
836             validationResults.addAll(validator.validateObject(majorDisciplineInfo, objStructure));
837 //        }
838         validateMajorDisciplineAtps(majorDisciplineInfo,validationResults);
839         return validationResults;
840     }
841 
842     @Override
843     public List<ValidationResultInfo> validateMinorDiscipline(
844             String validationType, MinorDisciplineInfo minorDisciplineInfo)
845             throws InvalidParameterException,
846             MissingParameterException, OperationFailedException {
847         // TODO Auto-generated method stub
848         return null;
849     }
850 
851     @Override
852     public List<ValidationResultInfo> validateProgramRequirement(
853             String validationType, ProgramRequirementInfo programRequirementInfo)
854             throws InvalidParameterException,
855             MissingParameterException, OperationFailedException {
856 
857         ObjectStructureDefinition objStructure = this.getObjectStructure(ProgramRequirementInfo.class.getName());
858         Validator validator = validatorFactory.getValidator();
859         List<ValidationResultInfo> validationResults = validator.validateObject(programRequirementInfo, objStructure);
860 
861         return validationResults;
862     }
863 
864     @Override
865     public ObjectStructureDefinition getObjectStructure(String objectTypeKey) {
866         return dictionaryService.getObjectStructure(objectTypeKey);
867     }
868 
869     @Override
870     public List<String> getObjectTypes() {
871         return dictionaryService.getObjectTypes();
872     }
873 
874     @Override
875     public SearchCriteriaTypeInfo getSearchCriteriaType(
876             String searchCriteriaTypeKey) throws DoesNotExistException,
877             InvalidParameterException, MissingParameterException,
878             OperationFailedException {
879         // TODO Auto-generated method stub
880         return null;
881     }
882 
883     @Override
884     public List<SearchCriteriaTypeInfo> getSearchCriteriaTypes()
885             throws OperationFailedException {
886         // TODO Auto-generated method stub
887         return null;
888     }
889 
890     @Override
891     public SearchResultTypeInfo getSearchResultType(String searchResultTypeKey)
892             throws DoesNotExistException, InvalidParameterException,
893             MissingParameterException, OperationFailedException {
894         // TODO Auto-generated method stub
895         return null;
896     }
897 
898     @Override
899     public List<SearchResultTypeInfo> getSearchResultTypes()
900             throws OperationFailedException {
901         // TODO Auto-generated method stub
902         return null;
903     }
904 
905     @Override
906     public SearchTypeInfo getSearchType(String searchTypeKey)
907             throws DoesNotExistException, InvalidParameterException,
908             MissingParameterException, OperationFailedException {
909         // TODO Auto-generated method stub
910         return null;
911     }
912 
913     @Override
914     public List<SearchTypeInfo> getSearchTypes()
915             throws OperationFailedException {
916         // TODO Auto-generated method stub
917         return null;
918     }
919 
920     @Override
921     public List<SearchTypeInfo> getSearchTypesByCriteria(
922             String searchCriteriaTypeKey) throws DoesNotExistException,
923             InvalidParameterException, MissingParameterException,
924             OperationFailedException {
925         // TODO Auto-generated method stub
926         return null;
927     }
928 
929     @Override
930     public List<SearchTypeInfo> getSearchTypesByResult(
931             String searchResultTypeKey) throws DoesNotExistException,
932             InvalidParameterException, MissingParameterException,
933             OperationFailedException {
934         // TODO Auto-generated method stub
935         return null;
936     }
937 
938     @Override
939     public SearchResult search(SearchRequest searchRequest)
940             throws MissingParameterException {
941         // TODO Auto-generated method stub
942         return null;
943     }
944 
945     /**
946      * Check for missing parameter and throw localized exception if missing
947      *
948      * @param param
949      * @param parameter name
950      * @throws MissingParameterException
951      */
952     private void checkForMissingParameter(Object param, String paramName)
953             throws MissingParameterException {
954         if (param == null) {
955             throw new MissingParameterException(paramName + " can not be null");
956         }
957     }
958 
959     // TODO - when CRUD for a second ProgramInfo is implemented, pull common code up from its process*() and this
960 
961     private MajorDisciplineInfo processMajorDisciplineInfo(MajorDisciplineInfo majorDisciplineInfo, NodeOperation operation) throws AssemblyException {
962 
963         BaseDTOAssemblyNode<MajorDisciplineInfo, CluInfo> results = majorDisciplineAssembler.disassemble(majorDisciplineInfo, operation);
964         invokeServiceCalls(results);
965         return results.getBusinessDTORef();
966     }
967 
968     private CredentialProgramInfo processCredentialProgramInfo(CredentialProgramInfo credentialProgramInfo, NodeOperation operation) throws AssemblyException {
969 
970         BaseDTOAssemblyNode<CredentialProgramInfo, CluInfo> results = credentialProgramAssembler.disassemble(credentialProgramInfo, operation);
971         invokeServiceCalls(results);
972         return results.getBusinessDTORef();
973     }
974 
975     private ProgramRequirementInfo processProgramRequirement(ProgramRequirementInfo programRequirementInfo, NodeOperation operation) throws AssemblyException {
976         BaseDTOAssemblyNode<ProgramRequirementInfo, CluInfo> results = programRequirementAssembler.disassemble(programRequirementInfo, operation);
977         invokeServiceCalls(results);
978         return results.getBusinessDTORef();
979     }
980 
981 	private void invokeServiceCalls(BaseDTOAssemblyNode<?, CluInfo> results) throws AssemblyException{
982         // Use the results to make the appropriate service calls here
983         try {
984             programServiceMethodInvoker.invokeServiceCalls(results);
985         } catch (AssemblyException e) {
986         	throw e;
987         } catch (Exception e) {
988             throw new AssemblyException(e);
989         }
990     }
991 
992     //Spring setters. Used by spring container to inject corresponding dependencies.
993 
994     public void setLuService(LuService luService) {
995         this.luService = luService;
996     }
997 
998     public LuService getLuService() {
999 		return luService;
1000 	}
1001 
1002 	public void setDictionaryService(DictionaryService dictionaryService) {
1003         this.dictionaryService = dictionaryService;
1004     }
1005 
1006     public DictionaryService getDictionaryService() {
1007 		return dictionaryService;
1008 	}
1009 
1010     public void setSearchManager(SearchManager searchManager) {
1011         this.searchManager = searchManager;
1012     }
1013     
1014 	public SearchManager getSearchManager() {
1015 		return searchManager;
1016 	}
1017 
1018 	public void setMajorDisciplineAssembler(MajorDisciplineAssembler majorDisciplineAssembler) {
1019         this.majorDisciplineAssembler = majorDisciplineAssembler;
1020     }
1021 
1022 	public MajorDisciplineAssembler getMajorDisciplineAssembler() {
1023 		return majorDisciplineAssembler;
1024 	}
1025 
1026 	public void setCredentialProgramAssembler(
1027 			CredentialProgramAssembler credentialProgramAssembler) {
1028 		this.credentialProgramAssembler = credentialProgramAssembler;
1029 	}
1030 
1031 	public CredentialProgramAssembler getCredentialProgramAssembler() {
1032 		return credentialProgramAssembler;
1033 	}
1034 
1035 	public void setProgramRequirementAssembler(ProgramRequirementAssembler programRequirementAssembler) {
1036         this.programRequirementAssembler = programRequirementAssembler;
1037     }
1038 
1039     public ProgramRequirementAssembler getProgramRequirementAssembler() {
1040 		return programRequirementAssembler;
1041 	}
1042 
1043 	public void setProgramServiceMethodInvoker(BusinessServiceMethodInvoker serviceMethodInvoker) {
1044         this.programServiceMethodInvoker = serviceMethodInvoker;
1045     }
1046 
1047     public BusinessServiceMethodInvoker getProgramServiceMethodInvoker() {
1048 		return programServiceMethodInvoker;
1049 	}
1050 
1051 	public void setValidatorFactory(ValidatorFactory validatorFactory) {
1052         this.validatorFactory = validatorFactory;
1053     }
1054 
1055 	public ValidatorFactory getValidatorFactory() {
1056 		return validatorFactory;
1057 	}
1058 	
1059 	public void setCoreProgramAssembler(CoreProgramAssembler coreProgramAssembler) {
1060 		this.coreProgramAssembler = coreProgramAssembler;
1061 	}
1062 
1063 	public CoreProgramAssembler getCoreProgramAssembler() {
1064 		return coreProgramAssembler;
1065 	}
1066 
1067 	private StatusInfo getStatus(){
1068         StatusInfo status = new StatusInfo();
1069         status.setSuccess(true);
1070         return status;
1071 	}
1072 
1073     private CoreProgramInfo processCoreProgramInfo(CoreProgramInfo coreProgramInfo, NodeOperation operation) throws AssemblyException {
1074 
1075         BaseDTOAssemblyNode<CoreProgramInfo, CluInfo> results = coreProgramAssembler.disassemble(coreProgramInfo, operation);
1076         invokeServiceCalls(results);
1077         return results.getBusinessDTORef();
1078     }
1079 
1080     @Override
1081     @Transactional(readOnly=false)
1082 	public CoreProgramInfo createCoreProgram(CoreProgramInfo coreProgramInfo) throws AlreadyExistsException, DataValidationErrorException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
1083         checkForMissingParameter(coreProgramInfo, "CoreProgramInfo");
1084         
1085         // Validate
1086         List<ValidationResultInfo> validationResults = validateCoreProgram("OBJECT", coreProgramInfo);
1087         if (null != validationResults && validationResults.size() > 0) {
1088             throw new DataValidationErrorException("Validation error!", validationResults);
1089         }
1090 
1091         try {
1092             return processCoreProgramInfo(coreProgramInfo, NodeOperation.CREATE);
1093         } catch (AssemblyException e) {
1094             LOG.error("Error disassembling CoreProgram", e);
1095             throw new OperationFailedException("Error disassembling CoreProgram");
1096         }
1097     }
1098 
1099 	@Override
1100 	@Transactional(readOnly=false)
1101 	public CoreProgramInfo createNewCoreProgramVersion(
1102 			String coreProgramId, String versionComment)
1103 			throws DoesNotExistException, InvalidParameterException,
1104 			MissingParameterException, OperationFailedException,
1105 			PermissionDeniedException, VersionMismatchException,
1106 			DataValidationErrorException {
1107 		//step one, get the original
1108 		VersionDisplayInfo currentVersion = luService.getCurrentVersion(LuServiceConstants.CLU_NAMESPACE_URI, coreProgramId);
1109 		CoreProgramInfo originalCoreProgram = getCoreProgram(currentVersion.getId());
1110 
1111 		//Version the Clu
1112 		CluInfo newVersionClu = luService.createNewCluVersion(coreProgramId, versionComment);
1113 
1114 		try {
1115 	        BaseDTOAssemblyNode<CoreProgramInfo, CluInfo> results;
1116 
1117 	        //Integrate changes into the original. (should this just be just the id?)
1118 			coreProgramAssembler.assemble(newVersionClu, originalCoreProgram, true);
1119 
1120 			//Clear Ids from the original so it will make a copy and do other processing
1121 			processCopy(originalCoreProgram, currentVersion.getId());
1122 
1123 			//Disassemble the new
1124 			results = coreProgramAssembler.disassemble(originalCoreProgram, NodeOperation.UPDATE);
1125 
1126 			// Use the results to make the appropriate service calls here
1127 			programServiceMethodInvoker.invokeServiceCalls(results);
1128 
1129 			return results.getBusinessDTORef();
1130 		} catch(AssemblyException e) {
1131 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
1132 		} catch (AlreadyExistsException e) {
1133 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
1134 		} catch (DependentObjectsExistException e) {
1135 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
1136 		} catch (CircularRelationshipException e) {
1137 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
1138 		} catch (UnsupportedActionException e) {
1139 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
1140 		} catch (CircularReferenceException e) {
1141 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
1142 		}
1143 	}
1144     
1145 
1146 
1147 	@Override
1148     @Transactional(readOnly=false)
1149 	public StatusInfo deleteCoreProgram(String coreProgramId) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
1150 //        try {
1151 //        	CoreProgramInfo coreProgramInfo = getCoreProgram(coreProgramId);
1152 //
1153 //            processCoreProgramInfo(coreProgramInfo, NodeOperation.DELETE);
1154 //
1155 //            return getStatus();
1156 //
1157 //        } catch (AssemblyException e) {
1158 //            LOG.error("Error disassembling CoreProgram", e);
1159 //            throw new OperationFailedException("Error disassembling CoreProgram");
1160 //        }
1161     	throw new OperationFailedException("Deletion of CoreProgram is not supported."); 
1162     }
1163 
1164     @Override
1165     public CoreProgramInfo getCoreProgram(String coreProgramId) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
1166     	CoreProgramInfo coreProgramInfo = null;
1167 
1168         try {
1169             CluInfo clu = luService.getClu(coreProgramId);
1170             if ( ! ProgramAssemblerConstants.CORE_PROGRAM.equals(clu.getType()) ) {
1171                 throw new DoesNotExistException("Specified CLU is not a CoreProgram");
1172             }
1173             coreProgramInfo = coreProgramAssembler.assemble(clu, null, false);
1174         } catch (AssemblyException e) {
1175             LOG.error("Error assembling CoreProgram", e);
1176             throw new OperationFailedException("Error assembling CoreProgram");
1177         }
1178         return coreProgramInfo;
1179 		// comment out the above, and uncomment below to get auto-generated data
1180         // (and vice-versa)
1181 //		try {
1182 //			return new CoreProgramDataGenerator().getCoreProgramInfoTestData();
1183 //		} catch (Exception e) {
1184 //			return null;
1185 //		}
1186     }
1187 
1188     @Override
1189     @Transactional(readOnly=false)
1190 	public CoreProgramInfo updateCoreProgram(CoreProgramInfo coreProgramInfo) throws DataValidationErrorException, DoesNotExistException, InvalidParameterException, MissingParameterException, VersionMismatchException, OperationFailedException, PermissionDeniedException {
1191         checkForMissingParameter(coreProgramInfo, "CoreProgramInfo");
1192         
1193         // Validate
1194         List<ValidationResultInfo> validationResults = validateCoreProgram("OBJECT", coreProgramInfo);
1195         if (null != validationResults && validationResults.size() > 0) {
1196             throw new DataValidationErrorException("Validation error!", validationResults);
1197         }
1198 
1199         try {
1200 
1201             return processCoreProgramInfo(coreProgramInfo, NodeOperation.UPDATE);
1202 
1203         } catch (AssemblyException e) {
1204             LOG.error("Error disassembling CoreProgram", e);
1205             throw new OperationFailedException("Error disassembling CoreProgram");
1206         }
1207     }
1208 
1209     @Override
1210     public List<ValidationResultInfo> validateCoreProgram(String validationType, CoreProgramInfo coreProgramInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException {
1211         List<ValidationResultInfo> validationResults = new ArrayList<ValidationResultInfo>();
1212 //        if ( ! ProgramAssemblerConstants.DRAFT.equals(coreProgramInfo.getState()) ) {
1213 	        ObjectStructureDefinition objStructure = this.getObjectStructure(CoreProgramInfo.class.getName());
1214 	        Validator validator = validatorFactory.getValidator();
1215             validationResults.addAll(validator.validateObject(coreProgramInfo, objStructure));
1216 //        }
1217         return validationResults;
1218     }
1219         
1220         
1221 	@Override
1222 	@Transactional(readOnly=false)
1223 	public CredentialProgramInfo createNewCredentialProgramVersion(
1224 			String credentialProgramId, String versionComment)
1225 			throws DoesNotExistException, InvalidParameterException,
1226 			MissingParameterException, OperationFailedException,
1227 			PermissionDeniedException, VersionMismatchException,
1228 			DataValidationErrorException {
1229 		//step one, get the original
1230 		VersionDisplayInfo currentVersion = luService.getCurrentVersion(LuServiceConstants.CLU_NAMESPACE_URI, credentialProgramId);
1231 		CredentialProgramInfo originaCredentialProgram = getCredentialProgram(currentVersion.getId());
1232 
1233 		//Version the Clu
1234 		CluInfo newVersionClu = luService.createNewCluVersion(credentialProgramId, versionComment);
1235 
1236 		try {
1237 	        BaseDTOAssemblyNode<CredentialProgramInfo, CluInfo> results;
1238 
1239 	        //Integrate changes into the original. (should this just be just the id?)
1240 			credentialProgramAssembler.assemble(newVersionClu, originaCredentialProgram, true);
1241 
1242 			//Clear Ids from the original so it will make a copy and do other processing
1243 			processCopy(originaCredentialProgram, currentVersion.getId());
1244 
1245 			//Disassemble the new
1246 			results = credentialProgramAssembler.disassemble(originaCredentialProgram, NodeOperation.UPDATE);
1247 
1248 			// Use the results to make the appropriate service calls here
1249 			programServiceMethodInvoker.invokeServiceCalls(results);
1250 
1251 			return results.getBusinessDTORef();
1252 		} catch(AssemblyException e) {
1253 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
1254 		} catch (AlreadyExistsException e) {
1255 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
1256 		} catch (DependentObjectsExistException e) {
1257 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
1258 		} catch (CircularRelationshipException e) {
1259 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
1260 		} catch (UnsupportedActionException e) {
1261 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
1262 		} catch (CircularReferenceException e) {
1263 			throw new OperationFailedException("Error creating new MajorDiscipline version",e);
1264 		}
1265 	}
1266 
1267 
1268 	@Override
1269 	@Transactional(readOnly=false)
1270 	public StatusInfo setCurrentCoreProgramVersion(String coreProgramId,
1271 			Date currentVersionStart) throws DoesNotExistException,
1272 			InvalidParameterException, MissingParameterException,
1273 			IllegalVersionSequencingException, OperationFailedException,
1274 			PermissionDeniedException {
1275 		StatusInfo status = luService.setCurrentCluVersion(coreProgramId, currentVersionStart);
1276 		
1277 		return status;
1278 	}
1279 
1280 	@Override
1281 	@Transactional(readOnly=false)
1282 	public StatusInfo setCurrentCredentialProgramVersion(
1283 			String credentialProgramId, Date currentVersionStart)
1284 			throws DoesNotExistException, InvalidParameterException,
1285 			MissingParameterException, IllegalVersionSequencingException,
1286 			OperationFailedException, PermissionDeniedException {
1287 		StatusInfo status = luService.setCurrentCluVersion(credentialProgramId, currentVersionStart);
1288 		
1289 		return status;
1290 	}
1291 
1292 	@Override
1293 	public VersionDisplayInfo getCurrentVersion(String refObjectTypeURI,
1294 			String refObjectId) throws DoesNotExistException,
1295 			InvalidParameterException, MissingParameterException,
1296 			OperationFailedException, PermissionDeniedException {
1297 		if(ProgramServiceConstants.PROGRAM_NAMESPACE_MAJOR_DISCIPLINE_URI.equals(refObjectTypeURI)){
1298 			return luService.getCurrentVersion(LuServiceConstants.CLU_NAMESPACE_URI, refObjectId);
1299 		}
1300 		throw new InvalidParameterException("Object type: " + refObjectTypeURI + " is not known to this implementation");
1301 	}
1302 
1303 	@Override
1304 	public VersionDisplayInfo getCurrentVersionOnDate(String refObjectTypeURI,
1305 			String refObjectId, Date date) throws DoesNotExistException,
1306 			InvalidParameterException, MissingParameterException,
1307 			OperationFailedException, PermissionDeniedException {
1308 		if(ProgramServiceConstants.PROGRAM_NAMESPACE_MAJOR_DISCIPLINE_URI.equals(refObjectTypeURI)){
1309 			return luService.getCurrentVersionOnDate(LuServiceConstants.CLU_NAMESPACE_URI, refObjectId, date);
1310 		}
1311 		throw new InvalidParameterException("Object type: " + refObjectTypeURI + " is not known to this implementation");
1312 	}
1313 
1314 	@Override
1315 	public VersionDisplayInfo getFirstVersion(String refObjectTypeURI,
1316 			String refObjectId) throws DoesNotExistException,
1317 			InvalidParameterException, MissingParameterException,
1318 			OperationFailedException, PermissionDeniedException {
1319 		if(ProgramServiceConstants.PROGRAM_NAMESPACE_MAJOR_DISCIPLINE_URI.equals(refObjectTypeURI)){
1320 			return luService.getFirstVersion(LuServiceConstants.CLU_NAMESPACE_URI, refObjectId);
1321 		}
1322 		throw new InvalidParameterException("Object type: " + refObjectTypeURI + " is not known to this implementation");
1323 
1324 	}
1325 
1326 	@Override
1327 	public VersionDisplayInfo getLatestVersion(String refObjectTypeURI,
1328 			String refObjectId) throws DoesNotExistException,
1329 			InvalidParameterException, MissingParameterException,
1330 			OperationFailedException, PermissionDeniedException {
1331 		if(ProgramServiceConstants.PROGRAM_NAMESPACE_MAJOR_DISCIPLINE_URI.equals(refObjectTypeURI)){
1332 			return luService.getLatestVersion(LuServiceConstants.CLU_NAMESPACE_URI, refObjectId);
1333 		}
1334 		throw new InvalidParameterException("Object type: " + refObjectTypeURI + " is not known to this implementation");
1335 
1336 	}
1337 
1338 	@Override
1339 	public VersionDisplayInfo getVersionBySequenceNumber(
1340 			String refObjectTypeURI, String refObjectId, Long sequence)
1341 			throws DoesNotExistException, InvalidParameterException,
1342 			MissingParameterException, OperationFailedException,
1343 			PermissionDeniedException {
1344 		if(ProgramServiceConstants.PROGRAM_NAMESPACE_MAJOR_DISCIPLINE_URI.equals(refObjectTypeURI)){
1345 			return luService.getVersionBySequenceNumber(LuServiceConstants.CLU_NAMESPACE_URI, refObjectId, sequence);
1346 		}
1347 		throw new InvalidParameterException("Object type: " + refObjectTypeURI + " is not known to this implementation");
1348 	}
1349 
1350 	@Override
1351 	public List<VersionDisplayInfo> getVersions(String refObjectTypeURI,
1352 			String refObjectId) throws DoesNotExistException,
1353 			InvalidParameterException, MissingParameterException,
1354 			OperationFailedException, PermissionDeniedException {
1355 		if(ProgramServiceConstants.PROGRAM_NAMESPACE_MAJOR_DISCIPLINE_URI.equals(refObjectTypeURI)){
1356 			return luService.getVersions(LuServiceConstants.CLU_NAMESPACE_URI, refObjectId);
1357 		}
1358 		throw new InvalidParameterException("Object type: " + refObjectTypeURI + " is not known to this implementation");
1359 	}
1360 
1361 	@Override
1362 	public List<VersionDisplayInfo> getVersionsInDateRange(
1363 			String refObjectTypeURI, String refObjectId, Date from, Date to)
1364 			throws DoesNotExistException, InvalidParameterException,
1365 			MissingParameterException, OperationFailedException,
1366 			PermissionDeniedException {
1367 		if(ProgramServiceConstants.PROGRAM_NAMESPACE_MAJOR_DISCIPLINE_URI.equals(refObjectTypeURI)){
1368 			return luService.getVersionsInDateRange(LuServiceConstants.CLU_NAMESPACE_URI, refObjectId, from, to);
1369 		}
1370 		throw new InvalidParameterException("Object type: " + refObjectTypeURI + " is not known to this implementation");
1371 	}
1372 
1373 	public void setAtpService(AtpService atpService) {
1374 		this.atpService = atpService;
1375 	}
1376 
1377 	public AtpService getAtpService() {
1378 		return atpService;
1379 	}
1380 
1381 	private void validateMajorDisciplineAtps(MajorDisciplineInfo majorDisciplineInfo, List<ValidationResultInfo> validationResults) throws InvalidParameterException, MissingParameterException, OperationFailedException{
1382 		
1383 		String startTerm = majorDisciplineInfo.getStartTerm();
1384 		
1385 		if(!isEmpty(majorDisciplineInfo.getAttributes().get("endInstAdmitTerm"))){
1386 			compareAtps(startTerm, majorDisciplineInfo.getAttributes().get("endInstAdmitTerm"), validationResults, "End Inst Admin Term", "endInstAdmitTerm");
1387 		}
1388 		
1389 		if(!isEmpty(majorDisciplineInfo.getEndProgramEntryTerm())){
1390 			compareAtps(startTerm, majorDisciplineInfo.getEndProgramEntryTerm(), validationResults, "End Program Entry Term", "endProgramEntryTerm");
1391 		}
1392 		
1393 		if(!isEmpty(majorDisciplineInfo.getEndTerm())){
1394 			compareAtps(startTerm, majorDisciplineInfo.getEndTerm(), validationResults, "End Program Enroll Term", "endTerm");
1395 		}		
1396 		
1397 		List<ProgramVariationInfo> variations = majorDisciplineInfo.getVariations();
1398 		if(variations != null && !variations.isEmpty()){
1399 			int idx = 0;
1400 			for(ProgramVariationInfo variation : variations){
1401 				validateVariationAtps(variation, validationResults, idx);
1402 				idx ++;
1403 			}
1404 		}
1405 	}
1406 	
1407 	//FIXME, this validation should be moved into a custom validation class + configuration
1408 	private void validateVariationAtps(ProgramVariationInfo programVariationInfo, List<ValidationResultInfo> validationResults, int idx) throws InvalidParameterException, MissingParameterException, OperationFailedException{
1409 		
1410 		String startTerm = programVariationInfo.getStartTerm();
1411 		
1412 		if(!isEmpty(programVariationInfo.getAttributes().get("endInstAdmitTerm"))){
1413 			compareAtps(startTerm, programVariationInfo.getAttributes().get("endInstAdmitTerm"), validationResults, "End Inst Admin Term",  "variations/" + idx + "/endInstAdmitTerm");
1414 		}
1415 	
1416 		if(!isEmpty(programVariationInfo.getEndProgramEntryTerm())){
1417 			compareAtps(startTerm, programVariationInfo.getEndProgramEntryTerm(), validationResults, "End Program Entry Term", "variations/" + idx + "/endProgramEntryTerm");
1418 		}
1419 		
1420 		if(!isEmpty(programVariationInfo.getEndTerm())){
1421 			compareAtps(startTerm, programVariationInfo.getEndTerm(), validationResults, "End Program Enroll Term", "variations/" + idx + "/endTerm");
1422 		}
1423 	}
1424 	
1425 	private AtpInfo getAtpInfo(String atpKey) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException{
1426 		if(atpKey==null){
1427 			return null;
1428 		}
1429 		return atpService.getAtp(atpKey);
1430 	}
1431 	//FIXME error should return using message service and not static text
1432 	private void compareAtps(String aptKey1, String aptKey2, List<ValidationResultInfo> validationResults, String field, String path) throws InvalidParameterException, MissingParameterException, OperationFailedException{
1433 		AtpInfo atpInfo1 = null;
1434 		AtpInfo atpInfo2 = null;
1435 		
1436 		try{
1437 			atpInfo1 = getAtpInfo(aptKey1);
1438 			atpInfo2 = getAtpInfo(aptKey2);
1439 		}catch(DoesNotExistException e){}
1440 		
1441 		if(atpInfo1 != null && atpInfo1 != null){
1442 			if(atpInfo1.getStartDate()!= null && atpInfo2.getStartDate() != null){			
1443 				boolean compareResult = ValidatorUtils.compareValues(atpInfo2.getStartDate(), atpInfo1.getStartDate(), DataType.DATE, "greater_than_equal", true, new ServerDateParser());
1444 				if(!compareResult){
1445 					ValidationResultInfo vri = new ValidationResultInfo();
1446 					vri.setElement(path);
1447 					vri.setError(field + " should be greater than Start Term");
1448 					validationResults.add(vri);
1449 				}
1450 			}
1451 		}
1452 			
1453 	}
1454 	
1455 	private boolean isEmpty(String value){
1456 		return value == null || (value != null && "".equals(value));
1457 	}
1458 
1459 	public void setDocumentService(DocumentService documentService) {
1460 		this.documentService = documentService;
1461 	}
1462 
1463 	public DocumentService getDocumentService() {
1464 		return documentService;
1465 	}
1466 
1467 }