Coverage Report - org.kuali.student.enrollment.class2.courseofferingset.service.decorators.CourseOfferingReverseRolloverRunner
 
Classes in this File Line Coverage Branch Coverage Complexity
CourseOfferingReverseRolloverRunner
0%
0/141
0%
0/46
2.56
 
 1  
 /*
 2  
  * To change this template, choose Tools | Templates
 3  
  * and open the template in the editor.
 4  
  */
 5  
 package org.kuali.student.enrollment.class2.courseofferingset.service.decorators;
 6  
 
 7  
 import org.apache.log4j.Logger;
 8  
 import java.util.ArrayList;
 9  
 import java.util.List;
 10  
 import org.kuali.student.common.versionmanagement.dto.VersionDisplayInfo;
 11  
 import org.kuali.student.enrollment.acal.dto.TermInfo;
 12  
 import org.kuali.student.enrollment.acal.service.AcademicCalendarService;
 13  
 import org.kuali.student.enrollment.courseoffering.dto.ActivityOfferingInfo;
 14  
 import org.kuali.student.enrollment.courseoffering.dto.FormatOfferingInfo;
 15  
 import org.kuali.student.enrollment.courseoffering.service.CourseOfferingService;
 16  
 import org.kuali.student.enrollment.courseofferingset.dto.SocRolloverResultInfo;
 17  
 import org.kuali.student.enrollment.courseofferingset.dto.SocRolloverResultItemInfo;
 18  
 import org.kuali.student.enrollment.courseofferingset.service.CourseOfferingSetService;
 19  
 import org.kuali.student.lum.course.dto.CourseInfo;
 20  
 import org.kuali.student.lum.course.service.CourseService;
 21  
 import org.kuali.student.lum.lu.service.LuServiceConstants;
 22  
 import org.kuali.student.r2.common.dto.ContextInfo;
 23  
 import org.kuali.student.r2.common.exceptions.DoesNotExistException;
 24  
 import org.kuali.student.r2.common.exceptions.OperationFailedException;
 25  
 import org.kuali.student.r2.common.util.RichTextHelper;
 26  
 import org.kuali.student.r2.common.util.constants.CourseOfferingSetServiceConstants;
 27  
 
 28  
 /**
 29  
  *
 30  
  * @author nwright
 31  
  */
 32  0
 public class CourseOfferingReverseRolloverRunner implements Runnable {
 33  
 
 34  0
     final static Logger logger = Logger.getLogger(CourseOfferingRolloverRunner.class);
 35  
     private CourseOfferingService coService;
 36  
     private CourseOfferingSetService socService;
 37  
     private CourseService courseService;
 38  
     private AcademicCalendarService acalService;
 39  
     private ContextInfo context;
 40  
     private SocRolloverResultInfo rolloverResult;
 41  
     private SocRolloverResultInfo reverseResult;
 42  
 
 43  
     public CourseOfferingService getCoService() {
 44  0
         return coService;
 45  
     }
 46  
 
 47  
     public void setCoService(CourseOfferingService coService) {
 48  0
         this.coService = coService;
 49  0
     }
 50  
 
 51  
     public CourseOfferingSetService getSocService() {
 52  0
         return socService;
 53  
     }
 54  
 
 55  
     public void setSocService(CourseOfferingSetService socService) {
 56  0
         this.socService = socService;
 57  0
     }
 58  
 
 59  
     public CourseService getCourseService() {
 60  0
         return courseService;
 61  
     }
 62  
 
 63  
     public void setCourseService(CourseService courseService) {
 64  0
         this.courseService = courseService;
 65  0
     }
 66  
 
 67  
     public AcademicCalendarService getAcalService() {
 68  0
         return acalService;
 69  
     }
 70  
 
 71  
     public void setAcalService(AcademicCalendarService acalService) {
 72  0
         this.acalService = acalService;
 73  0
     }
 74  
 
 75  
     public ContextInfo getContext() {
 76  0
         return context;
 77  
     }
 78  
 
 79  
     public void setContext(ContextInfo context) {
 80  0
         this.context = context;
 81  0
     }
 82  
 
 83  
     public SocRolloverResultInfo getReverseResult() {
 84  0
         return reverseResult;
 85  
     }
 86  
 
 87  
     public void setReverseResult(SocRolloverResultInfo reverseResult) {
 88  0
         this.reverseResult = reverseResult;
 89  0
     }
 90  
 
 91  
     public SocRolloverResultInfo getRolloverResult() {
 92  0
         return rolloverResult;
 93  
     }
 94  
 
 95  
     public void setRolloverResult(SocRolloverResultInfo rolloverResult) {
 96  0
         this.rolloverResult = rolloverResult;
 97  0
     }
 98  
 
 99  
     private void loadOptions() {
 100  0
         this.justCreates = getBooleanOption(CourseOfferingSetServiceConstants.REVERSE_JUST_CREATES_OPTION_KEY, false);
 101  0
         this.logSuccesses = getBooleanOption(CourseOfferingSetServiceConstants.LOG_SUCCESSES_OPTION_KEY, false);
 102  0
         this.progressFrequency = getIntOption(CourseOfferingSetServiceConstants.LOG_FREQUENCY_OPTION_KEY_PREFIX, 10);
 103  0
         this.haltErrorsMax = getIntOption(CourseOfferingSetServiceConstants.HALT_ERRORS_MAX_OPTION_KEY_PREFIX, 10);
 104  
 
 105  0
     }
 106  
     // TODO: implement these options
 107  0
     private boolean justCreates = false;
 108  0
     private boolean logSuccesses = false; // implemented
 109  0
     private int progressFrequency = 100; // implemented
 110  0
     private int haltErrorsMax = -1; // implemented
 111  
 
 112  
     private boolean getBooleanOption(String key, boolean defValue) {
 113  0
         for (String optionKey : this.reverseResult.getOptionKeys()) {
 114  0
             if (optionKey.equals(key)) {
 115  0
                 return true;
 116  
             }
 117  
         }
 118  
         // default
 119  0
         return defValue;
 120  
     }
 121  
 
 122  
     private int getIntOption(String keyPrefix, int defValue) {
 123  0
         for (String optionKey : this.reverseResult.getOptionKeys()) {
 124  0
             if (optionKey.startsWith(keyPrefix)) {
 125  0
                 return Integer.parseInt(optionKey);
 126  
             }
 127  
         }
 128  
         // default
 129  0
         return defValue;
 130  
     }
 131  
 
 132  
     ////
 133  
     //// implement the run method
 134  
     ////  
 135  
     @Override
 136  
     public void run() {
 137  
         try {
 138  0
             runInternal();
 139  0
         } catch (Exception ex) {
 140  
             try {
 141  0
                 reverseResult = this.socService.getSocRolloverResult(reverseResult.getId(), context);
 142  0
                 this.reverseResult.setStateKey(CourseOfferingSetServiceConstants.ABORTED_RESULT_STATE_KEY);
 143  0
                 this.reverseResult.setMessage(new RichTextHelper().fromPlain("Got an unexpected exception running rolloever:\n" +
 144  
                         ex.toString()));
 145  0
                 this.socService.updateSocRolloverResult(reverseResult.getId(), reverseResult, context);
 146  0
             } catch (Exception ex1) {
 147  0
                 logger.fatal(reverseResult, ex);
 148  0
                 throw new RuntimeException(ex1);
 149  0
             }
 150  0
         }
 151  0
     }
 152  
 
 153  
     private void runInternal() throws Exception {
 154  0
         this.loadOptions();
 155  
         // mark running
 156  0
         reverseResult.setStateKey(CourseOfferingSetServiceConstants.RUNNING_RESULT_STATE_KEY);
 157  0
         this.socService.updateSocRolloverResult(reverseResult.getId(), reverseResult, context);
 158  
         // Check if there are any course in the target soc
 159  0
         List<String> targetCoIds = socService.getCourseOfferingIdsBySoc(this.reverseResult.getTargetSocId(), context);
 160  0
         reverseResult.setItemsProcessed(0);
 161  0
         reverseResult.setItemsExpected(targetCoIds.size());
 162  0
         this.socService.updateSocRolloverResult(reverseResult.getId(), reverseResult, context);
 163  
 
 164  
         // Start processing
 165  0
         int i = 0;
 166  0
         int errors = 0;
 167  0
         List<SocRolloverResultItemInfo> items = new ArrayList<SocRolloverResultItemInfo>();
 168  0
         for (String targetCoId : targetCoIds) {
 169  0
             logger.info("Processing" + targetCoId);
 170  
             try {
 171  0
                 SocRolloverResultItemInfo item = reverseOneCourseOffering(targetCoId);
 172  0
                 items.add(item);
 173  0
                 reportProgressIfModulo(items, i);
 174  0
                 if (!item.getStateKey().equals(CourseOfferingSetServiceConstants.SUCCESS_RESULT_ITEM_STATE_KEY)) {
 175  0
                     errors++;
 176  0
                     if (this.haltErrorsMax != -1) {
 177  0
                         if (errors > this.haltErrorsMax) {
 178  0
                             throw new OperationFailedException("Too many errors, exceeded the halt threshold: " + errors +
 179  
                                     " out of " + i + " course offerings rolled over");
 180  
                         }
 181  
                     }
 182  
                 }
 183  0
             } catch (Exception ex) {
 184  
                 // log some conetxt for the exception
 185  0
                 logger.fatal("failed while processing the " + i + "th course offering " + targetCoId, ex);
 186  0
                 throw ex;
 187  0
             }
 188  0
             i++;
 189  
         }
 190  0
         reportProgress(items, i);
 191  
         // mark finished
 192  0
         reverseResult = this.socService.getSocRolloverResult(reverseResult.getId(), context);
 193  0
         reverseResult.setStateKey(CourseOfferingSetServiceConstants.FINISHED_RESULT_STATE_KEY);
 194  0
         this.socService.updateSocRolloverResult(reverseResult.getId(), reverseResult, context);
 195  0
     }
 196  
 
 197  
     private void reportProgressIfModulo(List<SocRolloverResultItemInfo> items, int i) throws Exception {
 198  0
         int modulo = i % progressFrequency;
 199  0
         if (modulo != 0) {
 200  0
             return;
 201  
         }
 202  0
         this.reportProgress(items, i);
 203  0
     }
 204  
 
 205  
     private void reportProgress(List<SocRolloverResultItemInfo> items, int i) throws Exception {
 206  0
         this.socService.updateSocRolloverProgress(reverseResult.getId(), i, context);
 207  0
         if (!this.logSuccesses) {
 208  0
             stripSuccesses(items);
 209  
         }
 210  0
         if (!items.isEmpty()) {
 211  0
             this.socService.createSocRolloverResultItems(reverseResult.getId(),
 212  
                     CourseOfferingSetServiceConstants.DELETE_RESULT_ITEM_TYPE_KEY,
 213  
                     items,
 214  
                     context);
 215  
         }
 216  0
         items.clear();
 217  0
     }
 218  
 
 219  
     private void stripSuccesses(List<SocRolloverResultItemInfo> items) {
 220  0
         List<SocRolloverResultItemInfo> list = new ArrayList<SocRolloverResultItemInfo>();
 221  0
         for (SocRolloverResultItemInfo item : items) {
 222  0
             if (!item.getStateKey().equals(CourseOfferingSetServiceConstants.SUCCESS_RESULT_ITEM_STATE_KEY)) {
 223  0
                 list.add(item);
 224  
             }
 225  
         }
 226  0
         if (items.size() != list.size()) {
 227  0
             items.clear();
 228  0
             items.addAll(list);
 229  
         }
 230  0
     }
 231  
 
 232  
     //
 233  
     // TODO: push this logic into the course offering service 
 234  
     private SocRolloverResultItemInfo reverseOneCourseOffering(String coId) throws Exception {
 235  0
         if (this.justCreates) {
 236  0
             if (!this.wasCreatedInRollover(coId)) {
 237  0
                 SocRolloverResultItemInfo item = new SocRolloverResultItemInfo();
 238  0
                 item.setSocRolloverResultId(reverseResult.getId());
 239  0
                 item.setTypeKey(CourseOfferingSetServiceConstants.DELETE_RESULT_ITEM_TYPE_KEY);
 240  0
                 item.setStateKey(CourseOfferingSetServiceConstants.INFO_RESULT_ITEM_STATE_KEY);
 241  0
                 item.setSourceCourseOfferingId(coId);
 242  0
                 item.setTargetCourseOfferingId(coId);
 243  0
                 item.setMessage(new RichTextHelper().fromPlain(
 244  
                         "Skipped because course offering was not created in the original rollover"));
 245  0
                 return item;
 246  
             }
 247  
         }
 248  
         // TODO: add a cascading delete for course offferings
 249  0
         for (FormatOfferingInfo fo : this.coService.getFormatOfferingsByCourseOffering(coId, context)) {
 250  0
             for (ActivityOfferingInfo ao : this.coService.getActivityOfferingsByFormatOffering(fo.getId(), context)) {
 251  0
                 coService.deleteActivityOffering(ao.getId(), context);
 252  
             }
 253  0
             coService.deleteFormatOffering(fo.getId(), context);
 254  
         }
 255  0
         this.coService.deleteCourseOffering(coId, context);
 256  
         //
 257  0
         SocRolloverResultItemInfo item = new SocRolloverResultItemInfo();
 258  0
         item.setSocRolloverResultId(reverseResult.getId());
 259  0
         item.setTypeKey(CourseOfferingSetServiceConstants.DELETE_RESULT_ITEM_TYPE_KEY);
 260  0
         item.setStateKey(CourseOfferingSetServiceConstants.SUCCESS_RESULT_ITEM_STATE_KEY);
 261  0
         item.setSourceCourseOfferingId(coId);
 262  0
         item.setTargetCourseOfferingId(coId);
 263  0
         return item;
 264  
     }
 265  
 
 266  
     private boolean wasCreatedInRollover(String coId) throws Exception {
 267  0
         List<SocRolloverResultItemInfo> list = this.socService.getSocRolloverResultItemsByResultIdAndTargetCourseOfferingId(
 268  
                 rolloverResult.getId(), coId, context);
 269  0
         if (list.isEmpty()) {
 270  0
             return false;
 271  
         }
 272  0
         for (SocRolloverResultItemInfo item : list) {
 273  0
             if (coId.equals(item.getTargetCourseOfferingId())) {
 274  0
                 if (item.getStateKey().equals(CourseOfferingSetServiceConstants.SUCCESS_RESULT_ITEM_STATE_KEY)) {
 275  0
                     if (item.getTypeKey().equals(CourseOfferingSetServiceConstants.CREATE_RESULT_ITEM_TYPE_KEY)) {
 276  0
                         return true;
 277  
                     }
 278  
                 }
 279  
             }
 280  
         }
 281  0
         return false;
 282  
     }
 283  
     // deal with R1 exception converting them to R2 exceptions
 284  
 
 285  
     private CourseInfo getCourse(String courseId) throws Exception {
 286  0
         CourseInfo course = null;
 287  
         try {
 288  0
             course = courseService.getCourse(courseId);
 289  0
         } catch (org.kuali.student.common.exceptions.DoesNotExistException e) {
 290  0
             throw new DoesNotExistException("The course does not exist. course: " + courseId, e);
 291  0
         } catch (Exception e) {
 292  0
             throw new OperationFailedException("unxpected trying to get course " + courseId, e);
 293  0
         }
 294  0
         return course;
 295  
     }
 296  
 }