Clover Coverage Report - KS LUM Impl 1.2-M3-SNAPSHOT
Coverage timestamp: Mon Jun 6 2011 06:44:48 EDT
../../../../../../../img/srcFileCovDistChart9.png 20% of files have more coverage
610   1,208   157   33.89
156   911   0.26   18
18     8.72  
1    
 
  CourseAssembler       Line # 75 610 0% 157 101 87.1% 0.87117344
 
  (14)
 
1    /*
2    * Copyright 2008 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 1.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl1.php
9    *
10    * Unless required by applicable law or agreed to in writing, software
11    * distributed under the License is distributed on an "AS IS" BASIS,
12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    * See the License for the specific language governing permissions and
14    * limitations under the License.
15    */
16    package org.kuali.student.lum.course.service.assembler;
17   
18    import java.util.ArrayList;
19    import java.util.Collections;
20    import java.util.Date;
21    import java.util.HashMap;
22    import java.util.HashSet;
23    import java.util.Iterator;
24    import java.util.List;
25    import java.util.Map;
26    import java.util.Map.Entry;
27    import java.util.Set;
28   
29    import org.apache.log4j.Logger;
30    import org.kuali.student.common.assembly.BOAssembler;
31    import org.kuali.student.common.assembly.BaseDTOAssemblyNode;
32    import org.kuali.student.common.assembly.BaseDTOAssemblyNode.NodeOperation;
33    import org.kuali.student.common.assembly.data.AssemblyException;
34    import org.kuali.student.common.dto.DtoConstants;
35    import org.kuali.student.common.dto.RichTextInfo;
36    import org.kuali.student.common.exceptions.DoesNotExistException;
37    import org.kuali.student.common.exceptions.InvalidParameterException;
38    import org.kuali.student.common.exceptions.MissingParameterException;
39    import org.kuali.student.common.exceptions.OperationFailedException;
40    import org.kuali.student.common.util.UUIDHelper;
41    import org.kuali.student.lum.course.dto.CourseCrossListingInfo;
42    import org.kuali.student.lum.course.dto.CourseExpenditureInfo;
43    import org.kuali.student.lum.course.dto.CourseFeeInfo;
44    import org.kuali.student.lum.course.dto.CourseInfo;
45    import org.kuali.student.lum.course.dto.CourseJointInfo;
46    import org.kuali.student.lum.course.dto.CourseRevenueInfo;
47    import org.kuali.student.lum.course.dto.CourseVariationInfo;
48    import org.kuali.student.lum.course.dto.FormatInfo;
49    import org.kuali.student.lum.course.dto.LoDisplayInfo;
50    import org.kuali.student.lum.lo.dto.LoInfo;
51    import org.kuali.student.lum.lo.service.LearningObjectiveService;
52    import org.kuali.student.lum.lrc.dto.ResultComponentInfo;
53    import org.kuali.student.lum.lrc.service.LrcService;
54    import org.kuali.student.lum.lu.dto.AdminOrgInfo;
55    import org.kuali.student.lum.lu.dto.CluAccountingInfo;
56    import org.kuali.student.lum.lu.dto.CluCluRelationInfo;
57    import org.kuali.student.lum.lu.dto.CluFeeInfo;
58    import org.kuali.student.lum.lu.dto.CluFeeRecordInfo;
59    import org.kuali.student.lum.lu.dto.CluIdentifierInfo;
60    import org.kuali.student.lum.lu.dto.CluInfo;
61    import org.kuali.student.lum.lu.dto.CluLoRelationInfo;
62    import org.kuali.student.lum.lu.dto.CluResultInfo;
63    import org.kuali.student.lum.lu.dto.LuCodeInfo;
64    import org.kuali.student.lum.lu.dto.ResultOptionInfo;
65    import org.kuali.student.lum.lu.service.LuService;
66    import org.kuali.student.lum.service.assembler.CluAssemblerUtils;
67    import org.springframework.util.StringUtils;
68    /**
69    * Assembler for CourseInfo. Provides assemble and disassemble operation on
70    * CourseInfo from/to CluInfo and other base DTOs
71    *
72    * @author Kuali Student Team
73    *
74    */
 
75    public class CourseAssembler implements BOAssembler<CourseInfo, CluInfo> {
76   
77    final static Logger LOG = Logger.getLogger(CourseAssembler.class);
78    private LuService luService;
79    private FormatAssembler formatAssembler;
80    private CourseJointAssembler courseJointAssembler;
81    private LoAssembler loAssembler;
82    private LearningObjectiveService loService;
83    private CluAssemblerUtils cluAssemblerUtils;
84    private LrcService lrcService;
85   
 
86  45 toggle @Override
87    public CourseInfo assemble(CluInfo clu, CourseInfo courseInfo,
88    boolean shallowBuild) throws AssemblyException {
89   
90  45 CourseInfo course = (null != courseInfo) ? courseInfo
91    : new CourseInfo();
92   
93    // Copy all the data from the clu to the course
94   
95  45 course.setAttributes(clu.getAttributes());
96  45 course.setCampusLocations(clu.getCampusLocations());
97  45 course.setCode(clu.getOfficialIdentifier().getCode());
98  45 course.setCourseNumberSuffix(clu.getOfficialIdentifier()
99    .getSuffixCode());
100  45 course.setLevel(clu.getOfficialIdentifier().getLevel());
101  45 course.setOutOfClassHours(clu.getIntensity());
102  45 course.setInstructors(clu.getInstructors());
103  45 course.setStartTerm(clu.getExpectedFirstAtp());
104  45 course.setEndTerm(clu.getLastAtp());
105  45 course.setCourseTitle(clu.getOfficialIdentifier().getLongName());
106   
107    // CrossListings
108  45 List<CourseCrossListingInfo> crossListings = assembleCrossListings(clu.getAlternateIdentifiers());
109  45 course.setCrossListings(crossListings);
110   
111    //Variation
112  45 List<CourseVariationInfo> variations = assembleVariations(clu.getAlternateIdentifiers());
113  45 course.setVariations(variations);
114   
115    // course.setDepartment(clu.getPrimaryAdminOrg().getOrgId());
116  45 if(course.getUnitsDeployment()==null){
117  0 course.setUnitsDeployment(new ArrayList<String>());
118    }
119  45 if(course.getUnitsContentOwner()==null){
120  0 course.setUnitsContentOwner(new ArrayList<String>());
121    }
122  45 List<String> courseAdminOrgs = new ArrayList<String>();
123  45 List<String> courseSubjectOrgs = new ArrayList<String>();
124  45 for(AdminOrgInfo adminOrg: clu.getAdminOrgs()){
125  178 if(adminOrg.getType().equals(CourseAssemblerConstants.ADMIN_ORG)){
126  90 courseAdminOrgs.add(adminOrg.getOrgId());
127    }
128  178 if(adminOrg.getType().equals(CourseAssemblerConstants.SUBJECT_ORG)){
129  88 courseSubjectOrgs.add(adminOrg.getOrgId());
130    }
131    }
132  45 course.setUnitsDeployment(courseAdminOrgs);
133  45 course.setUnitsContentOwner(courseSubjectOrgs);
134  45 course.setDescr(clu.getDescr());
135  45 course.setDuration(clu.getStdDuration());
136  45 course.setEffectiveDate(clu.getEffectiveDate());
137  45 course.setExpirationDate(clu.getExpirationDate());
138   
139    //Fees
140    //Fee justification
141  45 List<CourseFeeInfo> fees = new ArrayList<CourseFeeInfo>();
142  45 List<CourseRevenueInfo> revenues = new ArrayList<CourseRevenueInfo>();
143  45 if(clu.getFeeInfo() != null){
144  45 course.setFeeJustification(clu.getFeeInfo().getDescr());
145   
146    //Fees and revenues come from the same place but revenues have a special feeType
147  45 for(CluFeeRecordInfo cluFeeRecord: clu.getFeeInfo().getCluFeeRecords()){
148  178 String feeType = cluFeeRecord.getFeeType();
149  178 if(CourseAssemblerConstants.COURSE_FINANCIALS_REVENUE_TYPE.equals(feeType)){
150  90 CourseRevenueInfo courseRevenue = new CourseRevenueInfo();
151  90 courseRevenue.setFeeType(feeType);
152  90 courseRevenue.setAffiliatedOrgs(cluFeeRecord.getAffiliatedOrgs());
153  90 courseRevenue.setAttributes(cluFeeRecord.getAttributes());
154  90 courseRevenue.setId(cluFeeRecord.getId());
155  90 courseRevenue.setMetaInfo(cluFeeRecord.getMetaInfo());
156  90 revenues.add(courseRevenue);
157    }else{
158  88 CourseFeeInfo courseFee = new CourseFeeInfo();
159  88 courseFee.setFeeType(feeType);
160  88 courseFee.setRateType(cluFeeRecord.getRateType());
161  88 courseFee.setDescr(cluFeeRecord.getDescr());
162  88 courseFee.setMetaInfo(cluFeeRecord.getMetaInfo());
163  88 courseFee.setId(cluFeeRecord.getId());
164  88 courseFee.setFeeAmounts(cluFeeRecord.getFeeAmounts());
165  88 courseFee.setAttributes(cluFeeRecord.getAttributes());
166  88 fees.add(courseFee);
167    }
168    }
169    }
170  45 course.setFees(fees);
171  45 course.setRevenues(revenues);
172    //Expenditures are mapped from accounting info
173  45 if(course.getExpenditure() == null || clu.getAccountingInfo() == null){
174  14 course.setExpenditure(new CourseExpenditureInfo());
175    }
176  45 if(clu.getAccountingInfo() != null){
177  45 course.getExpenditure().setAffiliatedOrgs(clu.getAccountingInfo().getAffiliatedOrgs());
178    }
179   
180  45 course.setId(clu.getId());
181  45 course.setType(clu.getType());
182  45 course.setTermsOffered(clu.getOfferedAtpTypes());
183  45 course.setPrimaryInstructor(clu.getPrimaryInstructor());
184  45 course.setInstructors(clu.getInstructors());
185  45 course.setState(clu.getState());
186  45 course.setSubjectArea(clu.getOfficialIdentifier().getDivision());
187  45 course.setTranscriptTitle(clu.getOfficialIdentifier().getShortName());
188  45 course.setMetaInfo(clu.getMetaInfo());
189  45 course.setVersionInfo(clu.getVersionInfo());
190   
191   
192    //Special topics code
193  45 course.setSpecialTopicsCourse(false);
194  45 for(LuCodeInfo luCode : clu.getLuCodes()){
195  3 if(CourseAssemblerConstants.COURSE_CODE_SPECIAL_TOPICS.equals(luCode.getType())){
196  3 course.setSpecialTopicsCourse(Boolean.parseBoolean(luCode.getValue()));
197  3 break;
198    }
199    }
200    //Pilot Course code
201  45 course.setPilotCourse(false);
202  45 for(LuCodeInfo luCode : clu.getLuCodes()){
203  6 if(CourseAssemblerConstants.COURSE_CODE_PILOT_COURSE.equals(luCode.getType())){
204  3 course.setPilotCourse(Boolean.parseBoolean(luCode.getValue()));
205  3 break;
206    }
207    }
208   
209    // Don't make any changes to nested datastructures if this is
210  45 if (!shallowBuild) {
211  14 try {
212    // Use the luService to find Joints, then convert and add to the
213    // course
214  14 List<CluCluRelationInfo> cluClus = luService.getCluCluRelationsByClu(clu.getId());
215   
216  14 for (CluCluRelationInfo cluRel : cluClus) {
217  29 if (cluRel.getType().equals(CourseAssemblerConstants.JOINT_RELATION_TYPE)) {
218  0 CourseJointInfo jointInfo = null;
219  0 if(cluRel.getCluId().equals(clu.getId()))
220  0 jointInfo = courseJointAssembler.assemble(cluRel, cluRel.getRelatedCluId(), null, false);
221    else
222  0 jointInfo = courseJointAssembler.assemble(cluRel, cluRel.getCluId(), null, false);
223  0 course.getJoints().add(jointInfo);
224    }
225    }
226    } catch (DoesNotExistException e) {
227    } catch (Exception e) {
228  0 throw new AssemblyException("Error getting course joints", e);
229    }
230   
231  14 try {
232    // Use the luService to find formats, then convert and add to
233    // the course
234  14 List<CluInfo> formats = luService.getRelatedClusByCluId(course
235    .getId(),
236    CourseAssemblerConstants.COURSE_FORMAT_RELATION_TYPE);
237   
238  14 for (CluInfo format : formats) {
239  29 FormatInfo formatInfo = formatAssembler.assemble(format,
240    null, false);
241  29 course.getFormats().add(formatInfo);
242    }
243   
244    } catch (DoesNotExistException e) {
245    } catch (Exception e) {
246  0 throw new AssemblyException("Error getting related formats", e);
247    }
248   
249  14 try{
250    //Set Credit and Grading options
251  14 List<CluResultInfo> cluResults = luService.getCluResultByClu(course.getId());
252   
253  14 List<ResultComponentInfo> creditOptions = assembleCreditOptions(cluResults);
254  14 course.setCreditOptions(creditOptions);
255   
256  14 List<String> gradingOptions = assembleGradingOptions(cluResults);
257   
258  14 course.setGradingOptions(gradingOptions);
259    } catch (DoesNotExistException e){
260    } catch (Exception e) {
261  0 throw new AssemblyException("Error getting course results", e);
262    }
263   
264    //Learning Objectives
265  14 course.getCourseSpecificLOs().addAll(cluAssemblerUtils.assembleLos(course.getId(), shallowBuild));
266   
267    }
268   
269    //Remove special cases for grading options
270  45 course.getGradingOptions().remove(CourseAssemblerConstants.COURSE_RESULT_COMP_GRADE_AUDIT);
271   
272  45 return course;
273    }
274   
 
275  25 toggle @Override
276    public BaseDTOAssemblyNode<CourseInfo, CluInfo> disassemble(
277    CourseInfo course, NodeOperation operation)
278    throws AssemblyException {
279   
280  25 if (course == null) {
281    // FIXME Unsure now if this is an exception or just return null or
282    // empty assemblyNode
283  0 LOG.error("Course to disassemble is null!");
284  0 throw new AssemblyException("Course can not be null");
285    }
286   
287  25 BaseDTOAssemblyNode<CourseInfo, CluInfo> result = new BaseDTOAssemblyNode<CourseInfo, CluInfo>(
288    this);
289   
290  25 CluInfo clu;
291  25 try {
292  25 clu = (NodeOperation.UPDATE == operation) ? luService.getClu(course.getId()) : new CluInfo();
293    } catch (Exception e) {
294  0 throw new AssemblyException("Error getting existing learning unit during course update", e);
295    }
296   
297    // Create the id if it's not there already(important for creating
298    // relations)
299  25 clu.setId(UUIDHelper.genStringUUID(course.getId()));
300  25 if (null == course.getId()) {
301  14 course.setId(clu.getId());
302    }
303  25 clu.setType(CourseAssemblerConstants.COURSE_TYPE);
304  25 clu.setState(course.getState());
305   
306  25 CluIdentifierInfo identifier = new CluIdentifierInfo();
307  25 identifier.setType(CourseAssemblerConstants.COURSE_OFFICIAL_IDENT_TYPE);
308  25 identifier.setState(course.getState());
309  25 identifier.setLongName(course.getCourseTitle());
310  25 identifier.setShortName(course.getTranscriptTitle());
311  25 identifier.setSuffixCode(course.getCourseNumberSuffix());
312  25 identifier.setDivision(course.getSubjectArea());
313  25 identifier.setCode(course.getCode());
314   
315    //Custom logic to set the level, if level not provided
316  25 if(StringUtils.hasText(course.getLevel())) {
317  25 identifier.setLevel(course.getLevel());
318  0 } else if(course.getCourseNumberSuffix()!=null&&course.getCourseNumberSuffix().length()>=3){
319  0 identifier.setLevel(course.getCourseNumberSuffix().substring(0, 1)+"00");
320    }
321   
322  25 clu.setOfficialIdentifier(identifier);
323   
324  25 clu.setAdminOrgs(new ArrayList<AdminOrgInfo>());
325   
326    // Use the Course Variation assembler to disassemble the variations
327   
328    // copy all fields
329    //Remove any existing variations or crosslistings
330  45 for(Iterator<CluIdentifierInfo> iter = clu.getAlternateIdentifiers().iterator();iter.hasNext();){
331  20 CluIdentifierInfo cluIdentifier = iter.next();
332  20 if(CourseAssemblerConstants.COURSE_VARIATION_IDENT_TYPE.equals(cluIdentifier.getType()) ||
333    CourseAssemblerConstants.COURSE_CROSSLISTING_IDENT_TYPE.equals(cluIdentifier.getType()) ){
334  20 iter.remove();
335    }
336    }
337    //Add in variations
338  25 for(CourseVariationInfo variation:course.getVariations()){
339  50 CluIdentifierInfo cluIdentifier = new CluIdentifierInfo();
340  50 cluIdentifier.setId(variation.getId());
341  50 cluIdentifier.setType(CourseAssemblerConstants.COURSE_VARIATION_IDENT_TYPE);
342  50 cluIdentifier.setCode(identifier.getCode());
343  50 cluIdentifier.setSuffixCode(course.getCourseNumberSuffix());
344  50 cluIdentifier.setDivision(course.getSubjectArea());
345  50 cluIdentifier.setVariation(variation.getVariationCode());
346  50 cluIdentifier.setLongName(variation.getVariationTitle());
347  50 cluIdentifier.setState(course.getState());
348  50 clu.getAlternateIdentifiers().add(cluIdentifier);
349    }
350    //Add in crosslistings
351  25 for(CourseCrossListingInfo crossListing:course.getCrossListings()){
352  2 CluIdentifierInfo cluIdentifier = new CluIdentifierInfo();
353  2 cluIdentifier.setId(crossListing.getId());
354  2 cluIdentifier.setType(CourseAssemblerConstants.COURSE_CROSSLISTING_IDENT_TYPE);
355  2 cluIdentifier.setSuffixCode(crossListing.getCourseNumberSuffix());
356  2 cluIdentifier.setDivision(crossListing.getSubjectArea());
357  2 cluIdentifier.setState(course.getState());
358  2 cluIdentifier.setOrgId(crossListing.getDepartment());
359  2 cluIdentifier.setAttributes(crossListing.getAttributes());
360  2 cluIdentifier.setCode(crossListing.getCode());
361  2 clu.getAlternateIdentifiers().add(cluIdentifier);
362    }
363   
364  25 List<AdminOrgInfo> adminOrgInfos = new ArrayList<AdminOrgInfo>();
365  25 for(String org:course.getUnitsDeployment()){
366  50 AdminOrgInfo adminOrg = new AdminOrgInfo();
367  50 adminOrg.setType(CourseAssemblerConstants.ADMIN_ORG);
368  50 adminOrg.setOrgId(org);
369  50 adminOrgInfos.add(adminOrg);
370    }
371  25 clu.getAdminOrgs().addAll(adminOrgInfos);
372   
373  25 List<AdminOrgInfo> subjectOrgs = new ArrayList<AdminOrgInfo>();
374  25 for (String subOrg : course.getUnitsContentOwner()) {
375  48 AdminOrgInfo subjectOrg = new AdminOrgInfo();
376  48 subjectOrg.setType(CourseAssemblerConstants.SUBJECT_ORG);
377  48 subjectOrg.setOrgId(subOrg);
378  48 subjectOrgs.add(subjectOrg);
379    }
380  25 clu.getAdminOrgs().addAll(subjectOrgs);
381   
382   
383  25 clu.setAttributes(course.getAttributes());
384  25 clu.setCampusLocations(course.getCampusLocations());
385  25 clu.setDescr(course.getDescr());
386  25 clu.setStdDuration(course.getDuration());
387  25 clu.setEffectiveDate(course.getEffectiveDate());
388  25 clu.setExpirationDate(course.getExpirationDate());
389   
390  25 clu.setOfferedAtpTypes(course.getTermsOffered());
391  25 clu.setPrimaryInstructor(course.getPrimaryInstructor());
392   
393  25 clu.setIntensity(course.getOutOfClassHours());
394  25 clu.setInstructors(course.getInstructors());
395   
396  25 clu.setExpectedFirstAtp(course.getStartTerm());
397  25 clu.setLastAtp(course.getEndTerm());
398   
399  25 clu.setMetaInfo(course.getMetaInfo());
400  25 clu.setVersionInfo(course.getVersionInfo());
401   
402    // Add the Clu to the result
403  25 result.setNodeData(clu);
404  25 result.setOperation(operation);
405  25 result.setBusinessDTORef(course);
406   
407    // Use the Format assembler to disassemble the formats and relations
408  25 List<BaseDTOAssemblyNode<?, ?>> formatResults;
409  25 try {
410  25 formatResults = disassembleFormats(clu
411    .getId(), course, operation);
412  25 result.getChildNodes().addAll(formatResults);
413   
414    } catch (DoesNotExistException e) {
415    } catch (Exception e) {
416  0 throw new AssemblyException("Error while disassembling format", e);
417    }
418   
419    // Use the CourseJoint assembler to disassemble the CourseJoints and
420    // relations
421  25 List<BaseDTOAssemblyNode<?, ?>> courseJointResults = disassembleJoints(
422    clu.getId(), course, operation);
423  25 result.getChildNodes().addAll(courseJointResults);
424   
425    //Disassemble the CluResults (grading and credit options)
426    //Special code to take audit from attributes and put into options
427  25 if(course.getAttributes().containsKey(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_AUDIT)&&"true".equals(course.getAttributes().get(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_AUDIT))){
428  0 if(!course.getGradingOptions().contains(CourseAssemblerConstants.COURSE_RESULT_COMP_GRADE_AUDIT)){
429  0 course.getGradingOptions().add(CourseAssemblerConstants.COURSE_RESULT_COMP_GRADE_AUDIT);
430    }
431    }
432   
433  25 List<CluResultInfo> cluResultList;
434  25 try {
435  25 cluResultList = luService.getCluResultByClu(clu.getId());
436    } catch (DoesNotExistException e) {
437  0 cluResultList = Collections.emptyList();
438    } catch (Exception e) {
439  0 throw new AssemblyException("Error getting cluResults", e);
440    }
441   
442  25 List<BaseDTOAssemblyNode<?, ?>> creditOutcomes = disassembleCreditOutcomes(course, clu, cluResultList, operation);
443  25 result.getChildNodes().addAll(creditOutcomes);
444   
445  25 BaseDTOAssemblyNode<?, ?> gradingOptions = disassembleGradingOptions(
446    clu.getId(), course.getState(), course.getGradingOptions(), cluResultList, operation);
447  25 result.getChildNodes().add(gradingOptions);
448   
449    //Use the LoAssembler to disassemble Los
450  25 try {
451  25 List<BaseDTOAssemblyNode<?, ?>> loResults;
452  25 loResults = disassembleLos(clu.getId(), course, operation);
453  25 result.getChildNodes().addAll(loResults);
454    } catch (Exception e) {
455  0 throw new AssemblyException("Error while disassembling los", e);
456    }
457   
458    //add the special topics code if it did not exist, or remove if it was not wanted
459  25 boolean alreadyHadSpecialTopicsCode = false;
460  25 for(Iterator<LuCodeInfo> luCodeIterator = clu.getLuCodes().iterator();luCodeIterator.hasNext();){
461  1 LuCodeInfo luCode = luCodeIterator.next();
462  1 if(CourseAssemblerConstants.COURSE_CODE_SPECIAL_TOPICS.equals(luCode.getType())){
463  1 alreadyHadSpecialTopicsCode = true;
464  1 if(!course.isSpecialTopicsCourse()){
465  1 luCodeIterator.remove();
466    }
467  1 break;
468    }
469    }
470  25 if(!alreadyHadSpecialTopicsCode && course.isSpecialTopicsCourse()){
471  2 LuCodeInfo luCode = new LuCodeInfo();
472  2 luCode.setType(CourseAssemblerConstants.COURSE_CODE_SPECIAL_TOPICS);
473  2 luCode.setValue("true");
474  2 clu.getLuCodes().add(luCode);
475    }
476   
477    //add the special topics code if it did not exist, or remove if it was not wanted
478  25 boolean alreadyHadPilotCourseCode = false;
479  27 for(Iterator<LuCodeInfo> luCodeIterator = clu.getLuCodes().iterator();luCodeIterator.hasNext();){
480  3 LuCodeInfo luCode = luCodeIterator.next();
481  3 if(CourseAssemblerConstants.COURSE_CODE_PILOT_COURSE.equals(luCode.getType())){
482  1 alreadyHadPilotCourseCode = true;
483  1 if(!course.isPilotCourse()){
484  1 luCodeIterator.remove();
485    }
486  1 break;
487    }
488    }
489  25 if(!alreadyHadPilotCourseCode && course.isPilotCourse()){
490  2 LuCodeInfo luCode = new LuCodeInfo();
491  2 luCode.setType(CourseAssemblerConstants.COURSE_CODE_PILOT_COURSE);
492  2 luCode.setValue("true");
493  2 clu.getLuCodes().add(luCode);
494    }
495   
496    //FEES
497  25 if(clu.getFeeInfo() == null){
498  15 clu.setFeeInfo(new CluFeeInfo());
499    }
500  25 clu.getFeeInfo().setDescr(course.getFeeJustification());
501  25 clu.getFeeInfo().getCluFeeRecords().clear();
502  25 for(CourseRevenueInfo courseRevenue:course.getRevenues()){
503  50 CluFeeRecordInfo cluFeeRecord = new CluFeeRecordInfo();
504  50 cluFeeRecord.setFeeType(CourseAssemblerConstants.COURSE_FINANCIALS_REVENUE_TYPE);
505  50 cluFeeRecord.setRateType(CourseAssemblerConstants.COURSE_FINANCIALS_REVENUE_TYPE);
506  50 cluFeeRecord.setAttributes(courseRevenue.getAttributes());
507  50 cluFeeRecord.setAffiliatedOrgs(courseRevenue.getAffiliatedOrgs());
508  50 cluFeeRecord.setId(courseRevenue.getId());
509  50 cluFeeRecord.setMetaInfo(courseRevenue.getMetaInfo());
510  50 clu.getFeeInfo().getCluFeeRecords().add(cluFeeRecord);
511    }
512  25 for(CourseFeeInfo courseFee : course.getFees()){
513  48 CluFeeRecordInfo cluFeeRecord = new CluFeeRecordInfo();
514  48 cluFeeRecord.setFeeType(courseFee.getFeeType());
515  48 cluFeeRecord.setRateType(courseFee.getRateType());
516  48 cluFeeRecord.setDescr(courseFee.getDescr());
517  48 cluFeeRecord.setMetaInfo(courseFee.getMetaInfo());
518  48 cluFeeRecord.setId(courseFee.getId());
519  48 cluFeeRecord.setFeeAmounts(courseFee.getFeeAmounts());
520  48 cluFeeRecord.setAttributes(courseFee.getAttributes());
521  48 clu.getFeeInfo().getCluFeeRecords().add(cluFeeRecord);
522    }
523  25 if(clu.getAccountingInfo() == null || course.getExpenditure()== null){
524  15 clu.setAccountingInfo( new CluAccountingInfo());
525    }
526  25 if(course.getExpenditure() != null){
527  25 clu.getAccountingInfo().setAffiliatedOrgs(course.getExpenditure().getAffiliatedOrgs());
528  25 clu.getAccountingInfo().setAttributes(course.getExpenditure().getAttributes());
529    }
530   
531  25 return result;
532    }
533   
 
534  25 toggle private List<BaseDTOAssemblyNode<?, ?>> disassembleCreditOutcomes(CourseInfo course, CluInfo clu, List<CluResultInfo> currentCluResults, NodeOperation operation) throws AssemblyException, NumberFormatException {
535   
536  25 List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
537   
538  25 String courseResultType = CourseAssemblerConstants.COURSE_RESULT_TYPE_CREDITS;
539   
540    //See if we need to create any new lrcs
541  25 if(NodeOperation.DELETE!=operation){
542    //Find all the existing LRCs for the following three types
543  24 Set<String> rsltComps = new HashSet<String>();
544   
545  24 try{
546  24 try {
547  24 rsltComps.addAll(lrcService.getResultComponentIdsByResultComponentType(CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_FIXED));
548    } catch (DoesNotExistException e) {}
549  24 try {
550  24 rsltComps.addAll(lrcService.getResultComponentIdsByResultComponentType(CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_MULTIPLE));
551    } catch (DoesNotExistException e) {}
552  24 try {
553  24 rsltComps.addAll(lrcService.getResultComponentIdsByResultComponentType(CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_VARIABLE));
554    } catch (DoesNotExistException e) {}
555   
556    //Create any LRCs that do not yet exist
557  24 for(ResultComponentInfo creditOption:course.getCreditOptions()){
558  49 String id = null;
559  49 String type = null;
560  49 List<String> resultValues = null;
561  49 Map<String,String> attributes = null;
562    //Depending on the type, set the id, type and result values differently
563  49 if(CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_FIXED.equals(creditOption.getType())){
564  44 float fixedCreditValue = Float.parseFloat(creditOption.getAttributes().get(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_FIXED_CREDIT_VALUE));
565  44 id = CourseAssemblerConstants.COURSE_RESULT_COMP_CREDIT_PREFIX + fixedCreditValue;
566  44 type = CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_FIXED;
567  44 resultValues = new ArrayList<String>();
568  44 resultValues.add(String.valueOf(fixedCreditValue));
569  44 attributes = new HashMap<String,String>();
570  44 attributes.put(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_FIXED_CREDIT_VALUE, String.valueOf(fixedCreditValue));
571  5 }else if(CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_MULTIPLE.equals(creditOption.getType())){
572  3 Collections.sort(creditOption.getResultValues());
573  3 StringBuilder sb = new StringBuilder(CourseAssemblerConstants.COURSE_RESULT_COMP_CREDIT_PREFIX);
574  10 for(Iterator<String> iter = creditOption.getResultValues().iterator();iter.hasNext();){
575  7 sb.append(iter.next());
576  7 if(iter.hasNext()){
577  4 sb.append(",");
578    }
579    }
580  3 id = sb.toString();
581  3 type = CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_MULTIPLE;
582  3 resultValues = creditOption.getResultValues();
583  2 }else if(CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_VARIABLE.equals(creditOption.getType())){
584    /*
585    * For variable credits create a Result values that goes from min to max with the specified increment.
586    * If no increment is specified, use 1.0 as the increment. The increment can be specified as a float.
587    */
588   
589  2 String minCreditValue = creditOption.getAttributes().get(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_MIN_CREDIT_VALUE);
590  2 String maxCreditValue = creditOption.getAttributes().get(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_MAX_CREDIT_VALUE);
591  2 String creditValueIncr = creditOption.getAttributes().get(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_CREDIT_VALUE_INCR);
592  2 float minCredits = Float.parseFloat(minCreditValue);
593  2 float maxCredits = Float.parseFloat(maxCreditValue);
594   
595  2 float increment = (null != creditValueIncr && creditValueIncr.length() > 0 ) ? Float.parseFloat(creditValueIncr) : 1.0f ;
596   
597  2 id = CourseAssemblerConstants.COURSE_RESULT_COMP_CREDIT_PREFIX + minCreditValue + "-" + maxCreditValue;
598  2 type = CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_VARIABLE;
599  2 resultValues = new ArrayList<String>();
600  16 for(float i = minCredits; i <= maxCredits; i+=increment){
601  14 resultValues.add(String.valueOf(i));
602    }
603  2 attributes = new HashMap<String,String>();
604  2 attributes.put(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_MIN_CREDIT_VALUE, minCreditValue);
605  2 attributes.put(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_MAX_CREDIT_VALUE, maxCreditValue);
606  2 attributes.put(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_CREDIT_VALUE_INCR, creditValueIncr);
607    }
608   
609    //Set the id
610  49 creditOption.setId(id);
611   
612    //Create a new result component
613  49 if(id != null && !rsltComps.contains(id)){
614   
615    //need to make a fixed degree result type component
616  4 ResultComponentInfo resultComponent = new ResultComponentInfo();
617  4 resultComponent.setId(id);
618  4 resultComponent.setType(type);
619  4 resultComponent.setState (course.getState());
620  4 resultComponent.setResultValues(resultValues);
621  4 resultComponent.setAttributes(attributes);
622  4 BaseDTOAssemblyNode<ResultComponentInfo, ResultComponentInfo> node = new BaseDTOAssemblyNode<ResultComponentInfo, ResultComponentInfo>(null);
623  4 node.setOperation(NodeOperation.CREATE);
624  4 node.setNodeData(resultComponent);
625  4 node.setBusinessDTORef(creditOption);
626  4 results.add(node);
627   
628  4 rsltComps.add(id);
629    }
630    }
631    }catch (NumberFormatException e){
632  0 throw new AssemblyException("Invalid Arguments for credit outcome values",e);
633    }catch (Exception e){
634  0 throw new AssemblyException("Error Assembling", e);
635    }
636    }
637   
638    //Now do dissassembly for the actual clu-lrc relations and result options
639   
640    // Get the current options and put them in a map of option type id/cluResult
641  25 Map<String, List<CluResultInfo>> currentResults = new HashMap<String, List<CluResultInfo>>();
642   
643    //If this is not a create, lookup the results for this clu
644  25 if (!NodeOperation.CREATE.equals(operation)) {
645  11 for (CluResultInfo currentResult : currentCluResults) {
646  9 if (courseResultType.equals(currentResult.getType())) {
647    //There should only be one grading option per CluResult for credit outcomes
648  6 if(currentResult.getResultOptions().size()==1){
649    //Create a mapping to a list of cluresults with the same result componentId
650  6 String resultComponentId = currentResult.getResultOptions().get(0).getResultComponentId();
651  6 if(!currentResults.containsKey(resultComponentId)){
652  4 currentResults.put(resultComponentId, new ArrayList<CluResultInfo>());
653    }
654  6 currentResults.get(resultComponentId).add(currentResult);
655    }else{
656  0 LOG.warn("Credit Results should have exactly one result option each");
657    }
658    }
659    }
660    }
661   
662    //Loop through options on the course, if they are new, create a new cluResult
663  25 for(ResultComponentInfo creditOption : course.getCreditOptions()){
664  51 if (NodeOperation.CREATE == operation
665    || (NodeOperation.UPDATE == operation && !currentResults.containsKey(creditOption.getId()) )) {
666   
667  46 ResultOptionInfo resultOption = new ResultOptionInfo();
668  46 resultOption.setState(course.getState());
669  46 resultOption.setResultComponentId(creditOption.getId());
670   
671  46 CluResultInfo cluResult = new CluResultInfo();
672  46 cluResult.setCluId(clu.getId());
673  46 cluResult.setState(course.getState());
674  46 cluResult.setType(courseResultType);
675   
676  46 cluResult.getResultOptions().add(resultOption);
677   
678  46 BaseDTOAssemblyNode<ResultComponentInfo, CluResultInfo> cluResultNode = new BaseDTOAssemblyNode<ResultComponentInfo, CluResultInfo>(null);
679  46 cluResultNode.setNodeData(cluResult);
680  46 cluResultNode.setOperation(NodeOperation.CREATE);
681   
682  46 results.add(cluResultNode);
683  5 } else if (NodeOperation.UPDATE == operation
684    && currentResults.containsKey(creditOption.getId())) {
685    //Get the list from the map and remove an entry, if the list is empty then remove it from the map
686  3 List<CluResultInfo> cluResults = currentResults.get(creditOption.getId());
687  3 cluResults.remove(cluResults.size()-1);
688  3 if(cluResults.isEmpty()){
689  2 currentResults.remove(creditOption.getId());
690    }
691    }
692    }
693   
694    //Delete the leftovers
695  25 for(Entry<String,List<CluResultInfo>> entry:currentResults.entrySet()){
696  2 for(CluResultInfo cluResult:entry.getValue()){
697  3 BaseDTOAssemblyNode<ResultComponentInfo, CluResultInfo> cluResultNode = new BaseDTOAssemblyNode<ResultComponentInfo, CluResultInfo>(null);
698  3 cluResultNode.setNodeData(cluResult);
699  3 cluResultNode.setOperation(NodeOperation.DELETE);
700  3 results.add(cluResultNode);
701    }
702    }
703   
704  25 return results;
705    }
706   
 
707  14 toggle private List<String> assembleGradingOptions(List<CluResultInfo> cluResults){
708   
709  14 String courseResultType = CourseAssemblerConstants.COURSE_RESULT_TYPE_GRADE;
710   
711  14 List<String> results = new ArrayList<String>();
712    //Loop through all the CluResults to find the one with the matching type
713  14 for(CluResultInfo cluResult:cluResults){
714  42 if(courseResultType.equals(cluResult.getType())){
715    //Loop through all options and add to the list of Strings
716  14 for(ResultOptionInfo resultOption: cluResult.getResultOptions()){
717  28 results.add(resultOption.getResultComponentId());
718    }
719  14 break;
720    }
721    }
722  14 return results;
723    }
724   
 
725  14 toggle private List<ResultComponentInfo> assembleCreditOptions(
726    List<CluResultInfo> cluResults) throws AssemblyException {
727  14 String courseResultType = CourseAssemblerConstants.COURSE_RESULT_TYPE_CREDITS;
728  14 List<ResultComponentInfo> results = new ArrayList<ResultComponentInfo>();
729    //Loop through all the CluResults to find the one with the matching type
730  14 for(CluResultInfo cluResult:cluResults){
731  43 if(courseResultType.equals(cluResult.getType())){
732    //Loop through all options and add to the list of Strings
733  29 for(ResultOptionInfo resultOption: cluResult.getResultOptions()){
734  29 try {
735  29 ResultComponentInfo resultComponent = lrcService.getResultComponent(resultOption.getResultComponentId());
736  29 results.add(resultComponent);
737    } catch (DoesNotExistException e) {
738  0 LOG.warn("Course Credit option:"+resultOption.getId()+" refers to non-existant ResultComponentInfo "+resultOption.getResultComponentId());
739    } catch (Exception e) {
740  0 throw new AssemblyException("Error getting result components",e);
741    }
742    }
743    }
744    }
745  14 return results;
746    }
747   
748    // TODO Use CluAssemblerUtils
 
749  25 toggle private List<BaseDTOAssemblyNode<?, ?>> disassembleLos(String cluId,
750    CourseInfo course, NodeOperation operation) throws AssemblyException {
751    // TODO Auto-generated method stub
752  25 List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
753   
754    // Get the current formats and put them in a map of format id/relation
755    // id
756  25 Map<String, CluLoRelationInfo> currentCluLoRelations = new HashMap<String, CluLoRelationInfo>();
757  25 try {
758  25 List<CluLoRelationInfo> cluLoRelations = luService.getCluLoRelationsByClu(cluId);
759  25 for(CluLoRelationInfo cluLoRelation:cluLoRelations){
760  6 if(CourseAssemblerConstants.COURSE_LO_COURSE_SPECIFIC_RELATION.equals(cluLoRelation.getType())){
761  6 currentCluLoRelations.put(cluLoRelation.getLoId(), cluLoRelation);
762    }
763    }
764    } catch (DoesNotExistException e) {
765    } catch (Exception e) {
766  0 throw new AssemblyException("Error finding related Los");
767    }
768   
769    // Loop through all the los in this clu
770  25 for(LoDisplayInfo loDisplay : course.getCourseSpecificLOs()){
771   
772    // If this is a clu create/new lo update then all los will be created
773  50 if (NodeOperation.CREATE == operation
774    || (NodeOperation.UPDATE == operation && !currentCluLoRelations.containsKey(loDisplay.getLoInfo().getId()))) {
775   
776    // the lo does not exist, so create
777    // Assemble and add the lo
778  45 loDisplay.getLoInfo().setId(null);
779  45 loDisplay.getLoInfo().setState(course.getState());
780  45 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = loAssembler
781    .disassemble(loDisplay, NodeOperation.CREATE);
782  45 results.add(loNode);
783   
784    // Create the relationship and add it as well
785  45 CluLoRelationInfo relation = new CluLoRelationInfo();
786  45 relation.setCluId(cluId);
787  45 relation.setLoId(loNode.getNodeData().getId());
788  45 relation
789    .setType(CourseAssemblerConstants.COURSE_LO_COURSE_SPECIFIC_RELATION);
790  45 relation.setState(course.getState());
791   
792  45 BaseDTOAssemblyNode<LoDisplayInfo, CluLoRelationInfo> relationNode = new BaseDTOAssemblyNode<LoDisplayInfo, CluLoRelationInfo>(
793    null);
794  45 relationNode.setNodeData(relation);
795  45 relationNode.setOperation(NodeOperation.CREATE);
796   
797  45 results.add(relationNode);
798  5 } else if (NodeOperation.UPDATE == operation
799    && currentCluLoRelations.containsKey(loDisplay.getLoInfo().getId())) {
800  3 loDisplay.getLoInfo().setState(course.getState());
801    // If the clu already has this lo, then just update the lo
802  3 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = loAssembler
803    .disassemble(loDisplay, NodeOperation.UPDATE);
804  3 results.add(loNode);
805   
806    // remove this entry from the map so we can tell what needs to
807    // be deleted at the end
808  3 currentCluLoRelations.remove(loDisplay.getLoInfo().getId());
809  2 } else if (NodeOperation.DELETE == operation
810    && currentCluLoRelations.containsKey(loDisplay.getLoInfo().getId())) {
811   
812    // Delete the Format and its relation
813  2 CluLoRelationInfo relationToDelete = currentCluLoRelations.get(loDisplay.getLoInfo().getId());
814  2 BaseDTOAssemblyNode<LoDisplayInfo, CluLoRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<LoDisplayInfo, CluLoRelationInfo>(
815    null);
816  2 relationToDeleteNode.setNodeData(relationToDelete);
817  2 relationToDeleteNode.setOperation(NodeOperation.DELETE);
818  2 results.add(relationToDeleteNode);
819   
820  2 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = loAssembler
821    .disassemble(loDisplay, NodeOperation.DELETE);
822  2 results.add(loNode);
823   
824    // remove this entry from the map so we can tell what needs to
825    // be deleted at the end
826  2 currentCluLoRelations.remove(loDisplay.getLoInfo().getId());
827    }
828    }
829   
830    // Now any leftover lo ids are no longer needed, so delete
831    // los and relations
832  25 for (Entry<String, CluLoRelationInfo> entry : currentCluLoRelations.entrySet()) {
833    // Create a new relation with the id of the relation we want to
834    // delete
835  1 CluLoRelationInfo relationToDelete = entry.getValue();
836  1 BaseDTOAssemblyNode<LoDisplayInfo, CluLoRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<LoDisplayInfo, CluLoRelationInfo>(
837    null);
838  1 relationToDeleteNode.setNodeData(relationToDelete);
839  1 relationToDeleteNode.setOperation(NodeOperation.DELETE);
840  1 results.add(relationToDeleteNode);
841   
842  1 try{
843  1 LoInfo loToDelete = loService.getLo(entry.getKey());
844   
845  1 LoDisplayInfo loDisplayToDelete = loAssembler.assemble(loToDelete, null, false);
846  1 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = loAssembler
847    .disassemble(loDisplayToDelete, NodeOperation.DELETE);
848  1 results.add(loNode);
849    } catch (DoesNotExistException e){
850  0 LOG.warn("Trying to delete non exsistant LO:"+entry.getKey());
851    } catch (Exception e) {
852  0 throw new AssemblyException("Error disassembling LOs",e);
853    }
854    }
855   
856  25 return results;
857    }
858   
 
859  25 toggle private BaseDTOAssemblyNode<?, ?> disassembleGradingOptions(String cluId,
860    String courseState, List<String> options, List<CluResultInfo> currentCluResults, NodeOperation operation) throws AssemblyException {
861  25 BaseDTOAssemblyNode<List<String>, CluResultInfo> cluResultNode = new BaseDTOAssemblyNode<List<String>, CluResultInfo>(null);
862   
863  25 String courseResultType=CourseAssemblerConstants.COURSE_RESULT_TYPE_GRADE;
864  25 String resultsDescription="Grading options";
865  25 String resultDescription="Grading option";
866   
867    // Get the current options and put them in a map of option type id/cluResult
868  25 Map<String, ResultOptionInfo> currentResults = new HashMap<String, ResultOptionInfo>();
869   
870  25 CluResultInfo cluResult = null;
871   
872    //If this is not a create, lookup the results for this clu
873  25 if (!NodeOperation.CREATE.equals(operation)) {
874  11 for (CluResultInfo currentResult : currentCluResults) {
875  8 if (courseResultType.equals(currentResult.getType())) {
876  3 cluResult = currentResult;
877  3 if(NodeOperation.DELETE.equals(operation)){
878    //if this is a delete, then we only need the CluResultInfo
879  1 cluResultNode.setOperation(NodeOperation.DELETE);
880    }else{
881    //Find all the Result options and store in a map for easy access later
882  2 cluResultNode.setOperation(NodeOperation.UPDATE);
883  2 for(ResultOptionInfo resultOption:currentResult.getResultOptions()){
884  4 currentResults.put(resultOption.getResultComponentId(), resultOption);
885    }
886    }
887  3 break;
888    }
889    }
890    }
891   
892    //If this is a delete we don't need the result options, just the CluResultInfo
893  25 if(!NodeOperation.DELETE.equals(operation)){
894  24 if(cluResult == null){
895    //Create a new resultInfo of the given type if one does not exist and set operation to Create
896  22 cluResult = new CluResultInfo();
897  22 cluResult.setCluId(cluId);
898  22 cluResult.setState(courseState);
899  22 cluResult.setType(courseResultType);
900  22 RichTextInfo desc = new RichTextInfo();
901  22 desc.setPlain(resultsDescription);
902  22 cluResult.setDesc(desc);
903  22 cluResult.setEffectiveDate(new Date());
904  22 cluResultNode.setOperation(NodeOperation.CREATE);
905    }
906   
907  24 cluResult.setResultOptions(new ArrayList<ResultOptionInfo>());
908   
909    // Loop through all the credit options in this course
910  24 for (String optionType : options) {
911  48 if(currentResults.containsKey(optionType)){
912    //If the option exists already copy it to the new list of result options
913  3 ResultOptionInfo resultOptionInfo = currentResults.get(optionType);
914  3 cluResult.getResultOptions().add(resultOptionInfo);
915    }else{
916    //Otherwise create a new result option
917  45 ResultOptionInfo resultOptionInfo = new ResultOptionInfo();
918  45 RichTextInfo desc = new RichTextInfo();
919  45 desc.setPlain(resultDescription);
920  45 resultOptionInfo.setDesc(desc);
921  45 resultOptionInfo.setResultComponentId(optionType);
922  45 resultOptionInfo.setState(courseState);
923   
924  45 cluResult.getResultOptions().add(resultOptionInfo);
925    }
926    }
927    }
928   
929  25 cluResultNode.setNodeData(cluResult);
930  25 return cluResultNode;
931    }
932   
933    // TODO This is pretty much a copy of the FormatAssembler's
934    // disassembleActivities code... maybe can be made generic
 
935  25 toggle private List<BaseDTOAssemblyNode<?, ?>> disassembleFormats(String nodeId,
936    CourseInfo course, NodeOperation operation)
937    throws AssemblyException, DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException {
938   
939  25 List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
940   
941    // Get the current formats and put them in a map of format id/relation
942    // id
943  25 Map<String, String> currentformatIds = new HashMap<String, String>();
944   
945  25 if (!NodeOperation.CREATE.equals(operation)) {
946  11 try {
947  11 List<CluCluRelationInfo> formatRelationships = luService
948    .getCluCluRelationsByClu(course.getId());
949   
950    //formatRelationships = (null == formatRelationships) ? new ArrayList<CluCluRelationInfo>() : formatRelationships;
951   
952  11 for (CluCluRelationInfo formatRelation : formatRelationships) {
953  7 if (CourseAssemblerConstants.COURSE_FORMAT_RELATION_TYPE
954    .equals(formatRelation.getType())) {
955  7 currentformatIds.put(formatRelation.getRelatedCluId(),
956    formatRelation.getId());
957    }
958    }
959    } catch (DoesNotExistException e) {
960    } catch (InvalidParameterException e) {
961  0 throw new AssemblyException("Error getting related formats", e);
962    } catch (MissingParameterException e) {
963  0 throw new AssemblyException("Error getting related formats", e);
964    } catch (OperationFailedException e) {
965  0 throw new AssemblyException("Error getting related formats", e);
966    }
967    }
968   
969    // Loop through all the formats in this course
970  25 for (FormatInfo format : course.getFormats()) {
971   
972    // If this is a course create/new format update then all formats will be created
973  51 if (NodeOperation.CREATE == operation
974    || (NodeOperation.UPDATE == operation && !currentformatIds.containsKey(format.getId()) )) {
975    // the format does not exist, so create
976    // Assemble and add the format
977  45 format.setState(course.getState());
978  45 BaseDTOAssemblyNode<FormatInfo, CluInfo> formatNode = formatAssembler
979    .disassemble(format, NodeOperation.CREATE);
980  45 results.add(formatNode);
981   
982   
983    // Create the relationship and add it as well
984  45 CluCluRelationInfo relation = new CluCluRelationInfo();
985  45 relation.setCluId(nodeId);
986  45 relation.setRelatedCluId(formatNode.getNodeData().getId());// this
987    // should
988    // already
989    // be set even if
990    // it's a create
991  45 relation
992    .setType(CourseAssemblerConstants.COURSE_FORMAT_RELATION_TYPE);
993  45 relation.setState(course.getState());
994   
995  45 BaseDTOAssemblyNode<CourseInfo, CluCluRelationInfo> relationNode = new BaseDTOAssemblyNode<CourseInfo, CluCluRelationInfo>(
996    null);
997  45 relationNode.setNodeData(relation);
998  45 relationNode.setOperation(NodeOperation.CREATE);
999   
1000  45 results.add(relationNode);
1001  6 } else if (NodeOperation.UPDATE == operation
1002    && currentformatIds.containsKey(format.getId())) {
1003    // If the course already has this format, then just update the
1004    // format
1005  4 format.setState(course.getState());
1006  4 BaseDTOAssemblyNode<FormatInfo, CluInfo> formatNode = formatAssembler
1007    .disassemble(format, NodeOperation.UPDATE);
1008  4 results.add(formatNode);
1009   
1010    // remove this entry from the map so we can tell what needs to
1011    // be deleted at the end
1012  4 currentformatIds.remove(format.getId());
1013  2 } else if (NodeOperation.DELETE == operation
1014    && currentformatIds.containsKey(format.getId())) {
1015    // Delete the Format and its relation
1016  2 CluCluRelationInfo relationToDelete = new CluCluRelationInfo();
1017  2 relationToDelete.setId( currentformatIds.get(format.getId()) );
1018  2 BaseDTOAssemblyNode<CourseInfo, CluCluRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<CourseInfo, CluCluRelationInfo>(
1019    null);
1020  2 relationToDeleteNode.setNodeData(relationToDelete);
1021  2 relationToDeleteNode.setOperation(NodeOperation.DELETE);
1022  2 results.add(relationToDeleteNode);
1023   
1024  2 BaseDTOAssemblyNode<FormatInfo, CluInfo> formatNode = formatAssembler
1025    .disassemble(format, NodeOperation.DELETE);
1026  2 results.add(formatNode);
1027   
1028    // remove this entry from the map so we can tell what needs to
1029    // be deleted at the end
1030  2 currentformatIds.remove(format.getId());
1031    }
1032    }
1033   
1034    // Now any leftover format ids are no longer needed, so delete
1035    // formats and relations. These formats have to be assembled first before they can be marked for deletion
1036  25 for (Entry<String, String> entry : currentformatIds.entrySet()) {
1037    // Create a new relation with the id of the relation we want to
1038    // delete
1039  1 CluCluRelationInfo relationToDelete = new CluCluRelationInfo();
1040  1 relationToDelete.setId( entry.getValue() );
1041  1 BaseDTOAssemblyNode<CourseInfo, CluCluRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<CourseInfo, CluCluRelationInfo>(
1042    null);
1043  1 relationToDeleteNode.setNodeData(relationToDelete);
1044  1 relationToDeleteNode.setOperation(NodeOperation.DELETE);
1045  1 results.add(relationToDeleteNode);
1046   
1047  1 CluInfo formatCluToDelete = luService.getClu(entry.getKey());
1048  1 FormatInfo formatToDelete = formatAssembler.assemble(formatCluToDelete, null, false);
1049  1 BaseDTOAssemblyNode<FormatInfo, CluInfo> formatNode = formatAssembler
1050    .disassemble(formatToDelete, NodeOperation.DELETE);
1051  1 results.add(formatNode);
1052    }
1053   
1054  25 return results;
1055    }
1056   
 
1057  45 toggle private List<CourseVariationInfo> assembleVariations(List<CluIdentifierInfo> cluIdents) {
1058  45 List<CourseVariationInfo> variations = new ArrayList<CourseVariationInfo>();
1059  45 if (cluIdents != null) {
1060  45 for (CluIdentifierInfo cluIdent : cluIdents) {
1061  94 if (cluIdent.getType() != null &&
1062    cluIdent.getType().equals(CourseAssemblerConstants.COURSE_VARIATION_IDENT_TYPE)) {
1063  90 CourseVariationInfo variation = new CourseVariationInfo();
1064  90 variation.setId(cluIdent.getId());
1065  90 variation.setType(cluIdent.getType());
1066  90 variation.setCourseNumberSuffix(cluIdent.getSuffixCode());
1067  90 variation.setSubjectArea(cluIdent.getDivision());
1068  90 variation.setVariationCode(cluIdent.getVariation());
1069  90 variation.setVariationTitle(cluIdent.getLongName());
1070  90 variations.add(variation);
1071    }
1072    }
1073    }
1074  45 return variations;
1075    }
1076   
 
1077  45 toggle private List<CourseCrossListingInfo> assembleCrossListings(List<CluIdentifierInfo> cluIdents) {
1078  45 List<CourseCrossListingInfo> crossListings = new ArrayList<CourseCrossListingInfo>();
1079  45 if (cluIdents != null) {
1080  45 for (CluIdentifierInfo cluIdent : cluIdents) {
1081  94 if (cluIdent.getType() != null &&
1082    cluIdent.getType().equals(CourseAssemblerConstants.COURSE_CROSSLISTING_IDENT_TYPE)) {
1083  4 CourseCrossListingInfo crosslisting = new CourseCrossListingInfo();
1084  4 crosslisting.setId(cluIdent.getId());
1085  4 crosslisting.setCode(cluIdent.getCode());
1086  4 crosslisting.setAttributes(cluIdent.getAttributes());
1087  4 crosslisting.setType(cluIdent.getType());
1088  4 crosslisting.setCourseNumberSuffix(cluIdent.getSuffixCode());
1089  4 crosslisting.setSubjectArea(cluIdent.getDivision());
1090  4 crosslisting.setDepartment(cluIdent.getOrgId());
1091  4 crossListings.add(crosslisting);
1092    }
1093    }
1094    }
1095  45 return crossListings;
1096    }
1097   
1098    // TODO This is pretty much a copy of the disassembleJoints
1099    // code... maybe can be made generic
 
1100  25 toggle private List<BaseDTOAssemblyNode<?, ?>> disassembleJoints(String nodeId,
1101    CourseInfo course, NodeOperation operation)
1102    throws AssemblyException {
1103   
1104  25 List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
1105   
1106    // Get the current joints and put them in a map of joint id/relation
1107    // id
1108  25 Map<String, CluCluRelationInfo> currentJointIds = new HashMap<String, CluCluRelationInfo>();
1109   
1110  25 if (!NodeOperation.CREATE.equals(operation)) {
1111  11 try {
1112  11 List<CluCluRelationInfo> jointRelationships = luService.getCluCluRelationsByClu(course.getId());
1113  11 for (CluCluRelationInfo jointRelation : jointRelationships) {
1114  7 if (CourseAssemblerConstants.JOINT_RELATION_TYPE.equals(jointRelation.getType())) {
1115  0 if(jointRelation.getCluId().equals(course.getId())) {
1116  0 CluInfo clu = luService.getClu(jointRelation.getRelatedCluId());
1117  0 if (clu.getState().equals(DtoConstants.STATE_ACTIVE) || clu.getState().equals(DtoConstants.STATE_SUPERSEDED) ||
1118    clu.getState().equals(DtoConstants.STATE_APPROVED) || clu.getState().equals(DtoConstants.STATE_SUSPENDED))
1119  0 currentJointIds.put(jointRelation.getId(),jointRelation);
1120    } else {
1121  0 CluInfo clu = luService.getClu(jointRelation.getCluId());
1122  0 if (clu.getState().equals(DtoConstants.STATE_ACTIVE) || clu.getState().equals(DtoConstants.STATE_SUPERSEDED) ||
1123    clu.getState().equals(DtoConstants.STATE_APPROVED) || clu.getState().equals(DtoConstants.STATE_SUSPENDED))
1124  0 currentJointIds.put(jointRelation.getId(),jointRelation);
1125    }
1126    }
1127    }
1128    } catch (DoesNotExistException e) {
1129    } catch (InvalidParameterException e) {
1130  0 throw new AssemblyException("Error getting related formats", e);
1131    } catch (MissingParameterException e) {
1132  0 throw new AssemblyException("Error getting related formats", e);
1133    } catch (OperationFailedException e) {
1134  0 throw new AssemblyException("Error getting related formats", e);
1135    }
1136    }
1137   
1138    // Loop through all the joints in this course
1139  25 for (CourseJointInfo joint : course.getJoints()) {
1140    // If this is a course create then all joints will be created
1141  0 if (NodeOperation.UPDATE.equals(operation) && joint.getRelationId() != null
1142    && currentJointIds.containsKey(joint.getRelationId())) {
1143    // remove this entry from the map so we can tell what needs to
1144    // be deleted at the end
1145  0 CluCluRelationInfo relation = currentJointIds.remove(joint.getRelationId());
1146  0 relation.setRelatedCluId(joint.getCourseId());
1147  0 relation.setState(course.getState());
1148  0 BaseDTOAssemblyNode<CourseJointInfo, CluCluRelationInfo> jointNode = new BaseDTOAssemblyNode<CourseJointInfo, CluCluRelationInfo>(courseJointAssembler);
1149  0 jointNode.setBusinessDTORef(joint);
1150  0 jointNode.setNodeData(relation);
1151  0 jointNode.setOperation(NodeOperation.UPDATE);
1152  0 results.add(jointNode);
1153  0 } else if (!NodeOperation.DELETE.equals(operation)) {
1154    // the joint does not exist, so create cluclurelation
1155  0 BaseDTOAssemblyNode<CourseJointInfo, CluCluRelationInfo> jointNode = courseJointAssembler
1156    .disassemble(joint, NodeOperation.CREATE);
1157  0 jointNode.getNodeData().setCluId(nodeId);
1158  0 jointNode.getNodeData().setState(course.getState());
1159  0 results.add(jointNode);
1160    }
1161    }
1162   
1163    // Now any leftover joint ids are no longer needed, so delete
1164    // joint relations
1165  25 for (String id : currentJointIds.keySet()) {
1166    // Create a new relation with the id of the relation we want to
1167    // delete
1168  0 CluCluRelationInfo relationToDelete = new CluCluRelationInfo();
1169  0 relationToDelete.setId(id);
1170  0 BaseDTOAssemblyNode<CourseJointInfo, CluCluRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<CourseJointInfo, CluCluRelationInfo>(
1171    courseJointAssembler);
1172  0 relationToDeleteNode.setNodeData(relationToDelete);
1173  0 relationToDeleteNode.setOperation(NodeOperation.DELETE);
1174  0 results.add(relationToDeleteNode);
1175    }
1176   
1177  25 return results;
1178    }
1179   
 
1180  1 toggle public void setLuService(LuService luService) {
1181  1 this.luService = luService;
1182    }
1183   
 
1184  1 toggle public void setFormatAssembler(FormatAssembler formatAssembler) {
1185  1 this.formatAssembler = formatAssembler;
1186    }
1187   
 
1188  1 toggle public void setCourseJointAssembler(
1189    CourseJointAssembler courseJointAssembler) {
1190  1 this.courseJointAssembler = courseJointAssembler;
1191    }
1192   
 
1193  1 toggle public void setLoAssembler(LoAssembler loAssembler) {
1194  1 this.loAssembler = loAssembler;
1195    }
1196   
 
1197  1 toggle public void setLoService(LearningObjectiveService loService) {
1198  1 this.loService = loService;
1199    }
1200   
 
1201  1 toggle public void setCluAssemblerUtils(CluAssemblerUtils cluAssemblerUtils) {
1202  1 this.cluAssemblerUtils = cluAssemblerUtils;
1203    }
1204   
 
1205  1 toggle public void setLrcService(LrcService lrcService) {
1206  1 this.lrcService = lrcService;
1207    }
1208    }