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