Coverage Report - org.kuali.student.enrollment.class2.courseofferingset.service.decorators.CourseOfferingRolloverRunner
 
Classes in this File Line Coverage Branch Coverage Complexity
CourseOfferingRolloverRunner
0%
0/128
0%
0/36
2.524
 
 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.enrollment.acal.service.AcademicCalendarService;
 11  
 import org.kuali.student.enrollment.courseoffering.dto.CourseOfferingInfo;
 12  
 import org.kuali.student.enrollment.courseoffering.service.CourseOfferingService;
 13  
 import org.kuali.student.enrollment.courseofferingset.dto.SocRolloverResultInfo;
 14  
 import org.kuali.student.enrollment.courseofferingset.dto.SocRolloverResultItemInfo;
 15  
 import org.kuali.student.enrollment.courseofferingset.service.CourseOfferingSetService;
 16  
 import org.kuali.student.lum.course.service.CourseService;
 17  
 import org.kuali.student.r2.common.dto.ContextInfo;
 18  
 import org.kuali.student.r2.common.exceptions.AlreadyExistsException;
 19  
 import org.kuali.student.r2.common.exceptions.DataValidationErrorException;
 20  
 import org.kuali.student.r2.common.exceptions.OperationFailedException;
 21  
 import org.kuali.student.r2.common.util.RichTextHelper;
 22  
 import org.kuali.student.r2.common.util.constants.CourseOfferingSetServiceConstants;
 23  
 
 24  
 /**
 25  
  *
 26  
  * @author nwright
 27  
  */
 28  0
 public class CourseOfferingRolloverRunner implements Runnable {
 29  
 
 30  0
     final static Logger logger = Logger.getLogger(CourseOfferingRolloverRunner.class);
 31  
     private CourseOfferingService coService;
 32  
     private CourseOfferingSetService socService;
 33  
     private CourseService courseService;
 34  
     private AcademicCalendarService acalService;
 35  
     private ContextInfo context;
 36  
     private SocRolloverResultInfo result;
 37  
 
 38  
     public CourseOfferingService getCoService() {
 39  0
         return coService;
 40  
     }
 41  
 
 42  
     public void setCoService(CourseOfferingService coService) {
 43  0
         this.coService = coService;
 44  0
     }
 45  
 
 46  
     public CourseOfferingSetService getSocService() {
 47  0
         return socService;
 48  
     }
 49  
 
 50  
     public void setSocService(CourseOfferingSetService socService) {
 51  0
         this.socService = socService;
 52  0
     }
 53  
 
 54  
     public CourseService getCourseService() {
 55  0
         return courseService;
 56  
     }
 57  
 
 58  
     public void setCourseService(CourseService courseService) {
 59  0
         this.courseService = courseService;
 60  0
     }
 61  
 
 62  
     public AcademicCalendarService getAcalService() {
 63  0
         return acalService;
 64  
     }
 65  
 
 66  
     public void setAcalService(AcademicCalendarService acalService) {
 67  0
         this.acalService = acalService;
 68  0
     }
 69  
 
 70  
     public ContextInfo getContext() {
 71  0
         return context;
 72  
     }
 73  
 
 74  
     public void setContext(ContextInfo context) {
 75  0
         this.context = context;
 76  0
     }
 77  
 
 78  
     public SocRolloverResultInfo getResult() {
 79  0
         return result;
 80  
     }
 81  
 
 82  
     public void setResult(SocRolloverResultInfo result) {
 83  0
         this.result = result;
 84  0
     }
 85  
 
 86  
     private void loadOptionKeys() {
 87  0
         this.skipIfAlreadyExists = getBooleanOption(CourseOfferingSetServiceConstants.SKIP_IF_ALREADY_EXISTS_OPTION_KEY, false);
 88  0
         this.logSuccesses = getBooleanOption(CourseOfferingSetServiceConstants.LOG_SUCCESSES_OPTION_KEY, false);
 89  0
         this.progressFrequency = getIntOption(CourseOfferingSetServiceConstants.LOG_FREQUENCY_OPTION_KEY_PREFIX, 10);
 90  0
         this.haltErrorsMax = getIntOption(CourseOfferingSetServiceConstants.HALT_ERRORS_MAX_OPTION_KEY_PREFIX, 10);
 91  
 
 92  0
     }
 93  
     // TODO: implement these options
 94  0
     private boolean skipIfAlreadyExists = false;
 95  0
     private boolean logSuccesses = false;
 96  0
     private int progressFrequency = 100;
 97  0
     private int haltErrorsMax = -1;
 98  
 
 99  
     private boolean getBooleanOption(String key, boolean defValue) {
 100  0
         for (String optionKey : this.result.getOptionKeys()) {
 101  0
             if (optionKey.equals(key)) {
 102  0
                 return true;
 103  
             }
 104  
         }
 105  
         // default
 106  0
         return defValue;
 107  
     }
 108  
 
 109  
     private int getIntOption(String keyPrefix, int defValue) {
 110  0
         for (String optionKey : this.result.getOptionKeys()) {
 111  0
             if (optionKey.startsWith(keyPrefix)) {
 112  0
                 return Integer.parseInt(optionKey);
 113  
             }
 114  
         }
 115  
         // default
 116  0
         return defValue;
 117  
     }
 118  
 
 119  
     ////
 120  
     //// implement the run method
 121  
     ////  
 122  
     @Override
 123  
     public void run() {
 124  
         try {
 125  0
             runInternal();
 126  0
         } catch (Exception ex) {
 127  
             try {
 128  0
                 this.result = socService.getSocRolloverResult(result.getId(), context);
 129  0
                 this.result.setStateKey(CourseOfferingSetServiceConstants.ABORTED_RESULT_STATE_KEY);
 130  0
                 this.result.setMessage(new RichTextHelper().fromPlain("Got an unexpected exception running rolloever:\n" +
 131  
                         ex.toString()));
 132  0
                 this.socService.updateSocRolloverResult(result.getId(), result, context);
 133  0
             } catch (Exception ex1) {
 134  0
                 logger.fatal(result, ex);
 135  0
                 throw new RuntimeException(ex1);
 136  0
             }
 137  0
         }
 138  0
     }
 139  
 
 140  
     private void runInternal() throws Exception {
 141  0
         if (this.context == null) {
 142  0
             throw new NullPointerException("context not set");
 143  
         }
 144  0
         loadOptionKeys();
 145  
         // mark running
 146  0
         result = this.socService.getSocRolloverResult(result.getId(), context);
 147  0
         result.setStateKey(CourseOfferingSetServiceConstants.RUNNING_RESULT_STATE_KEY);
 148  0
         this.socService.updateSocRolloverResult(result.getId(), result, context);
 149  
         // Check if there are any course in the target soc
 150  0
         if (!skipIfAlreadyExists) {
 151  0
             List<String> targetCoIds = socService.getCourseOfferingIdsBySoc(this.result.getTargetSocId(), context);
 152  0
             if (!targetCoIds.isEmpty()) {
 153  0
                 throw new OperationFailedException(targetCoIds.size() + " course offerings already exist in the target soc");
 154  
             }
 155  
         }
 156  
         // mark the number expected
 157  0
         List<String> sourceCoIds = socService.getCourseOfferingIdsBySoc(this.result.getSourceSocId(), context);
 158  0
         result = this.socService.getSocRolloverResult(result.getId(), context);
 159  0
         result.setItemsProcessed(0);
 160  0
         result.setItemsExpected(sourceCoIds.size());
 161  0
         this.socService.updateSocRolloverResult(result.getId(), result, context);
 162  
 
 163  
         // Start processing
 164  0
         int i = 0;
 165  0
         int errors = 0;
 166  0
         List<SocRolloverResultItemInfo> items = new ArrayList<SocRolloverResultItemInfo>();
 167  0
         for (String sourceCoId : sourceCoIds) {
 168  0
             logger.info("Processing" + sourceCoId);
 169  0
             System.out.println("processing " + sourceCoId);
 170  
             try {
 171  0
                 SocRolloverResultItemInfo item = rolloverOneCourseOfferingReturningItem(sourceCoId);
 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 " + sourceCoId, ex);
 186  0
                 throw ex;
 187  0
             }
 188  0
             i++;
 189  
         }
 190  0
         reportProgress(items, i);
 191  
         // mark finished
 192  0
         result = socService.getSocRolloverResult(result.getId(), context);
 193  0
         result.setStateKey(CourseOfferingSetServiceConstants.FINISHED_RESULT_STATE_KEY);
 194  0
         this.socService.updateSocRolloverResult(result.getId(), result, 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(result.getId(), i, context);
 207  0
         if (!this.logSuccesses) {
 208  0
             stripSuccesses(items);
 209  
         }
 210  0
         if (!items.isEmpty()) {
 211  0
             Integer count = this.socService.createSocRolloverResultItems(result.getId(),
 212  
                     CourseOfferingSetServiceConstants.CREATE_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  
     private SocRolloverResultItemInfo rolloverOneCourseOfferingReturningItem(String sourceCoId) throws Exception {
 234  0
         CourseOfferingInfo targetCo = null;
 235  0
         String error = null;
 236  
         try {
 237  0
             targetCo = this.coService.rolloverCourseOffering(sourceCoId, this.result.getTargetTermId(), this.result.getOptionKeys(),
 238  
                     context);
 239  0
         } catch (AlreadyExistsException ex) {
 240  0
             error = ex.getMessage();
 241  0
         } catch (DataValidationErrorException ex) {
 242  0
             error = ex.getMessage();
 243  0
         }
 244  0
         SocRolloverResultItemInfo item = new SocRolloverResultItemInfo();
 245  0
         item.setSocRolloverResultId(result.getId());
 246  0
         item.setSourceCourseOfferingId(sourceCoId);
 247  0
         item.setTypeKey(CourseOfferingSetServiceConstants.CREATE_RESULT_ITEM_TYPE_KEY);
 248  0
         if (error == null) {
 249  0
             item.setStateKey(CourseOfferingSetServiceConstants.SUCCESS_RESULT_ITEM_STATE_KEY);
 250  0
             item.setTargetCourseOfferingId(targetCo.getId());
 251  0
             return item;
 252  
         }
 253  0
         item.setStateKey(CourseOfferingSetServiceConstants.ERROR_RESULT_ITEM_STATE_KEY);
 254  0
         item.setTargetCourseOfferingId(null);
 255  0
         item.setMessage(new RichTextHelper().fromPlain(error));
 256  0
         return item;
 257  
     }
 258  
 }