Clover Coverage Report - Kuali Student 1.1 (Aggregated)
Coverage timestamp: Sun Mar 6 2011 20:32:39 EST
../../../../../../../img/srcFileCovDistChart9.png 32% of files have more coverage
612   1,231   154   32.21
156   918   0.25   19
19     8.11  
1    
 
  CourseAssembler       Line # 74 612 0% 154 88 88.8% 0.888183
 
  (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.util.UUIDHelper;
31    import org.kuali.student.core.assembly.BOAssembler;
32    import org.kuali.student.core.assembly.BaseDTOAssemblyNode;
33    import org.kuali.student.core.assembly.BaseDTOAssemblyNode.NodeOperation;
34    import org.kuali.student.core.assembly.data.AssemblyException;
35    import org.kuali.student.core.dto.RichTextInfo;
36    import org.kuali.student.core.exceptions.DoesNotExistException;
37    import org.kuali.student.core.exceptions.InvalidParameterException;
38    import org.kuali.student.core.exceptions.MissingParameterException;
39    import org.kuali.student.core.exceptions.OperationFailedException;
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   
312    //Custom logic to set the code as the concatenation of division and course number suffix if code not provided
313  25 if (StringUtils.hasText(course.getCode())){
314  24 identifier.setCode(course.getCode());
315  1 } else if(StringUtils.hasText(course.getCourseNumberSuffix()) && StringUtils.hasText(course.getSubjectArea())){
316  1 identifier.setCode(calculateCourseCode(course.getSubjectArea(),course.getCourseNumberSuffix()));
317    }else{
318  0 identifier.setCode(null);
319    }
320   
321    //Custom logic to set the level, if level not provided
322  25 if(StringUtils.hasText(course.getLevel())) {
323  25 identifier.setLevel(course.getLevel());
324  0 } else if(course.getCourseNumberSuffix()!=null&&course.getCourseNumberSuffix().length()>=3){
325  0 identifier.setLevel(course.getCourseNumberSuffix().substring(0, 1)+"00");
326    }
327   
328  25 clu.setOfficialIdentifier(identifier);
329   
330  25 clu.setAdminOrgs(new ArrayList<AdminOrgInfo>());
331   
332    // Use the Course Variation assembler to disassemble the variations
333   
334    // copy all fields
335    //Remove any existing variations or crosslistings
336  45 for(Iterator<CluIdentifierInfo> iter = clu.getAlternateIdentifiers().iterator();iter.hasNext();){
337  20 CluIdentifierInfo cluIdentifier = iter.next();
338  20 if(CourseAssemblerConstants.COURSE_VARIATION_IDENT_TYPE.equals(cluIdentifier.getType()) ||
339    CourseAssemblerConstants.COURSE_CROSSLISTING_IDENT_TYPE.equals(cluIdentifier.getType()) ){
340  20 iter.remove();
341    }
342    }
343    //Add in variations
344  25 for(CourseVariationInfo variation:course.getVariations()){
345  50 CluIdentifierInfo cluIdentifier = new CluIdentifierInfo();
346  50 cluIdentifier.setId(variation.getId());
347  50 cluIdentifier.setType(CourseAssemblerConstants.COURSE_VARIATION_IDENT_TYPE);
348  50 cluIdentifier.setCode(identifier.getCode());
349  50 cluIdentifier.setSuffixCode(course.getCourseNumberSuffix());
350  50 cluIdentifier.setDivision(course.getSubjectArea());
351  50 cluIdentifier.setVariation(variation.getVariationCode());
352  50 cluIdentifier.setLongName(variation.getVariationTitle());
353  50 cluIdentifier.setState(course.getState());
354  50 clu.getAlternateIdentifiers().add(cluIdentifier);
355    }
356    //Add in ings
357  25 for(CourseCrossListingInfo crossListing:course.getCrossListings()){
358  2 CluIdentifierInfo cluIdentifier = new CluIdentifierInfo();
359  2 cluIdentifier.setId(crossListing.getId());
360  2 cluIdentifier.setType(CourseAssemblerConstants.COURSE_CROSSLISTING_IDENT_TYPE);
361  2 cluIdentifier.setSuffixCode(crossListing.getCourseNumberSuffix());
362  2 cluIdentifier.setDivision(crossListing.getSubjectArea());
363  2 cluIdentifier.setState(course.getState());
364  2 cluIdentifier.setOrgId(crossListing.getDepartment());
365  2 cluIdentifier.setAttributes(crossListing.getAttributes());
366   
367    //Custom logic to set the code as the concatenation of division and course number suffix if code not provided
368  2 if (StringUtils.hasText(crossListing.getCode())){
369  1 cluIdentifier.setCode(crossListing.getCode());
370  1 } else if(StringUtils.hasText(crossListing.getCourseNumberSuffix()) && StringUtils.hasText(crossListing.getSubjectArea())){
371  1 cluIdentifier.setCode(calculateCourseCode(crossListing.getSubjectArea(), crossListing.getCourseNumberSuffix()));
372    }else{
373  0 cluIdentifier.setCode(null);
374    }
375   
376  2 clu.getAlternateIdentifiers().add(cluIdentifier);
377    }
378   
379  25 List<AdminOrgInfo> adminOrgInfos = new ArrayList<AdminOrgInfo>();
380  25 for(String org:course.getUnitsDeployment()){
381  50 AdminOrgInfo adminOrg = new AdminOrgInfo();
382  50 adminOrg.setType(CourseAssemblerConstants.ADMIN_ORG);
383  50 adminOrg.setOrgId(org);
384  50 adminOrgInfos.add(adminOrg);
385    }
386  25 clu.getAdminOrgs().addAll(adminOrgInfos);
387   
388  25 List<AdminOrgInfo> subjectOrgs = new ArrayList<AdminOrgInfo>();
389  25 for (String subOrg : course.getUnitsContentOwner()) {
390  48 AdminOrgInfo subjectOrg = new AdminOrgInfo();
391  48 subjectOrg.setType(CourseAssemblerConstants.SUBJECT_ORG);
392  48 subjectOrg.setOrgId(subOrg);
393  48 subjectOrgs.add(subjectOrg);
394    }
395  25 clu.getAdminOrgs().addAll(subjectOrgs);
396   
397   
398  25 clu.setAttributes(course.getAttributes());
399  25 clu.setCampusLocations(course.getCampusLocations());
400  25 clu.setDescr(course.getDescr());
401  25 clu.setStdDuration(course.getDuration());
402  25 clu.setEffectiveDate(course.getEffectiveDate());
403  25 clu.setExpirationDate(course.getExpirationDate());
404   
405  25 clu.setOfferedAtpTypes(course.getTermsOffered());
406  25 clu.setPrimaryInstructor(course.getPrimaryInstructor());
407   
408  25 clu.setIntensity(course.getOutOfClassHours());
409  25 clu.setInstructors(course.getInstructors());
410   
411  25 clu.setExpectedFirstAtp(course.getStartTerm());
412  25 clu.setLastAtp(course.getEndTerm());
413   
414  25 clu.setMetaInfo(course.getMetaInfo());
415  25 clu.setVersionInfo(course.getVersionInfo());
416   
417    // Add the Clu to the result
418  25 result.setNodeData(clu);
419  25 result.setOperation(operation);
420  25 result.setBusinessDTORef(course);
421   
422    // Use the Format assembler to disassemble the formats and relations
423  25 List<BaseDTOAssemblyNode<?, ?>> formatResults;
424  25 try {
425  25 formatResults = disassembleFormats(clu
426    .getId(), course, operation);
427  25 result.getChildNodes().addAll(formatResults);
428   
429    } catch (DoesNotExistException e) {
430    } catch (Exception e) {
431  0 throw new AssemblyException("Error while disassembling format", e);
432    }
433   
434    // Use the CourseJoint assembler to disassemble the CourseJoints and
435    // relations
436  25 List<BaseDTOAssemblyNode<?, ?>> courseJointResults = disassembleJoints(
437    clu.getId(), course, operation);
438  25 result.getChildNodes().addAll(courseJointResults);
439   
440    //Disassemble the CluResults (grading and credit options)
441    //Special code to take audit from attributes and put into options
442  25 if(course.getAttributes().containsKey(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_AUDIT)&&"true".equals(course.getAttributes().get(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_AUDIT))){
443  0 if(!course.getGradingOptions().contains(CourseAssemblerConstants.COURSE_RESULT_COMP_GRADE_AUDIT)){
444  0 course.getGradingOptions().add(CourseAssemblerConstants.COURSE_RESULT_COMP_GRADE_AUDIT);
445    }
446    }
447   
448  25 List<CluResultInfo> cluResultList;
449  25 try {
450  25 cluResultList = luService.getCluResultByClu(clu.getId());
451    } catch (DoesNotExistException e) {
452  0 cluResultList = Collections.emptyList();
453    } catch (Exception e) {
454  0 throw new AssemblyException("Error getting cluResults", e);
455    }
456   
457  25 List<BaseDTOAssemblyNode<?, ?>> creditOutcomes = disassembleCreditOutcomes(course, clu, cluResultList, operation);
458  25 result.getChildNodes().addAll(creditOutcomes);
459   
460  25 BaseDTOAssemblyNode<?, ?> gradingOptions = disassembleGradingOptions(
461    clu.getId(), course.getState(), course.getGradingOptions(), cluResultList, operation);
462  25 result.getChildNodes().add(gradingOptions);
463   
464    //Use the LoAssembler to disassemble Los
465  25 try {
466  25 List<BaseDTOAssemblyNode<?, ?>> loResults;
467  25 loResults = disassembleLos(clu.getId(), course, operation);
468  25 result.getChildNodes().addAll(loResults);
469    } catch (Exception e) {
470  0 throw new AssemblyException("Error while disassembling los", e);
471    }
472   
473    //add the special topics code if it did not exist, or remove if it was not wanted
474  25 boolean alreadyHadSpecialTopicsCode = false;
475  25 for(Iterator<LuCodeInfo> luCodeIterator = clu.getLuCodes().iterator();luCodeIterator.hasNext();){
476  1 LuCodeInfo luCode = luCodeIterator.next();
477  1 if(CourseAssemblerConstants.COURSE_CODE_SPECIAL_TOPICS.equals(luCode.getType())){
478  1 alreadyHadSpecialTopicsCode = true;
479  1 if(!course.isSpecialTopicsCourse()){
480  1 luCodeIterator.remove();
481    }
482  1 break;
483    }
484    }
485  25 if(!alreadyHadSpecialTopicsCode && course.isSpecialTopicsCourse()){
486  2 LuCodeInfo luCode = new LuCodeInfo();
487  2 luCode.setType(CourseAssemblerConstants.COURSE_CODE_SPECIAL_TOPICS);
488  2 luCode.setValue("true");
489  2 clu.getLuCodes().add(luCode);
490    }
491   
492    //add the special topics code if it did not exist, or remove if it was not wanted
493  25 boolean alreadyHadPilotCourseCode = false;
494  27 for(Iterator<LuCodeInfo> luCodeIterator = clu.getLuCodes().iterator();luCodeIterator.hasNext();){
495  3 LuCodeInfo luCode = luCodeIterator.next();
496  3 if(CourseAssemblerConstants.COURSE_CODE_PILOT_COURSE.equals(luCode.getType())){
497  1 alreadyHadPilotCourseCode = true;
498  1 if(!course.isPilotCourse()){
499  1 luCodeIterator.remove();
500    }
501  1 break;
502    }
503    }
504  25 if(!alreadyHadPilotCourseCode && course.isPilotCourse()){
505  2 LuCodeInfo luCode = new LuCodeInfo();
506  2 luCode.setType(CourseAssemblerConstants.COURSE_CODE_PILOT_COURSE);
507  2 luCode.setValue("true");
508  2 clu.getLuCodes().add(luCode);
509    }
510   
511    //FEES
512  25 if(clu.getFeeInfo() == null){
513  15 clu.setFeeInfo(new CluFeeInfo());
514    }
515  25 clu.getFeeInfo().setDescr(course.getFeeJustification());
516  25 clu.getFeeInfo().getCluFeeRecords().clear();
517  25 for(CourseRevenueInfo courseRevenue:course.getRevenues()){
518  50 CluFeeRecordInfo cluFeeRecord = new CluFeeRecordInfo();
519  50 cluFeeRecord.setFeeType(CourseAssemblerConstants.COURSE_FINANCIALS_REVENUE_TYPE);
520  50 cluFeeRecord.setRateType(CourseAssemblerConstants.COURSE_FINANCIALS_REVENUE_TYPE);
521  50 cluFeeRecord.setAttributes(courseRevenue.getAttributes());
522  50 cluFeeRecord.setAffiliatedOrgs(courseRevenue.getAffiliatedOrgs());
523  50 cluFeeRecord.setId(courseRevenue.getId());
524  50 cluFeeRecord.setMetaInfo(courseRevenue.getMetaInfo());
525  50 clu.getFeeInfo().getCluFeeRecords().add(cluFeeRecord);
526    }
527  25 for(CourseFeeInfo courseFee : course.getFees()){
528  48 CluFeeRecordInfo cluFeeRecord = new CluFeeRecordInfo();
529  48 cluFeeRecord.setFeeType(courseFee.getFeeType());
530  48 cluFeeRecord.setRateType(courseFee.getRateType());
531  48 cluFeeRecord.setDescr(courseFee.getDescr());
532  48 cluFeeRecord.setMetaInfo(courseFee.getMetaInfo());
533  48 cluFeeRecord.setId(courseFee.getId());
534  48 cluFeeRecord.setFeeAmounts(courseFee.getFeeAmounts());
535  48 cluFeeRecord.setAttributes(courseFee.getAttributes());
536  48 clu.getFeeInfo().getCluFeeRecords().add(cluFeeRecord);
537    }
538  25 if(clu.getAccountingInfo() == null || course.getExpenditure()== null){
539  15 clu.setAccountingInfo( new CluAccountingInfo());
540    }
541  25 if(course.getExpenditure() != null){
542  25 clu.getAccountingInfo().setAffiliatedOrgs(course.getExpenditure().getAffiliatedOrgs());
543  25 clu.getAccountingInfo().setAttributes(course.getExpenditure().getAttributes());
544    }
545   
546  25 return result;
547    }
548   
 
549  25 toggle private List<BaseDTOAssemblyNode<?, ?>> disassembleCreditOutcomes(CourseInfo course, CluInfo clu, List<CluResultInfo> currentCluResults, NodeOperation operation) throws AssemblyException, NumberFormatException {
550   
551  25 List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
552   
553  25 String courseResultType = CourseAssemblerConstants.COURSE_RESULT_TYPE_CREDITS;
554   
555    //See if we need to create any new lrcs
556  25 if(NodeOperation.DELETE!=operation){
557    //Find all the existing LRCs for the following three types
558  24 Set<String> rsltComps = new HashSet<String>();
559   
560  24 try{
561  24 try {
562  24 rsltComps.addAll(lrcService.getResultComponentIdsByResultComponentType(CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_FIXED));
563    } catch (DoesNotExistException e) {}
564  24 try {
565  24 rsltComps.addAll(lrcService.getResultComponentIdsByResultComponentType(CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_MULTIPLE));
566    } catch (DoesNotExistException e) {}
567  24 try {
568  24 rsltComps.addAll(lrcService.getResultComponentIdsByResultComponentType(CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_VARIABLE));
569    } catch (DoesNotExistException e) {}
570   
571    //Create any LRCs that do not yet exist
572  24 for(ResultComponentInfo creditOption:course.getCreditOptions()){
573  49 String id = null;
574  49 String type = null;
575  49 List<String> resultValues = null;
576  49 Map<String,String> attributes = null;
577    //Depending on the type, set the id, type and result values differently
578  49 if(CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_FIXED.equals(creditOption.getType())){
579  44 float fixedCreditValue = Float.parseFloat(creditOption.getAttributes().get(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_FIXED_CREDIT_VALUE));
580  44 id = CourseAssemblerConstants.COURSE_RESULT_COMP_CREDIT_PREFIX + fixedCreditValue;
581  44 type = CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_FIXED;
582  44 resultValues = new ArrayList<String>();
583  44 resultValues.add(String.valueOf(fixedCreditValue));
584  44 attributes = new HashMap<String,String>();
585  44 attributes.put(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_FIXED_CREDIT_VALUE, String.valueOf(fixedCreditValue));
586  5 }else if(CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_MULTIPLE.equals(creditOption.getType())){
587  3 Collections.sort(creditOption.getResultValues());
588  3 StringBuilder sb = new StringBuilder(CourseAssemblerConstants.COURSE_RESULT_COMP_CREDIT_PREFIX);
589  10 for(Iterator<String> iter = creditOption.getResultValues().iterator();iter.hasNext();){
590  7 sb.append(iter.next());
591  7 if(iter.hasNext()){
592  4 sb.append(",");
593    }
594    }
595  3 id = sb.toString();
596  3 type = CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_MULTIPLE;
597  3 resultValues = creditOption.getResultValues();
598  2 }else if(CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_VARIABLE.equals(creditOption.getType())){
599    /*
600    * For variable credits create a Result values that goes from min to max with the specified increment.
601    * If no increment is specified, use 1.0 as the increment. The increment can be specified as a float.
602    */
603   
604  2 String minCreditValue = creditOption.getAttributes().get(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_MIN_CREDIT_VALUE);
605  2 String maxCreditValue = creditOption.getAttributes().get(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_MAX_CREDIT_VALUE);
606  2 String creditValueIncr = creditOption.getAttributes().get(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_CREDIT_VALUE_INCR);
607  2 float minCredits = Float.parseFloat(minCreditValue);
608  2 float maxCredits = Float.parseFloat(maxCreditValue);
609   
610  2 float increment = (null != creditValueIncr && creditValueIncr.length() > 0 ) ? Float.parseFloat(creditValueIncr) : 1.0f ;
611   
612  2 id = CourseAssemblerConstants.COURSE_RESULT_COMP_CREDIT_PREFIX + minCreditValue + "-" + maxCreditValue;
613  2 type = CourseAssemblerConstants.COURSE_RESULT_COMP_TYPE_CREDIT_VARIABLE;
614  2 resultValues = new ArrayList<String>();
615  16 for(float i = minCredits; i <= maxCredits; i+=increment){
616  14 resultValues.add(String.valueOf(i));
617    }
618  2 attributes = new HashMap<String,String>();
619  2 attributes.put(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_MIN_CREDIT_VALUE, minCreditValue);
620  2 attributes.put(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_MAX_CREDIT_VALUE, maxCreditValue);
621  2 attributes.put(CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_CREDIT_VALUE_INCR, creditValueIncr);
622    }
623   
624    //Set the id
625  49 creditOption.setId(id);
626   
627    //Create a new result component
628  49 if(id != null && !rsltComps.contains(id)){
629   
630    //need to make a fixed degree result type component
631  4 ResultComponentInfo resultComponent = new ResultComponentInfo();
632  4 resultComponent.setId(id);
633  4 resultComponent.setType(type);
634    //resultComponent.setState ("Active");
635  4 resultComponent.setState (course.getState());
636  4 resultComponent.setResultValues(resultValues);
637  4 resultComponent.setAttributes(attributes);
638  4 BaseDTOAssemblyNode<ResultComponentInfo, ResultComponentInfo> node = new BaseDTOAssemblyNode<ResultComponentInfo, ResultComponentInfo>(null);
639  4 node.setOperation(NodeOperation.CREATE);
640  4 node.setNodeData(resultComponent);
641  4 node.setBusinessDTORef(creditOption);
642  4 results.add(node);
643   
644  4 rsltComps.add(id);
645    }
646    }
647    }catch (NumberFormatException e){
648  0 throw new AssemblyException("Invalid Arguments for credit outcome values",e);
649    }catch (Exception e){
650  0 throw new AssemblyException("Error Assembling", e);
651    }
652    }
653   
654    //Now do dissassembly for the actual clu-lrc relations and result options
655   
656    // Get the current options and put them in a map of option type id/cluResult
657  25 Map<String, List<CluResultInfo>> currentResults = new HashMap<String, List<CluResultInfo>>();
658   
659    //If this is not a create, lookup the results for this clu
660  25 if (!NodeOperation.CREATE.equals(operation)) {
661  11 for (CluResultInfo currentResult : currentCluResults) {
662  9 if (courseResultType.equals(currentResult.getType())) {
663    //There should only be one grading option per CluResult for credit outcomes
664  6 if(currentResult.getResultOptions().size()==1){
665    //Create a mapping to a list of cluresults with the same result componentId
666  6 String resultComponentId = currentResult.getResultOptions().get(0).getResultComponentId();
667  6 if(!currentResults.containsKey(resultComponentId)){
668  4 currentResults.put(resultComponentId, new ArrayList<CluResultInfo>());
669    }
670  6 currentResults.get(resultComponentId).add(currentResult);
671    }else{
672  0 LOG.warn("Credit Results should have exactly one result option each");
673    }
674    }
675    }
676    }
677   
678    //Loop through options on the course, if they are new, create a new cluResult
679  25 for(ResultComponentInfo creditOption : course.getCreditOptions()){
680  51 if (NodeOperation.CREATE == operation
681    || (NodeOperation.UPDATE == operation && !currentResults.containsKey(creditOption.getId()) )) {
682   
683  46 ResultOptionInfo resultOption = new ResultOptionInfo();
684  46 resultOption.setState(course.getState());
685  46 resultOption.setResultComponentId(creditOption.getId());
686   
687  46 CluResultInfo cluResult = new CluResultInfo();
688  46 cluResult.setCluId(clu.getId());
689  46 cluResult.setState(course.getState());
690  46 cluResult.setType(courseResultType);
691   
692  46 cluResult.getResultOptions().add(resultOption);
693   
694  46 BaseDTOAssemblyNode<ResultComponentInfo, CluResultInfo> cluResultNode = new BaseDTOAssemblyNode<ResultComponentInfo, CluResultInfo>(null);
695  46 cluResultNode.setNodeData(cluResult);
696  46 cluResultNode.setOperation(NodeOperation.CREATE);
697   
698  46 results.add(cluResultNode);
699  5 } else if (NodeOperation.UPDATE == operation
700    && currentResults.containsKey(creditOption.getId())) {
701    //Get the list from the map and remove an entry, if the list is empty then remove it from the map
702  3 List<CluResultInfo> cluResults = currentResults.get(creditOption.getId());
703  3 cluResults.remove(cluResults.size()-1);
704  3 if(cluResults.isEmpty()){
705  2 currentResults.remove(creditOption.getId());
706    }
707    }
708    }
709   
710    //Delete the leftovers
711  25 for(Entry<String,List<CluResultInfo>> entry:currentResults.entrySet()){
712  2 for(CluResultInfo cluResult:entry.getValue()){
713  3 BaseDTOAssemblyNode<ResultComponentInfo, CluResultInfo> cluResultNode = new BaseDTOAssemblyNode<ResultComponentInfo, CluResultInfo>(null);
714  3 cluResultNode.setNodeData(cluResult);
715  3 cluResultNode.setOperation(NodeOperation.DELETE);
716  3 results.add(cluResultNode);
717    }
718    }
719   
720  25 return results;
721    }
722   
 
723  14 toggle private List<String> assembleGradingOptions(List<CluResultInfo> cluResults){
724   
725  14 String courseResultType = CourseAssemblerConstants.COURSE_RESULT_TYPE_GRADE;
726   
727  14 List<String> results = new ArrayList<String>();
728    //Loop through all the CluResults to find the one with the matching type
729  14 for(CluResultInfo cluResult:cluResults){
730  42 if(courseResultType.equals(cluResult.getType())){
731    //Loop through all options and add to the list of Strings
732  14 for(ResultOptionInfo resultOption: cluResult.getResultOptions()){
733  28 results.add(resultOption.getResultComponentId());
734    }
735  14 break;
736    }
737    }
738  14 return results;
739    }
740   
 
741  14 toggle private List<ResultComponentInfo> assembleCreditOptions(
742    List<CluResultInfo> cluResults) throws AssemblyException {
743  14 String courseResultType = CourseAssemblerConstants.COURSE_RESULT_TYPE_CREDITS;
744  14 List<ResultComponentInfo> results = new ArrayList<ResultComponentInfo>();
745    //Loop through all the CluResults to find the one with the matching type
746  14 for(CluResultInfo cluResult:cluResults){
747  43 if(courseResultType.equals(cluResult.getType())){
748    //Loop through all options and add to the list of Strings
749  29 for(ResultOptionInfo resultOption: cluResult.getResultOptions()){
750  29 try {
751  29 ResultComponentInfo resultComponent = lrcService.getResultComponent(resultOption.getResultComponentId());
752  29 results.add(resultComponent);
753    } catch (DoesNotExistException e) {
754  0 LOG.warn("Course Credit option:"+resultOption.getId()+" refers to non-existant ResultComponentInfo "+resultOption.getResultComponentId());
755    } catch (Exception e) {
756  0 throw new AssemblyException("Error getting result components",e);
757    }
758    }
759    }
760    }
761  14 return results;
762    }
763   
764    // TODO Use CluAssemblerUtils
 
765  25 toggle private List<BaseDTOAssemblyNode<?, ?>> disassembleLos(String cluId,
766    CourseInfo course, NodeOperation operation) throws AssemblyException {
767    // TODO Auto-generated method stub
768  25 List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
769   
770    // Get the current formats and put them in a map of format id/relation
771    // id
772  25 Map<String, CluLoRelationInfo> currentCluLoRelations = new HashMap<String, CluLoRelationInfo>();
773  25 try {
774  25 List<CluLoRelationInfo> cluLoRelations = luService.getCluLoRelationsByClu(cluId);
775  25 for(CluLoRelationInfo cluLoRelation:cluLoRelations){
776  6 if(CourseAssemblerConstants.COURSE_LO_COURSE_SPECIFIC_RELATION.equals(cluLoRelation.getType())){
777  6 currentCluLoRelations.put(cluLoRelation.getLoId(), cluLoRelation);
778    }
779    }
780    } catch (DoesNotExistException e) {
781    } catch (Exception e) {
782  0 throw new AssemblyException("Error finding related Los");
783    }
784   
785    // Loop through all the los in this clu
786  25 for(LoDisplayInfo loDisplay : course.getCourseSpecificLOs()){
787   
788    // If this is a clu create/new lo update then all los will be created
789  50 if (NodeOperation.CREATE == operation
790    || (NodeOperation.UPDATE == operation && !currentCluLoRelations.containsKey(loDisplay.getLoInfo().getId()))) {
791   
792    // the lo does not exist, so create
793    // Assemble and add the lo
794  45 loDisplay.getLoInfo().setId(null);
795  45 loDisplay.getLoInfo().setState(course.getState());
796  45 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = loAssembler
797    .disassemble(loDisplay, NodeOperation.CREATE);
798  45 results.add(loNode);
799   
800    // Create the relationship and add it as well
801  45 CluLoRelationInfo relation = new CluLoRelationInfo();
802  45 relation.setCluId(cluId);
803  45 relation.setLoId(loNode.getNodeData().getId());
804  45 relation
805    .setType(CourseAssemblerConstants.COURSE_LO_COURSE_SPECIFIC_RELATION);
806  45 relation.setState(course.getState());
807   
808  45 BaseDTOAssemblyNode<LoDisplayInfo, CluLoRelationInfo> relationNode = new BaseDTOAssemblyNode<LoDisplayInfo, CluLoRelationInfo>(
809    null);
810  45 relationNode.setNodeData(relation);
811  45 relationNode.setOperation(NodeOperation.CREATE);
812   
813  45 results.add(relationNode);
814  5 } else if (NodeOperation.UPDATE == operation
815    && currentCluLoRelations.containsKey(loDisplay.getLoInfo().getId())) {
816    // If the clu already has this lo, then just update the lo
817  3 loDisplay.getLoInfo().setState(course.getState());
818  3 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = loAssembler
819    .disassemble(loDisplay, NodeOperation.UPDATE);
820  3 results.add(loNode);
821   
822    // remove this entry from the map so we can tell what needs to
823    // be deleted at the end
824  3 currentCluLoRelations.remove(loDisplay.getLoInfo().getId());
825  2 } else if (NodeOperation.DELETE == operation
826    && currentCluLoRelations.containsKey(loDisplay.getLoInfo().getId())) {
827   
828    // Delete the Format and its relation
829  2 CluLoRelationInfo relationToDelete = currentCluLoRelations.get(loDisplay.getLoInfo().getId());
830  2 BaseDTOAssemblyNode<LoDisplayInfo, CluLoRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<LoDisplayInfo, CluLoRelationInfo>(
831    null);
832  2 relationToDeleteNode.setNodeData(relationToDelete);
833  2 relationToDeleteNode.setOperation(NodeOperation.DELETE);
834  2 results.add(relationToDeleteNode);
835   
836  2 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = loAssembler
837    .disassemble(loDisplay, NodeOperation.DELETE);
838  2 results.add(loNode);
839   
840    // remove this entry from the map so we can tell what needs to
841    // be deleted at the end
842  2 currentCluLoRelations.remove(loDisplay.getLoInfo().getId());
843    }
844    }
845   
846    // Now any leftover lo ids are no longer needed, so delete
847    // los and relations
848  25 for (Entry<String, CluLoRelationInfo> entry : currentCluLoRelations.entrySet()) {
849    // Create a new relation with the id of the relation we want to
850    // delete
851  1 CluLoRelationInfo relationToDelete = entry.getValue();
852  1 BaseDTOAssemblyNode<LoDisplayInfo, CluLoRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<LoDisplayInfo, CluLoRelationInfo>(
853    null);
854  1 relationToDeleteNode.setNodeData(relationToDelete);
855  1 relationToDeleteNode.setOperation(NodeOperation.DELETE);
856  1 results.add(relationToDeleteNode);
857   
858  1 try{
859  1 LoInfo loToDelete = loService.getLo(entry.getKey());
860   
861  1 LoDisplayInfo loDisplayToDelete = loAssembler.assemble(loToDelete, null, false);
862  1 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = loAssembler
863    .disassemble(loDisplayToDelete, NodeOperation.DELETE);
864  1 results.add(loNode);
865    } catch (DoesNotExistException e){
866  0 LOG.warn("Trying to delete non exsistant LO:"+entry.getKey());
867    } catch (Exception e) {
868  0 throw new AssemblyException("Error disassembling LOs",e);
869    }
870    }
871   
872  25 return results;
873    }
874   
 
875  25 toggle private BaseDTOAssemblyNode<?, ?> disassembleGradingOptions(String cluId,
876    String courseState, List<String> options, List<CluResultInfo> currentCluResults, NodeOperation operation) throws AssemblyException {
877  25 BaseDTOAssemblyNode<List<String>, CluResultInfo> cluResultNode = new BaseDTOAssemblyNode<List<String>, CluResultInfo>(null);
878   
879  25 String courseResultType=CourseAssemblerConstants.COURSE_RESULT_TYPE_GRADE;
880  25 String resultsDescription="Grading options";
881  25 String resultDescription="Grading option";
882   
883    // Get the current options and put them in a map of option type id/cluResult
884  25 Map<String, ResultOptionInfo> currentResults = new HashMap<String, ResultOptionInfo>();
885   
886  25 CluResultInfo cluResult = null;
887   
888    //If this is not a create, lookup the results for this clu
889  25 if (!NodeOperation.CREATE.equals(operation)) {
890  11 for (CluResultInfo currentResult : currentCluResults) {
891  8 if (courseResultType.equals(currentResult.getType())) {
892  3 cluResult = currentResult;
893  3 if(NodeOperation.DELETE.equals(operation)){
894    //if this is a delete, then we only need the CluResultInfo
895  1 cluResultNode.setOperation(NodeOperation.DELETE);
896    }else{
897    //Find all the Result options and store in a map for easy access later
898  2 cluResultNode.setOperation(NodeOperation.UPDATE);
899  2 for(ResultOptionInfo resultOption:currentResult.getResultOptions()){
900  4 currentResults.put(resultOption.getResultComponentId(), resultOption);
901    }
902    }
903  3 break;
904    }
905    }
906    }
907   
908    //If this is a delete we don't need the result options, just the CluResultInfo
909  25 if(!NodeOperation.DELETE.equals(operation)){
910  24 if(cluResult == null){
911    //Create a new resultInfo of the given type if one does not exist and set operation to Create
912  22 cluResult = new CluResultInfo();
913  22 cluResult.setCluId(cluId);
914  22 cluResult.setState(courseState);
915  22 cluResult.setType(courseResultType);
916  22 RichTextInfo desc = new RichTextInfo();
917  22 desc.setPlain(resultsDescription);
918  22 cluResult.setDesc(desc);
919  22 cluResult.setEffectiveDate(new Date());
920  22 cluResultNode.setOperation(NodeOperation.CREATE);
921    }
922   
923  24 cluResult.setResultOptions(new ArrayList<ResultOptionInfo>());
924   
925    // Loop through all the credit options in this course
926  24 for (String optionType : options) {
927  48 if(currentResults.containsKey(optionType)){
928    //If the option exists already copy it to the new list of result options
929  3 ResultOptionInfo resultOptionInfo = currentResults.get(optionType);
930  3 cluResult.getResultOptions().add(resultOptionInfo);
931    }else{
932    //Otherwise create a new result option
933  45 ResultOptionInfo resultOptionInfo = new ResultOptionInfo();
934  45 RichTextInfo desc = new RichTextInfo();
935  45 desc.setPlain(resultDescription);
936  45 resultOptionInfo.setDesc(desc);
937  45 resultOptionInfo.setResultComponentId(optionType);
938  45 resultOptionInfo.setState(courseState);
939   
940  45 cluResult.getResultOptions().add(resultOptionInfo);
941    }
942    }
943    }
944   
945  25 cluResultNode.setNodeData(cluResult);
946  25 return cluResultNode;
947    }
948   
949    // TODO This is pretty much a copy of the FormatAssembler's
950    // disassembleActivities code... maybe can be made generic
 
951  25 toggle private List<BaseDTOAssemblyNode<?, ?>> disassembleFormats(String nodeId,
952    CourseInfo course, NodeOperation operation)
953    throws AssemblyException, DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException {
954   
955  25 List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
956   
957    // Get the current formats and put them in a map of format id/relation
958    // id
959  25 Map<String, String> currentformatIds = new HashMap<String, String>();
960   
961  25 if (!NodeOperation.CREATE.equals(operation)) {
962  11 try {
963  11 List<CluCluRelationInfo> formatRelationships = luService
964    .getCluCluRelationsByClu(course.getId());
965   
966    //formatRelationships = (null == formatRelationships) ? new ArrayList<CluCluRelationInfo>() : formatRelationships;
967   
968  11 for (CluCluRelationInfo formatRelation : formatRelationships) {
969  7 if (CourseAssemblerConstants.COURSE_FORMAT_RELATION_TYPE
970    .equals(formatRelation.getType())) {
971  7 currentformatIds.put(formatRelation.getRelatedCluId(),
972    formatRelation.getId());
973    }
974    }
975    } catch (DoesNotExistException e) {
976    } catch (InvalidParameterException e) {
977  0 throw new AssemblyException("Error getting related formats", e);
978    } catch (MissingParameterException e) {
979  0 throw new AssemblyException("Error getting related formats", e);
980    } catch (OperationFailedException e) {
981  0 throw new AssemblyException("Error getting related formats", e);
982    }
983    }
984   
985    // Loop through all the formats in this course
986  25 for (FormatInfo format : course.getFormats()) {
987   
988    // If this is a course create/new format update then all formats will be created
989  51 if (NodeOperation.CREATE == operation
990    || (NodeOperation.UPDATE == operation && !currentformatIds.containsKey(format.getId()) )) {
991    // the format does not exist, so create
992    // Assemble and add the format
993  45 format.setState(course.getState());
994  45 BaseDTOAssemblyNode<FormatInfo, CluInfo> formatNode = formatAssembler
995    .disassemble(format, NodeOperation.CREATE);
996  45 formatNode.getNodeData().setState(course.getState());
997  45 results.add(formatNode);
998   
999   
1000    // Create the relationship and add it as well
1001  45 CluCluRelationInfo relation = new CluCluRelationInfo();
1002  45 relation.setCluId(nodeId);
1003  45 relation.setRelatedCluId(formatNode.getNodeData().getId());// this
1004    // should
1005    // already
1006    // be set even if
1007    // it's a create
1008  45 relation
1009    .setType(CourseAssemblerConstants.COURSE_FORMAT_RELATION_TYPE);
1010  45 relation.setState(course.getState());
1011   
1012  45 BaseDTOAssemblyNode<CourseInfo, CluCluRelationInfo> relationNode = new BaseDTOAssemblyNode<CourseInfo, CluCluRelationInfo>(
1013    null);
1014  45 relationNode.setNodeData(relation);
1015  45 relationNode.setOperation(NodeOperation.CREATE);
1016   
1017  45 results.add(relationNode);
1018  6 } else if (NodeOperation.UPDATE == operation
1019    && currentformatIds.containsKey(format.getId())) {
1020    // If the course already has this format, then just update the
1021    // format
1022  4 format.setState(course.getState());
1023  4 BaseDTOAssemblyNode<FormatInfo, CluInfo> formatNode = formatAssembler
1024    .disassemble(format, NodeOperation.UPDATE);
1025  4 formatNode.getNodeData().setState(course.getState());
1026  4 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  4 currentformatIds.remove(format.getId());
1031  2 } else if (NodeOperation.DELETE == operation
1032    && currentformatIds.containsKey(format.getId())) {
1033    // Delete the Format and its relation
1034  2 CluCluRelationInfo relationToDelete = new CluCluRelationInfo();
1035  2 relationToDelete.setId( currentformatIds.get(format.getId()) );
1036  2 BaseDTOAssemblyNode<CourseInfo, CluCluRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<CourseInfo, CluCluRelationInfo>(
1037    null);
1038  2 relationToDeleteNode.setNodeData(relationToDelete);
1039  2 relationToDeleteNode.setOperation(NodeOperation.DELETE);
1040  2 results.add(relationToDeleteNode);
1041   
1042  2 BaseDTOAssemblyNode<FormatInfo, CluInfo> formatNode = formatAssembler
1043    .disassemble(format, NodeOperation.DELETE);
1044  2 results.add(formatNode);
1045   
1046    // remove this entry from the map so we can tell what needs to
1047    // be deleted at the end
1048  2 currentformatIds.remove(format.getId());
1049    }
1050    }
1051   
1052    // Now any leftover format ids are no longer needed, so delete
1053    // formats and relations. These formats have to be assembled first before they can be marked for deletion
1054  25 for (Entry<String, String> entry : currentformatIds.entrySet()) {
1055    // Create a new relation with the id of the relation we want to
1056    // delete
1057  1 CluCluRelationInfo relationToDelete = new CluCluRelationInfo();
1058  1 relationToDelete.setId( entry.getValue() );
1059  1 BaseDTOAssemblyNode<CourseInfo, CluCluRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<CourseInfo, CluCluRelationInfo>(
1060    null);
1061  1 relationToDeleteNode.setNodeData(relationToDelete);
1062  1 relationToDeleteNode.setOperation(NodeOperation.DELETE);
1063  1 results.add(relationToDeleteNode);
1064   
1065  1 CluInfo formatCluToDelete = luService.getClu(entry.getKey());
1066  1 FormatInfo formatToDelete = formatAssembler.assemble(formatCluToDelete, null, false);
1067  1 BaseDTOAssemblyNode<FormatInfo, CluInfo> formatNode = formatAssembler
1068    .disassemble(formatToDelete, NodeOperation.DELETE);
1069  1 results.add(formatNode);
1070    }
1071   
1072  25 return results;
1073    }
1074   
 
1075  45 toggle private List<CourseVariationInfo> assembleVariations(List<CluIdentifierInfo> cluIdents) {
1076  45 List<CourseVariationInfo> variations = new ArrayList<CourseVariationInfo>();
1077  45 if (cluIdents != null) {
1078  45 for (CluIdentifierInfo cluIdent : cluIdents) {
1079  94 if (cluIdent.getType() != null &&
1080    cluIdent.getType().equals(CourseAssemblerConstants.COURSE_VARIATION_IDENT_TYPE)) {
1081  90 CourseVariationInfo variation = new CourseVariationInfo();
1082  90 variation.setId(cluIdent.getId());
1083  90 variation.setType(cluIdent.getType());
1084  90 variation.setCourseNumberSuffix(cluIdent.getSuffixCode());
1085  90 variation.setSubjectArea(cluIdent.getDivision());
1086  90 variation.setVariationCode(cluIdent.getVariation());
1087  90 variation.setVariationTitle(cluIdent.getLongName());
1088  90 variations.add(variation);
1089    }
1090    }
1091    }
1092  45 return variations;
1093    }
1094   
 
1095  45 toggle private List<CourseCrossListingInfo> assembleCrossListings(List<CluIdentifierInfo> cluIdents) {
1096  45 List<CourseCrossListingInfo> crossListings = new ArrayList<CourseCrossListingInfo>();
1097  45 if (cluIdents != null) {
1098  45 for (CluIdentifierInfo cluIdent : cluIdents) {
1099  94 if (cluIdent.getType() != null &&
1100    cluIdent.getType().equals(CourseAssemblerConstants.COURSE_CROSSLISTING_IDENT_TYPE)) {
1101  4 CourseCrossListingInfo crosslisting = new CourseCrossListingInfo();
1102  4 crosslisting.setId(cluIdent.getId());
1103  4 crosslisting.setCode(cluIdent.getCode());
1104  4 crosslisting.setAttributes(cluIdent.getAttributes());
1105  4 crosslisting.setType(cluIdent.getType());
1106  4 crosslisting.setCourseNumberSuffix(cluIdent.getSuffixCode());
1107  4 crosslisting.setSubjectArea(cluIdent.getDivision());
1108  4 crosslisting.setDepartment(cluIdent.getOrgId());
1109  4 crossListings.add(crosslisting);
1110    }
1111    }
1112    }
1113  45 return crossListings;
1114    }
1115   
1116    // TODO This is pretty much a copy of the disassembleJoints
1117    // code... maybe can be made generic
 
1118  25 toggle private List<BaseDTOAssemblyNode<?, ?>> disassembleJoints(String nodeId,
1119    CourseInfo course, NodeOperation operation)
1120    throws AssemblyException {
1121   
1122  25 List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
1123   
1124    // Get the current joints and put them in a map of joint id/relation
1125    // id
1126  25 Map<String, CluCluRelationInfo> currentJointIds = new HashMap<String, CluCluRelationInfo>();
1127   
1128  25 if (!NodeOperation.CREATE.equals(operation)) {
1129  11 try {
1130  11 List<CluCluRelationInfo> jointRelationships = luService
1131    .getCluCluRelationsByClu(course.getId());
1132  11 for (CluCluRelationInfo jointRelation : jointRelationships) {
1133  7 if (CourseAssemblerConstants.JOINT_RELATION_TYPE
1134    .equals(jointRelation.getType())) {
1135  0 currentJointIds.put(jointRelation.getId(),jointRelation);
1136    }
1137    }
1138    } catch (DoesNotExistException e) {
1139    } catch (InvalidParameterException e) {
1140  0 throw new AssemblyException("Error getting related formats", e);
1141    } catch (MissingParameterException e) {
1142  0 throw new AssemblyException("Error getting related formats", e);
1143    } catch (OperationFailedException e) {
1144  0 throw new AssemblyException("Error getting related formats", e);
1145    }
1146    }
1147   
1148    // Loop through all the joints in this course
1149  25 for (CourseJointInfo joint : course.getJoints()) {
1150   
1151    // If this is a course create then all joints will be created
1152  0 if (NodeOperation.UPDATE.equals(operation) && joint.getRelationId() != null
1153    && currentJointIds.containsKey(joint.getRelationId())) {
1154    // remove this entry from the map so we can tell what needs to
1155    // be deleted at the end
1156  0 CluCluRelationInfo relation = currentJointIds.remove(joint.getRelationId());
1157  0 relation.setRelatedCluId(joint.getCourseId());
1158  0 BaseDTOAssemblyNode<CourseJointInfo, CluCluRelationInfo> jointNode = new BaseDTOAssemblyNode<CourseJointInfo, CluCluRelationInfo>(courseJointAssembler);
1159  0 jointNode.setBusinessDTORef(joint);
1160  0 jointNode.setNodeData(relation);
1161  0 jointNode.setOperation(NodeOperation.UPDATE);
1162  0 jointNode.getNodeData().setState(course.getState());
1163  0 results.add(jointNode);
1164  0 } else if (!NodeOperation.DELETE.equals(operation)) {
1165    // the joint does not exist, so create cluclurelation
1166  0 BaseDTOAssemblyNode<CourseJointInfo, CluCluRelationInfo> jointNode = courseJointAssembler
1167    .disassemble(joint, NodeOperation.CREATE);
1168  0 jointNode.getNodeData().setCluId(nodeId);
1169  0 jointNode.getNodeData().setState(course.getState());
1170  0 results.add(jointNode);
1171    }
1172    }
1173   
1174    // Now any leftover joint ids are no longer needed, so delete
1175    // joint relations
1176  25 for (String id : currentJointIds.keySet()) {
1177    // Create a new relation with the id of the relation we want to
1178    // delete
1179  0 CluCluRelationInfo relationToDelete = new CluCluRelationInfo();
1180  0 relationToDelete.setId(id);
1181  0 BaseDTOAssemblyNode<CourseJointInfo, CluCluRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<CourseJointInfo, CluCluRelationInfo>(
1182    courseJointAssembler);
1183  0 relationToDeleteNode.setNodeData(relationToDelete);
1184  0 relationToDeleteNode.setOperation(NodeOperation.DELETE);
1185  0 results.add(relationToDeleteNode);
1186    }
1187   
1188  25 return results;
1189    }
1190   
1191    /**
1192    *
1193    * This method calculates code for course and cross listed course.
1194    *
1195    * @param subjectArea
1196    * @param suffixNumber
1197    * @return
1198    */
 
1199  2 toggle private String calculateCourseCode(String subjectArea, String suffixNumber) {
1200  2 return subjectArea + suffixNumber;
1201    }
1202   
 
1203  1 toggle public void setLuService(LuService luService) {
1204  1 this.luService = luService;
1205    }
1206   
 
1207  1 toggle public void setFormatAssembler(FormatAssembler formatAssembler) {
1208  1 this.formatAssembler = formatAssembler;
1209    }
1210   
 
1211  1 toggle public void setCourseJointAssembler(
1212    CourseJointAssembler courseJointAssembler) {
1213  1 this.courseJointAssembler = courseJointAssembler;
1214    }
1215   
 
1216  1 toggle public void setLoAssembler(LoAssembler loAssembler) {
1217  1 this.loAssembler = loAssembler;
1218    }
1219   
 
1220  1 toggle public void setLoService(LearningObjectiveService loService) {
1221  1 this.loService = loService;
1222    }
1223   
 
1224  1 toggle public void setCluAssemblerUtils(CluAssemblerUtils cluAssemblerUtils) {
1225  1 this.cluAssemblerUtils = cluAssemblerUtils;
1226    }
1227   
 
1228  1 toggle public void setLrcService(LrcService lrcService) {
1229  1 this.lrcService = lrcService;
1230    }
1231    }