View Javadoc

1   /*
2    * Copyright 2010 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   */
15  
16  package org.kuali.student.r2.lum.program.service.assembler;
17  
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.Iterator;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.kuali.student.common.util.UUIDHelper;
25  import org.kuali.student.r2.lum.service.assembler.CluAssemblerUtils;
26  import org.kuali.student.r1.common.assembly.BaseDTOAssemblyNode;
27  import org.kuali.student.r1.common.assembly.BaseDTOAssemblyNode.NodeOperation;
28  import org.kuali.student.r2.common.assembler.AssemblyException;
29  import org.kuali.student.r2.common.dto.AttributeInfo;
30  import org.kuali.student.r2.common.dto.ContextInfo;
31  import org.kuali.student.r2.common.dto.DtoConstants;
32  import org.kuali.student.r2.common.dto.RichTextInfo;
33  import org.kuali.student.r2.common.exceptions.DoesNotExistException;
34  import org.kuali.student.r2.common.exceptions.InvalidParameterException;
35  import org.kuali.student.r2.common.exceptions.MissingParameterException;
36  import org.kuali.student.r2.common.exceptions.OperationFailedException;
37  import org.kuali.student.r2.common.exceptions.PermissionDeniedException;
38  import org.kuali.student.r2.lum.clu.dto.AdminOrgInfo;
39  import org.kuali.student.r2.lum.clu.dto.CluCluRelationInfo;
40  import org.kuali.student.r2.lum.clu.dto.CluIdentifierInfo;
41  import org.kuali.student.r2.lum.clu.dto.CluInfo;
42  import org.kuali.student.r2.lum.clu.dto.CluPublicationInfo;
43  import org.kuali.student.r2.lum.clu.dto.CluResultInfo;
44  import org.kuali.student.r2.lum.clu.dto.FieldInfo;
45  import org.kuali.student.r2.lum.clu.dto.LuCodeInfo;
46  import org.kuali.student.r2.lum.clu.service.CluService;
47  import org.kuali.student.r2.lum.program.dto.CredentialProgramInfo;
48  import org.kuali.student.r2.lum.program.dto.assembly.ProgramAtpAssembly;
49  import org.kuali.student.r2.lum.program.dto.assembly.ProgramBasicOrgAssembly;
50  import org.kuali.student.r2.lum.program.dto.assembly.ProgramCodeAssembly;
51  import org.kuali.student.r2.lum.program.dto.assembly.ProgramCommonAssembly;
52  import org.kuali.student.r2.lum.program.dto.assembly.ProgramCredentialAssembly;
53  import org.kuali.student.r2.lum.program.dto.assembly.ProgramFullOrgAssembly;
54  import org.kuali.student.r2.lum.program.dto.assembly.ProgramIdentifierAssembly;
55  import org.kuali.student.r2.lum.program.dto.assembly.ProgramPublicationAssembly;
56  import org.kuali.student.r2.lum.program.dto.assembly.ProgramRequirementAssembly;
57  
58  public class ProgramAssemblerUtils {
59  
60      private CluService cluService;
61      private CluAssemblerUtils cluAssemblerUtils;
62  
63       /**
64       * Copy basic values from clu to program
65       *
66       * @param clu
67       * @param program
68       * @return
69       * @throws AssemblyException
70       */
71       public ProgramCommonAssembly assembleBasics(CluInfo clu, ProgramCommonAssembly program, ContextInfo contextInfo) throws AssemblyException {
72  
73           if (program instanceof CredentialProgramInfo) {
74               ((CredentialProgramInfo)program).setCredentialProgramType(clu.getTypeKey());
75           }
76           else {
77               program.setTypeKey(clu.getTypeKey());
78           }
79           program.setStateKey(clu.getStateKey());
80           program.setMeta(clu.getMeta());
81           program.setAttributes(clu.getAttributes());
82           program.setId(clu.getId());
83  
84           return program;
85       }
86  
87      /**
88       * Copy basic values from program to clu
89       *
90       * @param clu
91       * @param program
92       * @param operation
93       * @return
94       * @throws AssemblyException
95       */
96      public CluInfo disassembleBasics(CluInfo clu, ProgramCommonAssembly program) throws AssemblyException {
97  
98          if (program instanceof CredentialProgramInfo) {
99              clu.setTypeKey(((CredentialProgramInfo)program).getCredentialProgramType());
100         }
101         else {
102             clu.setTypeKey(program.getTypeKey());
103         }
104         clu.setId(UUIDHelper.genStringUUID(program.getId()));
105         
106         // Default 
107         clu.setStateKey(program.getStateKey());
108         clu.setMeta(program.getMeta());
109         clu.setAttributes(program.getAttributes());
110         if (clu.getIsEnrollable() == null) {
111             clu.setIsEnrollable(false);
112         }
113         return clu;
114 
115     }
116 
117     //TODO maybe this should be in CluAssemblerUtils??
118     public ProgramRequirementAssembly assembleRequirements(CluInfo clu, ProgramRequirementAssembly program, ContextInfo contextInfo) throws AssemblyException {
119 
120         try {
121             List<String> requirements = cluService.getRelatedCluIdsByCluAndRelationType(clu.getId(), ProgramAssemblerConstants.HAS_PROGRAM_REQUIREMENT, contextInfo);
122             if (requirements != null && requirements.size() > 0) {
123                 program.setProgramRequirements(requirements);
124             }
125         }
126         catch (Exception e)
127         {
128             throw new AssemblyException("Error assembling program requirements", e);
129         }
130 
131         return program;
132     }
133 
134     //TODO  maybe this should be in CluAssemblerUtils??
135     public CluInfo disassembleRequirements(CluInfo clu, ProgramRequirementAssembly program, NodeOperation operation, BaseDTOAssemblyNode<?, ?> result, boolean stateChanged, ContextInfo contextInfo) throws AssemblyException {
136         try {
137             List<String> requirements = program.getProgramRequirements ();
138 
139             if (requirements != null && !requirements.isEmpty()) {
140             	if (stateChanged){
141             		addUpdateRequirementStateNodes(requirements, program.getStateKey(), result, contextInfo);
142             	}
143             	
144                	Map<String, String> currentRelations = null;
145 
146                 if (!NodeOperation.CREATE.equals(operation)) {
147                 	currentRelations = getCluCluRelations(clu.getId(), ProgramAssemblerConstants.HAS_PROGRAM_REQUIREMENT, contextInfo);
148                 }
149                 
150     	    	for (String requirementId : requirements){
151     	    		List<BaseDTOAssemblyNode<?, ?>> reqResults = addAllRelationNodes(clu.getId(), requirementId, ProgramAssemblerConstants.HAS_PROGRAM_REQUIREMENT, operation, currentRelations);
152     	            if (reqResults != null && reqResults.size()> 0) {
153     	                result.getChildNodes().addAll(reqResults);
154     	            }
155     	    	}
156     	    	
157     	        if(currentRelations != null && currentRelations.size() > 0){
158 	    	        for (Map.Entry<String, String> entry : currentRelations.entrySet()) {
159 	    	            // Create a new relation with the id of the relation we want to
160 	    	            // delete
161 	    	            CluCluRelationInfo relationToDelete = new CluCluRelationInfo();
162 	    	            relationToDelete.setId( entry.getValue() );
163 	    	            BaseDTOAssemblyNode<Object, CluCluRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<Object, CluCluRelationInfo>(
164 	    	                    null);
165 	    	            relationToDeleteNode.setNodeData(relationToDelete);
166 	    	            relationToDeleteNode.setOperation(NodeOperation.DELETE);
167 	    	            result.getChildNodes().add(relationToDeleteNode);
168 	    	        }
169     	        }
170             }
171 	    } catch (Exception e) {
172 	        throw new AssemblyException("Error while disassembling program requirements", e);
173 	    }
174 	    
175         return clu;
176 
177     }
178 
179         
180     /**
181      * This adds nodes to update the state for the requirement clu
182      * @param state
183      * @param result
184      * @throws OperationFailedException 
185      * @throws MissingParameterException 
186      * @throws InvalidParameterException 
187      * @throws PermissionDeniedException 
188      */
189     private void addUpdateRequirementStateNodes(List<String> requirements, String state, BaseDTOAssemblyNode<?, ?> result, ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
190     	for (String requirementId:requirements){
191     		try {
192     			
193 	    		CluInfo requirementClu = cluService.getClu(requirementId, contextInfo);
194 	            requirementClu.setStateKey(state);
195 	            BaseDTOAssemblyNode<Object, CluInfo> reqCluNode = new BaseDTOAssemblyNode<Object, CluInfo>(null);
196 	            reqCluNode.setNodeData(requirementClu);
197 	            reqCluNode.setOperation(NodeOperation.UPDATE);
198 	            result.getChildNodes().add(reqCluNode);
199     		} catch (DoesNotExistException e){
200     			//Don't need to update what doesn't exist
201     		}
202     	}
203 	}
204 
205 	/**
206      * Copy identifier values from clu to program
207      *
208      * @param clu
209      * @param o
210      * @return
211      * @throws AssemblyException
212      */
213     public ProgramIdentifierAssembly assembleIdentifiers(CluInfo clu, ProgramIdentifierAssembly program) throws AssemblyException {
214 
215         if (clu.getOfficialIdentifier() != null) {
216             if (clu.getOfficialIdentifier().getShortName() != null) {
217                 program.setShortTitle(clu.getOfficialIdentifier().getShortName());
218             }
219             if (clu.getOfficialIdentifier().getLongName() != null) {
220                 program.setLongTitle(clu.getOfficialIdentifier().getLongName());
221             }
222             if (clu.getOfficialIdentifier().getCode() != null) {
223                 program.setCode(clu.getOfficialIdentifier().getCode());
224             }
225         }
226         if (clu.getAlternateIdentifiers() != null) {
227             for (CluIdentifierInfo cluIdInfo : clu.getAlternateIdentifiers()) {
228                 String idInfoType = cluIdInfo.getTypeKey();
229                 if (ProgramAssemblerConstants.TRANSCRIPT.equals(idInfoType)) {
230                     program.setTranscriptTitle(cluIdInfo.getShortName());
231                 } else if (ProgramAssemblerConstants.DIPLOMA.equals(idInfoType)) {
232                     program.setDiplomaTitle(cluIdInfo.getShortName());
233                 }
234             }
235         }
236         return program;
237     }
238 
239 
240     /**
241      * Copy identifier values from program to clu
242      *
243      * @param clu
244      * @param program
245      * @param operation
246      * @return
247      * @throws AssemblyException
248      */
249     public CluInfo disassembleIdentifiers(CluInfo clu, ProgramIdentifierAssembly program, NodeOperation operation) throws AssemblyException {
250 
251         CluIdentifierInfo official = null != clu.getOfficialIdentifier() ? clu.getOfficialIdentifier() : new CluIdentifierInfo();
252 
253         official.setCode(program.getCode());
254         official.setLongName(program.getLongTitle());
255         official.setShortName(program.getShortTitle());
256         official.setStateKey(program.getStateKey());
257         // gotta be this type
258         official.setTypeKey(ProgramAssemblerConstants.OFFICIAL);
259 
260         if (program instanceof CredentialProgramInfo) {
261             CredentialProgramInfo cred = (CredentialProgramInfo)program;
262             official.setLevel(cred.getProgramLevel());
263         }
264 
265         clu.setOfficialIdentifier(official);
266 
267         //Remove any existing diploma or transcript alt identifiers
268         CluIdentifierInfo diplomaInfo = null;
269         CluIdentifierInfo transcriptInfo = null;
270         for(Iterator<CluIdentifierInfo> iter = clu.getAlternateIdentifiers().iterator();iter.hasNext();){
271             CluIdentifierInfo cluIdentifier = iter.next();
272             if (ProgramAssemblerConstants.DIPLOMA.equals(cluIdentifier.getTypeKey())) {
273                 diplomaInfo = cluIdentifier;
274                 diplomaInfo.setStateKey(program.getStateKey());
275             } else if (ProgramAssemblerConstants.TRANSCRIPT.equals(cluIdentifier.getTypeKey())) {
276                 transcriptInfo = cluIdentifier;
277                 transcriptInfo.setStateKey(program.getStateKey());
278             }
279         }
280         
281         if (program.getDiplomaTitle() != null) {
282             if (diplomaInfo == null) {
283                 diplomaInfo = new CluIdentifierInfo();
284                 diplomaInfo.setStateKey(program.getStateKey());
285                 clu.getAlternateIdentifiers().add(diplomaInfo);
286             }
287             diplomaInfo.setCode(official.getCode());
288             diplomaInfo.setShortName(program.getDiplomaTitle());
289             diplomaInfo.setTypeKey(ProgramAssemblerConstants.DIPLOMA);
290         }
291 
292         if (program.getTranscriptTitle() != null) {
293             if (transcriptInfo == null) {
294                 transcriptInfo = new CluIdentifierInfo();
295                 transcriptInfo.setStateKey(program.getStateKey());
296                 clu.getAlternateIdentifiers().add(transcriptInfo);
297             }
298             transcriptInfo.setCode(official.getCode());
299             transcriptInfo.setShortName(program.getTranscriptTitle());
300             transcriptInfo.setTypeKey(ProgramAssemblerConstants.TRANSCRIPT);
301         }
302         return clu;
303     }
304 
305     /**
306      * Copy Lu Codes from clu to program
307      *
308      * @param clu
309      * @param program
310      * @return
311      * @throws AssemblyException
312      */
313     public ProgramCodeAssembly assembleLuCodes(CluInfo clu, ProgramCodeAssembly program) throws AssemblyException {
314 
315         if (clu.getLuCodes() != null) {
316             for (LuCodeInfo codeInfo : clu.getLuCodes()) {
317                 if (ProgramAssemblerConstants.CIP_2000.equals(codeInfo.getType())) {
318                     program.setCip2000Code(codeInfo.getValue());
319                 } else if (ProgramAssemblerConstants.CIP_2010.equals(codeInfo.getType())) {
320                     program.setCip2010Code(codeInfo.getValue());
321                 } else if (ProgramAssemblerConstants.HEGIS.equals(codeInfo.getType())) {
322                     program.setHegisCode(codeInfo.getValue());
323                 } else if (ProgramAssemblerConstants.UNIVERSITY_CLASSIFICATION.equals(codeInfo.getType())) {
324                     program.setUniversityClassification(codeInfo.getValue());
325                 } else if (ProgramAssemblerConstants.SELECTIVE_ENROLLMENT.equals(codeInfo.getType())) {
326                     program.setSelectiveEnrollmentCode(codeInfo.getValue());
327                 }
328             }
329         }
330 
331         return program;
332     }
333 
334 
335     /**
336      * Copy Lu Codes from program to clu
337      *
338      * @param clu
339      * @param program
340      * @param operation
341      * @throws AssemblyException
342      */
343     public CluInfo disassembleLuCodes(CluInfo clu, ProgramCodeAssembly program, NodeOperation operation) throws AssemblyException {
344 
345         clu.setLuCodes(new ArrayList<LuCodeInfo>());
346 
347         addLuCodeFromProgram(ProgramAssemblerConstants.CIP_2000, program.getCip2000Code(), clu.getLuCodes());
348         addLuCodeFromProgram(ProgramAssemblerConstants.CIP_2010, program.getCip2010Code(), clu.getLuCodes());
349         addLuCodeFromProgram(ProgramAssemblerConstants.HEGIS, program.getHegisCode(), clu.getLuCodes());
350         addLuCodeFromProgram(ProgramAssemblerConstants.UNIVERSITY_CLASSIFICATION, program.getUniversityClassification(), clu.getLuCodes());
351         addLuCodeFromProgram(ProgramAssemblerConstants.SELECTIVE_ENROLLMENT, program.getSelectiveEnrollmentCode(), clu.getLuCodes());
352 
353         return clu;
354 
355     }
356 
357     /**
358      * Copy AdminOrg id's from clu's AdminOrgInfo's to program
359      *
360      * @param clu
361      * @param program
362      * @return
363      * @throws AssemblyException
364      */
365     public ProgramBasicOrgAssembly assembleBasicAdminOrgs(CluInfo clu, ProgramBasicOrgAssembly program) throws AssemblyException {
366 
367         if (clu.getAdminOrgs() != null) {
368             clearProgramAdminOrgs(program);
369             for (AdminOrgInfo cluOrg : clu.getAdminOrgs()) {
370                 if (cluOrg.getTypeKey().equals(ProgramAssemblerConstants.CURRICULUM_OVERSIGHT_DIVISION)) {
371                     program.getDivisionsContentOwner().add(cluOrg.getOrgId());
372                 }
373                 else if (cluOrg.getTypeKey().equals(ProgramAssemblerConstants.STUDENT_OVERSIGHT_DIVISION)) {
374                     program.getDivisionsStudentOversight().add(cluOrg.getOrgId())  ;
375                 }
376                 else if (cluOrg.getTypeKey().equals(ProgramAssemblerConstants.CURRICULUM_OVERSIGHT_UNIT)) {
377                     program.getUnitsContentOwner().add(cluOrg.getOrgId())  ;
378                 }
379                 else if (cluOrg.getTypeKey().equals(ProgramAssemblerConstants.STUDENT_OVERSIGHT_UNIT)) {
380                     program.getUnitsStudentOversight().add(cluOrg.getOrgId())  ;
381                 }
382             }
383         }
384         return program;
385     }
386 
387     public ProgramFullOrgAssembly assembleFullOrgs(CluInfo clu, ProgramFullOrgAssembly program) throws AssemblyException {
388 
389         clearFullAdminOrgs(program);
390         for (AdminOrgInfo cluOrg : clu.getAdminOrgs()) {
391             if (cluOrg.getTypeKey().equals(ProgramAssemblerConstants.DEPLOYMENT_DIVISION)) {
392                 program.getDivisionsDeployment().add(cluOrg.getOrgId())  ;
393             }
394             else if (cluOrg.getTypeKey().equals(ProgramAssemblerConstants.FINANCIAL_RESOURCES_DIVISION)) {
395                 program.getDivisionsFinancialResources().add(cluOrg.getOrgId())  ;
396             }
397             else if (cluOrg.getTypeKey().equals(ProgramAssemblerConstants.FINANCIAL_CONTROL_DIVISION)) {
398                 program.getDivisionsFinancialControl().add(cluOrg.getOrgId())  ;
399             }
400             else if (cluOrg.getTypeKey().equals(ProgramAssemblerConstants.DEPLOYMENT_UNIT)) {
401                 program.getUnitsDeployment().add(cluOrg.getOrgId())  ;
402             }
403             else if (cluOrg.getTypeKey().equals(ProgramAssemblerConstants.FINANCIAL_RESOURCES_UNIT)) {
404                 program.getUnitsFinancialResources().add(cluOrg.getOrgId())  ;
405             }
406             else if (cluOrg.getTypeKey().equals(ProgramAssemblerConstants.FINANCIAL_CONTROL_UNIT)) {
407                 program.getUnitsFinancialControl().add(cluOrg.getOrgId())  ;
408             }
409         }
410         return program;
411     }
412 
413     private void clearProgramAdminOrgs(ProgramBasicOrgAssembly program) {
414         program.setDivisionsContentOwner(new ArrayList<String>());
415         program.setDivisionsStudentOversight(new ArrayList<String>());
416         program.setUnitsContentOwner(new ArrayList<String>());
417         program.setUnitsStudentOversight(new ArrayList<String>());
418     }
419 
420     private void clearFullAdminOrgs(ProgramFullOrgAssembly program) {
421         program.setDivisionsDeployment(new ArrayList<String>());
422         program.setDivisionsFinancialResources(new ArrayList<String>());
423         program.setDivisionsFinancialControl(new ArrayList<String>());
424         program.setUnitsDeployment(new ArrayList<String>());
425         program.setUnitsFinancialResources(new ArrayList<String>());
426         program.setUnitsFinancialControl(new ArrayList<String>());
427     }
428 
429     /**
430      * Copy AdminOrg values from program to clu
431      *
432      * @param clu
433      * @param o
434      * @param operation
435      */
436     public CluInfo disassembleAdminOrgs(CluInfo clu, ProgramBasicOrgAssembly program, NodeOperation operation){
437 
438         // clear out all old admin orgs
439         clu.setAdminOrgs(new ArrayList<AdminOrgInfo>());
440 
441         newBuildAdminOrgs(clu,  program.getDivisionsContentOwner(), ProgramAssemblerConstants.CURRICULUM_OVERSIGHT_DIVISION);
442         newBuildAdminOrgs(clu, program.getDivisionsStudentOversight(), ProgramAssemblerConstants.STUDENT_OVERSIGHT_DIVISION );
443         newBuildAdminOrgs(clu,  program.getUnitsContentOwner(), ProgramAssemblerConstants.CURRICULUM_OVERSIGHT_UNIT);
444         newBuildAdminOrgs(clu, program.getUnitsStudentOversight(), ProgramAssemblerConstants.STUDENT_OVERSIGHT_UNIT );
445         if (program instanceof CredentialProgramInfo) {
446             List<String> institutionOrgs = new ArrayList<String>();
447             institutionOrgs.add(((CredentialProgramInfo)program).getInstitution().getOrgId());
448             newBuildAdminOrgs(clu, institutionOrgs , ProgramAssemblerConstants.INSTITUTION) ;
449         }
450         if (program instanceof ProgramFullOrgAssembly) {
451             ProgramFullOrgAssembly fullOrg = (ProgramFullOrgAssembly) program;
452             newBuildAdminOrgs(clu, fullOrg.getDivisionsDeployment(), ProgramAssemblerConstants.DEPLOYMENT_DIVISION);
453             newBuildAdminOrgs(clu, fullOrg.getDivisionsFinancialResources(), ProgramAssemblerConstants.FINANCIAL_RESOURCES_DIVISION);
454             newBuildAdminOrgs(clu, fullOrg.getDivisionsFinancialControl(), ProgramAssemblerConstants.FINANCIAL_CONTROL_DIVISION);
455             newBuildAdminOrgs(clu, fullOrg.getUnitsDeployment(), ProgramAssemblerConstants.DEPLOYMENT_UNIT);
456             newBuildAdminOrgs(clu, fullOrg.getUnitsFinancialResources(), ProgramAssemblerConstants.FINANCIAL_RESOURCES_UNIT);
457             newBuildAdminOrgs(clu, fullOrg.getUnitsFinancialControl(), ProgramAssemblerConstants.FINANCIAL_CONTROL_UNIT);
458 
459         }
460         return clu;
461 
462     }
463 
464     private CluInfo newBuildAdminOrgs(CluInfo clu,  List<String> orgIds, String type) {
465 
466         if (null != orgIds) {
467             for (String orgId : orgIds) {
468                 AdminOrgInfo subjectOrg = new AdminOrgInfo();
469                 subjectOrg.setTypeKey(type);
470                 subjectOrg.setOrgId(orgId);
471                 clu.getAdminOrgs().add(subjectOrg);
472             }
473         }
474         return clu;
475     }
476 
477     /**
478      * Copy result option values from clu to program
479      *
480      * @param cluId
481      * @param resultType
482      * @return
483      * @throws AssemblyException
484      */
485     public List<String> assembleResultOptions(String cluId, ContextInfo contextInfo) throws AssemblyException {
486         List<String> resultOptions = null;
487         try{
488             List<CluResultInfo> cluResults = cluService.getCluResultByClu(cluId, contextInfo);
489 
490             List<String> resultTypes = new ArrayList<String>();
491             resultTypes.add(ProgramAssemblerConstants.DEGREE_RESULTS);
492             resultTypes.add(ProgramAssemblerConstants.CERTIFICATE_RESULTS);
493 
494             resultOptions = cluAssemblerUtils.assembleCluResults(resultTypes, cluResults);
495 
496         } catch (DoesNotExistException e){
497         } catch (Exception e) {
498             throw new AssemblyException("Error getting major results", e);
499         }
500         return resultOptions;
501     }
502 
503     /**
504      * Copy atp values  from clu to program
505      *
506      * @param clu
507      * @param program
508      * @return
509      * @throws AssemblyException
510      */
511     public ProgramAtpAssembly assembleAtps(CluInfo clu, ProgramAtpAssembly program) throws AssemblyException {
512 
513         if (clu.getExpectedFirstAtp() != null) {
514             program.setStartTerm(clu.getExpectedFirstAtp());
515         }
516         if (clu.getLastAtp() != null) {
517             program.setEndTerm(clu.getLastAtp());
518         }
519         if (clu.getLastAdmitAtp() != null) {
520             program.setEndProgramEntryTerm(clu.getLastAdmitAtp());
521         }
522         return program;
523     }
524 
525 
526     /**
527      * Copy atp values from Program to clu
528      *
529      * @param clu
530      * @param program
531      * @return
532      * @throws AssemblyException
533      */
534     public CluInfo disassembleAtps(CluInfo clu, ProgramAtpAssembly program, NodeOperation operation) throws AssemblyException {
535 
536         clu.setExpectedFirstAtp(program.getStartTerm());
537         clu.setLastAtp(program.getEndTerm());
538         clu.setLastAdmitAtp(program.getEndProgramEntryTerm());
539 
540         return clu;
541 
542     }
543 
544     /**
545      * Copy publication values from clu to program
546      *
547      * @param clu
548      * @param program
549      * @return
550      * @throws AssemblyException
551      * @throws PermissionDeniedException 
552      */
553     public ProgramPublicationAssembly assemblePublications(CluInfo clu, ProgramPublicationAssembly program, ContextInfo contextInfo) throws AssemblyException, PermissionDeniedException {
554 
555 
556         if (clu.getReferenceURL() != null) {
557             program.setReferenceURL(clu.getReferenceURL());
558         }
559 
560         try {
561             List<CluPublicationInfo> cluPublications = cluService.getCluPublicationsByClu(clu.getId(), contextInfo);
562 
563             List<String> targets = new ArrayList<String>();
564 
565             for (CluPublicationInfo cluPublication : cluPublications) {
566                 if (cluPublication.getTypeKey().equals(ProgramAssemblerConstants.CATALOG)) {
567                     assembleCatalogDescr(program, cluPublication);
568                 }
569                 else {
570                     targets.add(cluPublication.getTypeKey());
571                 }
572             }
573 
574             if (targets != null && !targets.isEmpty()) {
575                 program.setCatalogPublicationTargets(targets);
576             }
577         } catch (DoesNotExistException e) {
578         } catch (InvalidParameterException e) {
579         } catch (MissingParameterException e) {
580         } catch (OperationFailedException e) {
581             throw new AssemblyException("Error getting publication targets", e);
582         }
583         return program;
584     }
585 
586     private void assembleCatalogDescr(ProgramPublicationAssembly program, CluPublicationInfo cluPublication)  {
587 
588         for (FieldInfo fieldInfo : cluPublication.getVariants()) {
589             if (fieldInfo.getId().equals(ProgramAssemblerConstants.CATALOG_DESCR)) {
590                 RichTextInfo desc = new RichTextInfo();
591                 desc.setPlain(fieldInfo.getValue());
592                 desc.setFormatted(fieldInfo.getValue());
593                 program.setCatalogDescr(desc);
594                 break;
595             }
596         }
597     }
598 
599      private List<BaseDTOAssemblyNode<?, ?>> disassembleCatalogDescr(ProgramPublicationAssembly program,  NodeOperation operation, ContextInfo contextInfo) throws AssemblyException {
600 
601          List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
602 
603          CluPublicationInfo currentPubInfo = null;
604 
605          try {
606 
607              // if not create get current catalog descr
608              if (!NodeOperation.CREATE.equals(operation)) {
609                  List<CluPublicationInfo> pubs = cluService.getCluPublicationsByClu(program.getId(), contextInfo);
610                  for (CluPublicationInfo pubInfo : pubs) {
611                      if (pubInfo.getTypeKey().equals(ProgramAssemblerConstants.CATALOG)) {
612                          currentPubInfo = pubInfo;
613                      }
614                  }
615              }
616 
617              if (program.getCatalogDescr() != null) {
618                  //  If this is a create then create new catalog descr
619                  if (NodeOperation.CREATE == operation
620                          || (NodeOperation.UPDATE == operation && currentPubInfo == null )) {
621                      // the description does not exist, so create
622                      CluPublicationInfo pubInfo = buildCluPublicationInfo(program.getId(), ProgramAssemblerConstants.CATALOG);
623                      pubInfo.setStateKey(program.getStateKey());
624                      FieldInfo variant = new FieldInfo();
625                      variant.setId(ProgramAssemblerConstants.CATALOG_DESCR);
626                      variant.setValue(program.getCatalogDescr() .getPlain());
627                      pubInfo.getVariants().add(variant);
628 
629                      BaseDTOAssemblyNode<Object, CluPublicationInfo> pubNode = new BaseDTOAssemblyNode<Object, CluPublicationInfo>(
630                              null);
631                      pubNode.setNodeData(pubInfo);
632                      pubNode.setOperation(NodeOperation.CREATE);
633 
634                      results.add(pubNode);
635                  } else if (NodeOperation.UPDATE == operation
636                          && currentPubInfo != null) {
637 
638                      CluPublicationInfo pubInfo = currentPubInfo;
639                      pubInfo.setStateKey(program.getStateKey());
640                      for (FieldInfo fieldInfo : pubInfo.getVariants()) {
641                          if (fieldInfo.getId().equals(ProgramAssemblerConstants.CATALOG_DESCR)) {
642                              fieldInfo.setValue(program.getCatalogDescr() .getPlain());
643                              break;
644                          }
645                      }
646 
647                      BaseDTOAssemblyNode<Object, CluPublicationInfo> pubNode = new BaseDTOAssemblyNode<Object, CluPublicationInfo>(
648                              null);
649                      pubNode.setNodeData(pubInfo);
650                      pubNode.setOperation(NodeOperation.UPDATE);
651 
652                      results.add(pubNode);
653                      
654                  }
655                  else if (NodeOperation.DELETE == operation  )  {
656 
657                      deletePublicationInfo(results, currentPubInfo);
658                  }
659              }
660          } catch (Exception e) {
661              throw new AssemblyException(e);
662          }
663          return results;
664     }
665 
666     private void deletePublicationInfo(List<BaseDTOAssemblyNode<?, ?>> results, CluPublicationInfo currentPubInfo) {
667         CluPublicationInfo descrToDelete = new CluPublicationInfo();
668         descrToDelete.setId(currentPubInfo.getId());
669         BaseDTOAssemblyNode<Object, CluPublicationInfo> pubToDeleteNode = new BaseDTOAssemblyNode<Object, CluPublicationInfo>(
670                 null);
671         pubToDeleteNode.setNodeData(descrToDelete);
672         pubToDeleteNode.setOperation(NodeOperation.DELETE);
673         results.add(pubToDeleteNode);
674     }
675 
676     /**
677      * Copy publication values from program to clu
678      *
679      * @param clu
680      * @param program
681      * @param operation
682      * @return
683      * @throws AssemblyException
684      */
685     public CluInfo disassemblePublications(CluInfo clu, ProgramPublicationAssembly program, NodeOperation operation, BaseDTOAssemblyNode<?, ?> result, ContextInfo contextInfo) throws AssemblyException {
686 
687         clu.setReferenceURL(program.getReferenceURL());
688         clu.setStateKey(program.getStateKey());
689 
690         List<BaseDTOAssemblyNode<?, ?>> targetResults = disassemblePublicationTargets(program, operation, contextInfo);
691         if (targetResults != null && targetResults.size()> 0) {
692             result.getChildNodes().addAll(targetResults);
693         }
694 
695         List<BaseDTOAssemblyNode<?, ?>> descrResults = disassembleCatalogDescr(program, operation,contextInfo) ;
696         if (descrResults != null && descrResults.size()> 0) {
697             result.getChildNodes().addAll(descrResults);
698         }
699 
700         return clu;
701 
702     }
703 
704     /**
705      * Copy credential program id value from program to clu
706      *
707      * @param clu
708      * @param o
709      * @param operation
710      * @return
711      * @throws AssemblyException
712      * @throws PermissionDeniedException 
713      */
714     public List<BaseDTOAssemblyNode<?,?>>  disassembleCredentialProgram(ProgramCredentialAssembly program, NodeOperation operation, String relationType, ContextInfo contextInfo) throws AssemblyException, PermissionDeniedException {
715 
716         List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
717 
718         try {
719             CluInfo credentialClu = cluService.getClu(program.getCredentialProgramId(),contextInfo);
720         } catch (DoesNotExistException e) {
721         } catch (Exception e) {
722             throw new AssemblyException("Credential Clu does not exist for " + program.getCredentialProgramId());
723         }
724 
725         Map<String, String> currentRelations = new HashMap<String, String>();
726 
727         if (!NodeOperation.CREATE.equals(operation)) {
728             try {
729                 List<CluCluRelationInfo> cluRelations = cluService.getCluCluRelationsByClu(program.getId(),contextInfo);
730                 for (CluCluRelationInfo cluRelation : cluRelations) {
731                     if (relationType.equals(cluRelation.getTypeKey()) ) {
732                         currentRelations.put(cluRelation.getRelatedCluId(), cluRelation.getId());
733                     }
734                 }
735             } catch (DoesNotExistException e) {
736             } catch (InvalidParameterException e) {
737             } catch (MissingParameterException e) {
738             } catch (OperationFailedException e) {
739                 throw new AssemblyException("Error getting related clus", e);
740             }
741         }
742 
743 
744         //  If this is a create then vreate new relation
745         if (NodeOperation.CREATE == operation
746                 || (NodeOperation.UPDATE == operation && !currentRelations.containsKey(program.getCredentialProgramId()) )) {
747             // the relation does not exist, so create
748             CluCluRelationInfo relation = new CluCluRelationInfo();
749             relation.setCluId(program.getCredentialProgramId());
750             relation.setRelatedCluId(program.getId());
751             relation.setTypeKey(relationType);
752             // We are hard coding this to active since relations can only be active/suspended
753             // DO NOT propagate states such as DRAFT etc to the relations.
754             relation.setStateKey(DtoConstants.STATE_ACTIVE);
755 
756             BaseDTOAssemblyNode<Object, CluCluRelationInfo> relationNode = new BaseDTOAssemblyNode<Object, CluCluRelationInfo>(
757                     null);
758             relationNode.setNodeData(relation);
759             relationNode.setOperation(NodeOperation.CREATE);
760 
761             results.add(relationNode);
762         } else if (NodeOperation.UPDATE == operation
763                 && currentRelations.containsKey(program.getCredentialProgramId())) {
764             // If the relationship already exists update it
765 
766             // remove this entry from the map so we can tell what needs to
767             // be deleted at the end
768             currentRelations.remove(program.getCredentialProgramId());
769         } else if (NodeOperation.DELETE == operation
770                 && currentRelations.containsKey(program.getId()))  {
771             // Delete the Format and its relation
772             CluCluRelationInfo relationToDelete = new CluCluRelationInfo();
773             relationToDelete.setId( currentRelations.get(program.getId()) );
774             BaseDTOAssemblyNode<Object, CluCluRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<Object, CluCluRelationInfo>(
775                     null);
776             relationToDeleteNode.setNodeData(relationToDelete);
777             relationToDeleteNode.setOperation(NodeOperation.DELETE);
778             results.add(relationToDeleteNode);
779 
780             // remove this entry from the map so we can tell what needs to
781             // be deleted at the end
782             currentRelations.remove(program.getId());
783         }
784 
785         if(currentRelations != null && currentRelations.size() > 0){
786 	        for (Map.Entry<String, String> entry : currentRelations.entrySet()) {
787 	            // Create a new relation with the id of the relation we want to
788 	            // delete
789 	            CluCluRelationInfo relationToDelete = new CluCluRelationInfo();
790 	            relationToDelete.setId( entry.getValue() );
791 	            BaseDTOAssemblyNode<Object, CluCluRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<Object, CluCluRelationInfo>(
792 	                    null);
793 	            relationToDeleteNode.setNodeData(relationToDelete);
794 	            relationToDeleteNode.setOperation(NodeOperation.DELETE);
795 	            results.add(relationToDeleteNode);
796 	        }
797         }
798         return results;
799     }
800 
801     public List<BaseDTOAssemblyNode<?, ?>> addRelationNodes(String cluId, String relatedCluId, String relationType, NodeOperation operation, ContextInfo contextInfo)throws AssemblyException, PermissionDeniedException{
802     	Map<String, String> currentRelations = null;
803     	List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
804 
805         if (!NodeOperation.CREATE.equals(operation)) {
806         	currentRelations =  getCluCluRelations(cluId, relationType, contextInfo);
807         }
808 
809         //  If this is a create then vreate new relation
810         if (NodeOperation.CREATE == operation
811                 || (NodeOperation.UPDATE == operation && !currentRelations.containsKey(relatedCluId) )) {
812             // the relation does not exist, so create
813         	addCreateRelationNode(cluId, relatedCluId, relationType, results);
814         } else if (NodeOperation.UPDATE == operation
815                 && currentRelations.containsKey(relatedCluId)) {
816             // If the relationship already exists update it
817 
818             // remove this entry from the map so we can tell what needs to
819             // be deleted at the end
820             currentRelations.remove(relatedCluId);
821         } else if (NodeOperation.DELETE == operation
822                 && currentRelations.containsKey(relatedCluId))  {
823             // Delete the Format and its relation
824         	addDeleteRelationNodes(currentRelations, results);
825 
826             // remove this entry from the map so we can tell what needs to
827             // be deleted at the end
828             currentRelations.remove(relatedCluId);
829         }
830         
831         if(currentRelations != null && currentRelations.size() > 0){
832 	        for (Map.Entry<String, String> entry : currentRelations.entrySet()) {
833 	            // Create a new relation with the id of the relation we want to
834 	            // delete
835 	            CluCluRelationInfo relationToDelete = new CluCluRelationInfo();
836 	            relationToDelete.setId( entry.getValue() );
837 	            BaseDTOAssemblyNode<Object, CluCluRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<Object, CluCluRelationInfo>(
838 	                    null);
839 	            relationToDeleteNode.setNodeData(relationToDelete);
840 	            relationToDeleteNode.setOperation(NodeOperation.DELETE);
841 	            results.add(relationToDeleteNode);
842 	        }
843         }
844         return results;
845     }
846     public List<BaseDTOAssemblyNode<?, ?>> addAllRelationNodes(String cluId, String relatedCluId, String relationType, NodeOperation operation, Map<String, String> currentRelations)throws AssemblyException{
847     	List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
848 
849 		if (NodeOperation.CREATE == operation
850 		        || (NodeOperation.UPDATE == operation && !currentRelations.containsKey(relatedCluId) )) {
851 		    // the relation does not exist, so create
852 			addCreateRelationNode(cluId, relatedCluId, relationType, results);
853 		} else if (NodeOperation.UPDATE == operation
854 		        && currentRelations.containsKey(relatedCluId)) {
855 		    // If the relationship already exists update it
856 		
857 		    // remove this entry from the map so we can tell what needs to
858 		    // be deleted at the end
859 		    currentRelations.remove(relatedCluId);
860 		} else if (NodeOperation.DELETE == operation
861 		        && currentRelations.containsKey(relatedCluId))  {
862 		    // Delete the Format and its relation
863 			addDeleteRelationNodes(currentRelations, results);
864 		
865 		    // remove this entry from the map so we can tell what needs to
866 		    // be deleted at the end
867 		    currentRelations.remove(relatedCluId);
868 		}
869         
870         return results;
871     }
872     public Map<String, String> getCluCluRelations(String cluId, String relationType, ContextInfo contextInfo) throws AssemblyException, PermissionDeniedException{
873         Map<String, String> currentRelations = new HashMap<String, String>();
874 
875             try {
876                 List<CluCluRelationInfo> cluRelations = cluService.getCluCluRelationsByClu(cluId, contextInfo);
877                
878                 for (CluCluRelationInfo cluRelation : cluRelations) {
879                     if (relationType.equals(cluRelation.getTypeKey())) {
880                         currentRelations.put(cluRelation.getRelatedCluId(), cluRelation.getId());
881                     }
882                 }
883             } catch (DoesNotExistException e) {
884             } catch (InvalidParameterException e) {
885             } catch (MissingParameterException e) {
886             } catch (OperationFailedException e) {
887                 throw new AssemblyException("Error getting related clus", e);
888             }
889 
890             return currentRelations;
891     }
892     
893     public Map<String, CluCluRelationInfo> getCluCluActiveRelations(String cluId, String relationType, ContextInfo contextInfo) throws AssemblyException, PermissionDeniedException{
894         Map<String, CluCluRelationInfo> currentRelations = new HashMap<String, CluCluRelationInfo>();
895 
896             try {
897                 List<CluCluRelationInfo> cluRelations = cluService.getCluCluRelationsByClu(cluId,contextInfo);
898 
899                 for (CluCluRelationInfo cluRelation : cluRelations) {
900                     if (relationType.equals(cluRelation.getTypeKey()) && (!cluRelation.getStateKey().isEmpty() && cluRelation.getStateKey().equalsIgnoreCase(DtoConstants.STATE_ACTIVE))) {
901                         currentRelations.put(cluRelation.getRelatedCluId(), cluRelation);
902                     }
903                 }
904             } catch (DoesNotExistException e) {
905             } catch (InvalidParameterException e) {
906             } catch (MissingParameterException e) {
907             } catch (OperationFailedException e) {
908                 throw new AssemblyException("Error getting related clus", e);
909             }
910 
911             return currentRelations;
912     }
913 
914     public void addCreateRelationNode(String cluId, String relatedCluId, String relationType, List<BaseDTOAssemblyNode<?, ?>> results){
915         CluCluRelationInfo relation = new CluCluRelationInfo();
916         relation.setCluId(cluId);
917         relation.setRelatedCluId(relatedCluId);
918         relation.setTypeKey(relationType);
919         
920         // Relations can only be in state Active or Suspended
921         // DO NOT set state on relations to Draft, Approved, etc
922         // We will default to Active
923         relation.setStateKey(DtoConstants.STATE_ACTIVE);
924 
925         BaseDTOAssemblyNode<Object, CluCluRelationInfo> relationNode = new BaseDTOAssemblyNode<Object, CluCluRelationInfo>(
926                 null);
927         relationNode.setNodeData(relation);
928         relationNode.setOperation(NodeOperation.CREATE);
929 
930         results.add(relationNode);
931 
932     }
933 
934     public void addDeleteRelationNodes(Map<String, String> currentRelations, List<BaseDTOAssemblyNode<?, ?>> results){
935         for (Map.Entry<String, String> entry : currentRelations.entrySet()) {
936             // Create a new relation with the id of the relation we want to
937             // delete
938             CluCluRelationInfo relationToDelete = new CluCluRelationInfo();
939             relationToDelete.setId( entry.getValue() );
940             BaseDTOAssemblyNode<Object, CluCluRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<Object, CluCluRelationInfo>(
941                     null);
942             relationToDeleteNode.setNodeData(relationToDelete);
943             relationToDeleteNode.setOperation(NodeOperation.DELETE);
944             results.add(relationToDeleteNode);
945         }
946     }
947     
948     public void addSuspendedRelationNodes(Map<String, CluCluRelationInfo> currentRelations, List<BaseDTOAssemblyNode<?, ?>> results){
949         for (Map.Entry<String, CluCluRelationInfo> entry : currentRelations.entrySet()) {
950             CluCluRelationInfo suspendedRelation = new CluCluRelationInfo();
951             suspendedRelation = entry.getValue();
952             suspendedRelation.setStateKey(DtoConstants.STATE_SUSPENDED);
953             BaseDTOAssemblyNode<Object, CluCluRelationInfo> suspendedRelationNode = new BaseDTOAssemblyNode<Object, CluCluRelationInfo>(
954                     null);
955             suspendedRelationNode.setNodeData(suspendedRelation);
956             suspendedRelationNode.setOperation(NodeOperation.UPDATE);
957             results.add(suspendedRelationNode);
958         }
959     }
960 
961     private void addLuCodeFromProgram(String type, String value, List<LuCodeInfo> list) throws AssemblyException {
962 
963         if (value != null && !value.isEmpty()) {
964             LuCodeInfo code = new LuCodeInfo();
965             code.setType(type);
966             code.setValue(value);
967             code.setAttributes(new ArrayList<AttributeInfo>());
968             list.add(code);
969         }
970     }
971 
972     /**
973      * Copy publications from program to clu
974      *
975      * @param clu
976      * @param o
977      * @param operation
978      * @return
979      * @throws AssemblyException
980           */
981     private List<BaseDTOAssemblyNode<?, ?>> disassemblePublicationTargets(ProgramPublicationAssembly program,  NodeOperation operation, ContextInfo contextInfo) throws AssemblyException {
982 
983         List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
984 
985         Map<String, CluPublicationInfo> currentPubs = new HashMap<String, CluPublicationInfo>();
986         if (!NodeOperation.CREATE.equals(operation)) {
987 
988             // Get the current publications and put them in a map
989             try {
990                 List<CluPublicationInfo> cluPubs = cluService.getCluPublicationsByClu(program.getId(),contextInfo);
991                 for(CluPublicationInfo cluPub : cluPubs){
992                     cluPub.setStateKey(program.getStateKey());
993                     if (!cluPub.getTypeKey().equals(ProgramAssemblerConstants.CATALOG)) {
994                         currentPubs.put(cluPub.getTypeKey(), cluPub);                        
995                     }
996                 }
997             } catch (DoesNotExistException e) {
998             } catch (Exception e) {
999                 throw new AssemblyException("Error finding publications");
1000             }
1001         }
1002 
1003         if (program.getCatalogPublicationTargets() != null && !program.getCatalogPublicationTargets().isEmpty()) {
1004             for (String publicationType : program.getCatalogPublicationTargets()) {
1005                 //  If this is a create then create new publication
1006                 if (NodeOperation.CREATE == operation
1007                         || (NodeOperation.UPDATE == operation && !currentPubs.containsKey(publicationType) )) {
1008                     // the publication does not exist, so create
1009                     CluPublicationInfo pubInfo = buildCluPublicationInfo(program.getId(), publicationType);
1010                     
1011                     // Set the publication type state to match the program state.
1012                     pubInfo.setStateKey(program.getStateKey());
1013                     BaseDTOAssemblyNode<Object, CluPublicationInfo> pubNode = new BaseDTOAssemblyNode<Object, CluPublicationInfo>(
1014                             null);
1015                     pubNode.setNodeData(pubInfo);
1016                     pubNode.setOperation(NodeOperation.CREATE);
1017 
1018                     results.add(pubNode);
1019                 } else if (NodeOperation.UPDATE == operation
1020                         && currentPubs.containsKey(publicationType)) {
1021                     // Update the state of an existing pub info to the
1022                     // program state. To do this we need to remove the publication
1023                     // type and create a new node with the update operation
1024                     CluPublicationInfo pubInfo = currentPubs.remove(publicationType);
1025                     pubInfo.setStateKey(program.getStateKey());
1026                     BaseDTOAssemblyNode<Object, CluPublicationInfo> pubNode = new BaseDTOAssemblyNode<Object, CluPublicationInfo>(
1027                                null);
1028                     pubNode.setNodeData(pubInfo);
1029                     pubNode.setOperation(NodeOperation.UPDATE);
1030                     results.add(pubNode);
1031                  } else if (NodeOperation.DELETE == operation
1032                         && currentPubs.containsKey(publicationType))  {
1033 
1034                     CluPublicationInfo pubToDelete = new CluPublicationInfo();
1035                     pubToDelete.setId(publicationType);
1036                     BaseDTOAssemblyNode<Object, CluPublicationInfo> pubToDeleteNode = new BaseDTOAssemblyNode<Object, CluPublicationInfo>(
1037                             null);
1038                     pubToDeleteNode.setNodeData(pubToDelete);
1039                     pubToDeleteNode.setOperation(NodeOperation.DELETE);
1040                     results.add(pubToDeleteNode);
1041 
1042                     currentPubs.remove(publicationType);
1043                 }
1044             }
1045         }
1046 
1047 
1048         for (Map.Entry<String, CluPublicationInfo> entry : currentPubs.entrySet()) {
1049             // Create a new relation with the id of the relation we want to
1050             // delete
1051             deletePublicationInfo(results, entry.getValue());
1052         }
1053 
1054         return results;
1055     }
1056 
1057     private CluPublicationInfo buildCluPublicationInfo(String programId, String publicationType) throws AssemblyException {
1058 
1059         CluPublicationInfo pubInfo = new CluPublicationInfo();
1060         pubInfo.setTypeKey(publicationType);
1061         pubInfo.setCluId(programId);
1062 
1063         return pubInfo;
1064     }
1065 
1066     // Spring setters
1067     public void setCluService(CluService cluService) {
1068         this.cluService = cluService;
1069     }
1070 
1071     public void setCluAssemblerUtils(CluAssemblerUtils cluAssemblerUtils) {
1072         this.cluAssemblerUtils = cluAssemblerUtils;
1073     }
1074 
1075     public String getCredentialProgramID(String cluId, ContextInfo contextInfo) throws AssemblyException {
1076 
1077         List<String> credentialProgramIDs = null;
1078         try {
1079             credentialProgramIDs = cluService.getCluIdsByRelatedCluAndRelationType(cluId, ProgramAssemblerConstants.HAS_MAJOR_PROGRAM, contextInfo);
1080         } catch (Exception e) {
1081             throw new AssemblyException(e);
1082         }
1083         // Can a Program have more than one Credential Program?
1084         // TODO - do we need to validate that?
1085         if (null == credentialProgramIDs || credentialProgramIDs.isEmpty()) {
1086             throw new AssemblyException("Program with ID == " + cluId + " has no Credential Program associated with it.");
1087         } else if (credentialProgramIDs.size() > 1) {
1088             throw new AssemblyException("Program with ID == " + cluId + " has more than one Credential Program associated with it.");
1089         }
1090         return credentialProgramIDs.get(0);
1091     }
1092    
1093 }