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