001 /* 002 * Copyright 2007 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 1.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl1.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.student.lum.program.service.assembler; 017 018 import java.util.ArrayList; 019 import java.util.List; 020 import java.util.Map; 021 022 import org.apache.log4j.Logger; 023 import org.kuali.student.common.assembly.BOAssembler; 024 import org.kuali.student.common.assembly.BaseDTOAssemblyNode; 025 import org.kuali.student.common.assembly.BaseDTOAssemblyNode.NodeOperation; 026 import org.kuali.student.common.assembly.data.AssemblyException; 027 import org.kuali.student.common.dto.AmountInfo; 028 import org.kuali.student.common.dto.DtoConstants; 029 import org.kuali.student.common.exceptions.DataValidationErrorException; 030 import org.kuali.student.common.exceptions.DoesNotExistException; 031 import org.kuali.student.common.exceptions.InvalidParameterException; 032 import org.kuali.student.common.exceptions.MissingParameterException; 033 import org.kuali.student.common.exceptions.OperationFailedException; 034 import org.kuali.student.lum.course.service.assembler.CourseAssembler; 035 import org.kuali.student.lum.lu.dto.CluCluRelationInfo; 036 import org.kuali.student.lum.lu.dto.CluInfo; 037 import org.kuali.student.lum.lu.service.LuService; 038 import org.kuali.student.lum.program.dto.CoreProgramInfo; 039 import org.kuali.student.lum.program.dto.MajorDisciplineInfo; 040 import org.kuali.student.lum.program.dto.ProgramVariationInfo; 041 import org.kuali.student.lum.service.assembler.CluAssemblerUtils; 042 043 044 /** 045 * @author KS TODO - Much of this should be shared with ProgramVariationAssembler (and probably other Program Assemblers to 046 * come). AssemblerUtils? 047 */ 048 public class MajorDisciplineAssembler implements BOAssembler<MajorDisciplineInfo, CluInfo> { 049 final static Logger LOG = Logger.getLogger(CourseAssembler.class); 050 051 private LuService luService; 052 053 private ProgramVariationAssembler programVariationAssembler; 054 private CoreProgramAssembler coreProgramAssembler; 055 private CluAssemblerUtils cluAssemblerUtils; 056 private ProgramAssemblerUtils programAssemblerUtils; 057 058 @Override 059 public MajorDisciplineInfo assemble(CluInfo clu, MajorDisciplineInfo majorDiscipline, boolean shallowBuild) throws AssemblyException { 060 MajorDisciplineInfo mdInfo = (null != majorDiscipline) ? majorDiscipline : new MajorDisciplineInfo(); 061 062 // Copy all the data from the clu to the majordiscipline 063 programAssemblerUtils.assembleBasics(clu, mdInfo); 064 programAssemblerUtils.assembleIdentifiers(clu, mdInfo); 065 programAssemblerUtils.assembleBasicAdminOrgs(clu, mdInfo); 066 programAssemblerUtils.assembleFullOrgs(clu, mdInfo); 067 programAssemblerUtils.assembleAtps(clu, mdInfo); 068 programAssemblerUtils.assembleLuCodes(clu, mdInfo); 069 070 mdInfo.setIntensity((null != clu.getIntensity()) ? clu.getIntensity().getUnitType() : null); 071 mdInfo.setStdDuration(clu.getStdDuration()); 072 mdInfo.setPublishedInstructors(clu.getInstructors()); 073 mdInfo.setCampusLocations(clu.getCampusLocations()); 074 mdInfo.setAccreditingAgencies(clu.getAccreditations()); 075 mdInfo.setEffectiveDate(clu.getEffectiveDate()); 076 mdInfo.setDescr(clu.getDescr()); 077 mdInfo.setVersionInfo(clu.getVersionInfo()); 078 mdInfo.setNextReviewPeriod(clu.getNextReviewPeriod()); 079 080 if (!shallowBuild) { 081 programAssemblerUtils.assembleRequirements(clu, mdInfo); 082 mdInfo.setCredentialProgramId(programAssemblerUtils.getCredentialProgramID(clu.getId())); 083 mdInfo.setResultOptions(programAssemblerUtils.assembleResultOptions(clu.getId())); 084 mdInfo.setLearningObjectives(cluAssemblerUtils.assembleLos(clu.getId(), shallowBuild)); 085 mdInfo.setVariations(assembleVariations(clu.getId(), shallowBuild)); 086 mdInfo.setOrgCoreProgram(assembleCoreProgram(clu.getId(), shallowBuild)); 087 programAssemblerUtils.assemblePublications(clu, mdInfo); 088 } 089 090 return mdInfo; 091 } 092 093 private CoreProgramInfo assembleCoreProgram(String cluId, boolean shallowBuild) throws AssemblyException { 094 CoreProgramInfo coreProgramInfo = null; 095 try { 096 List<CluInfo> corePrograms = luService.getRelatedClusByCluId(cluId, ProgramAssemblerConstants.HAS_CORE_PROGRAM); 097 // TODO - is it an error if there's more than one core program? 098 if (corePrograms.size() == 1) { 099 coreProgramInfo = coreProgramAssembler.assemble(corePrograms.get(0), null, shallowBuild); 100 } else if (corePrograms.size() > 1) { 101 throw new AssemblyException(new DataValidationErrorException("MajorDiscipline has more than one associated Core Program")); 102 } 103 } catch (Exception e) { 104 throw new AssemblyException(e); 105 } 106 return coreProgramInfo; 107 } 108 109 private List<ProgramVariationInfo> assembleVariations(String cluId, boolean shallowBuild) throws AssemblyException { 110 List<ProgramVariationInfo> variations = new ArrayList<ProgramVariationInfo>(); 111 112 try { 113 Map<String, CluCluRelationInfo> currentRelations = null; 114 currentRelations = programAssemblerUtils.getCluCluActiveRelations(cluId, ProgramAssemblerConstants.HAS_PROGRAM_VARIATION); 115 116 if(currentRelations != null && !currentRelations.isEmpty()){ 117 for (String variationId : currentRelations.keySet()) { 118 CluInfo variationClu = luService.getClu(variationId); 119 variations.add(programVariationAssembler.assemble(variationClu, null, shallowBuild)); 120 } 121 } 122 } catch (Exception e) { 123 throw new AssemblyException(e); 124 } 125 return variations; 126 } 127 128 @Override 129 public BaseDTOAssemblyNode<MajorDisciplineInfo, CluInfo> disassemble(MajorDisciplineInfo major, NodeOperation operation) throws AssemblyException { 130 if (major == null) { 131 LOG.error("Major for disassemble is null!"); 132 throw new AssemblyException("Major cannot be null"); 133 } 134 135 //TODO IDs for objects w/o ids 136 137 BaseDTOAssemblyNode<MajorDisciplineInfo, CluInfo> result = new BaseDTOAssemblyNode<MajorDisciplineInfo, CluInfo>( 138 this); 139 140 CluInfo clu; 141 try { 142 clu = (NodeOperation.UPDATE == operation) ? luService.getClu(major.getId()) : new CluInfo(); 143 } catch (Exception e) { 144 throw new AssemblyException("Error getting existing learning unit during major update", e); 145 } 146 147 boolean stateChanged = NodeOperation.UPDATE == operation && major.getState() != null && !major.getState().equals(clu.getState()); 148 149 programAssemblerUtils.disassembleBasics(clu, major); 150 if (major.getId() == null) 151 major.setId(clu.getId()); 152 programAssemblerUtils.disassembleLuCodes(clu, major, operation); 153 programAssemblerUtils.disassembleAdminOrgs(clu, major, operation); 154 programAssemblerUtils.disassembleAtps(clu, major, operation); 155 programAssemblerUtils.disassembleIdentifiers(clu, major, operation); 156 programAssemblerUtils.disassemblePublications(clu, major, operation, result); 157 158 if(major.getProgramRequirements() != null && !major.getProgramRequirements().isEmpty()) { 159 programAssemblerUtils.disassembleRequirements(clu, major, operation, result, stateChanged); 160 } 161 162 if (major.getVariations() != null && !major.getVariations().isEmpty()) { 163 try { 164 disassembleVariations(major, operation, result); 165 } catch (Exception e) { 166 throw new AssemblyException("Error diassembling Variations during major update", e); 167 } 168 } 169 if (major.getOrgCoreProgram() != null ) { 170 disassembleCoreProgram(major, operation, result); 171 } 172 if (major.getCredentialProgramId() != null) { 173 disassembleCredentialProgram(major, operation, result); 174 } 175 if (major.getResultOptions() != null) { 176 disassembleResultOptions(major, operation, result); 177 } 178 if (major.getLearningObjectives() != null) { 179 disassembleLearningObjectives(major, operation, result); 180 } 181 182 AmountInfo intensity = new AmountInfo(); 183 intensity.setUnitType(major.getIntensity()); 184 clu.setIntensity(intensity); 185 clu.setStdDuration(major.getStdDuration()); 186 clu.setInstructors(major.getPublishedInstructors()); 187 188 clu.setNextReviewPeriod(major.getNextReviewPeriod()); 189 clu.setEffectiveDate(major.getEffectiveDate()); 190 191 clu.setCampusLocations(major.getCampusLocations()); 192 clu.setDescr(major.getDescr()); 193 194 clu.setAccreditations(major.getAccreditingAgencies()); 195 clu.setNextReviewPeriod(major.getNextReviewPeriod()); 196 clu.setState(major.getState()); 197 198 // Add the Clu to the result 199 result.setNodeData(clu); 200 result.setOperation(operation); 201 result.setBusinessDTORef(major); 202 203 return result; 204 } 205 206 private void disassembleLearningObjectives(MajorDisciplineInfo major, NodeOperation operation, BaseDTOAssemblyNode<MajorDisciplineInfo, CluInfo> result) throws AssemblyException { 207 try { 208 List<BaseDTOAssemblyNode<?, ?>> loResults = cluAssemblerUtils.disassembleLos(major.getId(), major.getState(), major.getLearningObjectives(), operation); 209 if (loResults != null) { 210 result.getChildNodes().addAll(loResults); 211 } 212 } catch (DoesNotExistException e) { 213 } catch (Exception e) { 214 throw new AssemblyException("Error while disassembling los", e); 215 } 216 } 217 218 private void disassembleResultOptions(MajorDisciplineInfo major, NodeOperation operation, BaseDTOAssemblyNode<MajorDisciplineInfo, CluInfo> result) throws AssemblyException { 219 //TODO Check for ProgramAssemblerConstants.CERTIFICATE_RESULTS too 220 221 BaseDTOAssemblyNode<?, ?> degreeResults = cluAssemblerUtils.disassembleCluResults( 222 major.getId(), major.getState(), major.getResultOptions(), operation, ProgramAssemblerConstants.DEGREE_RESULTS, "Result options", "Result option"); 223 if (degreeResults != null) { 224 result.getChildNodes().add(degreeResults); 225 } 226 } 227 228 private void disassembleCredentialProgram(MajorDisciplineInfo major, NodeOperation operation, BaseDTOAssemblyNode<MajorDisciplineInfo, CluInfo> result) throws AssemblyException { 229 230 List<BaseDTOAssemblyNode<?,?>> credentialResults; 231 try { 232 credentialResults = programAssemblerUtils.disassembleCredentialProgram(major, operation, ProgramAssemblerConstants.HAS_MAJOR_PROGRAM); 233 if (credentialResults != null) { 234 result.getChildNodes().addAll(credentialResults); 235 } 236 } catch (Exception e) { 237 throw new AssemblyException("Error while disassembling Credential program", e); 238 } 239 } 240 241 private void disassembleVariations(MajorDisciplineInfo major, NodeOperation operation, BaseDTOAssemblyNode<MajorDisciplineInfo, CluInfo> result) throws AssemblyException, DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException { 242 Map<String, CluCluRelationInfo> currentRelations = null; 243 List<BaseDTOAssemblyNode<?, ?>> nodes = new ArrayList<BaseDTOAssemblyNode<?, ?>>(); 244 245 if (!NodeOperation.CREATE.equals(operation)){ 246 currentRelations = programAssemblerUtils.getCluCluActiveRelations(major.getId(), ProgramAssemblerConstants.HAS_PROGRAM_VARIATION); 247 } 248 249 // Loop through all the variations in this MD 250 for (ProgramVariationInfo variation : major.getVariations()) { 251 BaseDTOAssemblyNode<?,?> variationNode; 252 variation.setState(major.getState()); 253 try { 254 if (NodeOperation.UPDATE.equals(operation) && variation.getId() != null 255 && (currentRelations != null && currentRelations.containsKey(variation.getId()))) { 256 // If the relationship already exists update it 257 // remove this entry from the map so we can tell what needs to be deleted at the end 258 variationNode = programVariationAssembler.disassemble(variation, operation); 259 if (variationNode != null) nodes.add(variationNode); 260 currentRelations.remove(variation.getId()); 261 } else if (!NodeOperation.DELETE.equals(operation)) { 262 // the variation does not exist, so create variation & cluclurelation 263 variationNode = programVariationAssembler.disassemble(variation, NodeOperation.CREATE); 264 if (variationNode != null) nodes.add(variationNode); 265 programAssemblerUtils.addCreateRelationNode(major.getId(), variation.getId(), ProgramAssemblerConstants.HAS_PROGRAM_VARIATION, nodes); 266 } 267 } catch (Exception e) { 268 throw new AssemblyException("Error while disassembling Variation", e); 269 } 270 } 271 272 // Now any leftover variation ids are no longer needed, so suspend them 273 if(currentRelations != null && currentRelations.size() > 0){ 274 programAssemblerUtils.addSuspendedRelationNodes(currentRelations, nodes); 275 addInactivateVariationNodes(currentRelations, nodes); 276 } 277 278 result.getChildNodes().addAll(nodes); 279 } 280 281 private void addInactivateVariationNodes(Map<String, CluCluRelationInfo> currentRelations, List<BaseDTOAssemblyNode<?, ?>> nodes) throws AssemblyException{ 282 for (String variationId : currentRelations.keySet()) { 283 CluInfo variationClu; 284 try { 285 variationClu = luService.getClu(variationId); 286 ProgramVariationInfo delVariation = programVariationAssembler.assemble(variationClu, null, true); 287 delVariation.setState(DtoConstants.STATE_SUSPENDED); 288 BaseDTOAssemblyNode<?,?> variationNode = programVariationAssembler.disassemble(delVariation , NodeOperation.UPDATE); 289 if (variationNode != null) nodes.add(variationNode); 290 } catch (Exception e) { 291 throw new AssemblyException("Error while disassembling variation, deactivateVariations", e); 292 } 293 } 294 } 295 296 private void disassembleCoreProgram(MajorDisciplineInfo major, NodeOperation operation, BaseDTOAssemblyNode<MajorDisciplineInfo, CluInfo> result) throws AssemblyException { 297 298 BaseDTOAssemblyNode<?,?> coreResults; 299 try { 300 major.getOrgCoreProgram().setState(major.getState()); 301 coreResults = coreProgramAssembler.disassemble(major.getOrgCoreProgram(), operation); 302 if (coreResults != null) { 303 result.getChildNodes().add(coreResults); 304 } 305 } catch (Exception e) { 306 throw new AssemblyException("Error while disassembling Core program", e); 307 } 308 } 309 310 // Setters for Spring 311 public void setLuService(LuService luService) { 312 this.luService = luService; 313 } 314 315 public void setProgramVariationAssembler(ProgramVariationAssembler programVariationAssembler) { 316 this.programVariationAssembler = programVariationAssembler; 317 } 318 319 public ProgramVariationAssembler getProgramVariationAssembler() { 320 return programVariationAssembler; 321 } 322 323 public void setCoreProgramAssembler(CoreProgramAssembler coreProgramAssembler) { 324 this.coreProgramAssembler = coreProgramAssembler; 325 } 326 327 public void setCluAssemblerUtils(CluAssemblerUtils cluAssemblerUtils) { 328 this.cluAssemblerUtils = cluAssemblerUtils; 329 } 330 331 public void setProgramAssemblerUtils(ProgramAssemblerUtils programAssemblerUtils) { 332 this.programAssemblerUtils = programAssemblerUtils; 333 } 334 }