View Javadoc
1   /*
2    * Copyright 2008 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.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/ecl2.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.ole.module.purap.batch.service.impl;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.ole.module.purap.PurapParameterConstants;
20  import org.kuali.ole.module.purap.batch.service.PurapRunDateService;
21  import org.kuali.ole.sys.service.impl.OleParameterConstants.PURCHASING_BATCH;
22  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
23  
24  import java.util.Calendar;
25  import java.util.Date;
26  import java.util.StringTokenizer;
27  
28  public class PurapRunDateServiceImpl implements PurapRunDateService {
29      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PurapRunDateServiceImpl.class);
30  
31      private ParameterService parameterService;
32  
33      /**
34       * Determines the date to assume when running the batch processes
35       */
36      public Date calculateRunDate(Date executionDate) {
37          Calendar currentCal = Calendar.getInstance();
38          currentCal.setTime(executionDate);
39  
40          CutoffTime cutoffTime = parseCutoffTime(retrieveCutoffTimeValue());
41  
42          if (isCurrentDateAfterCutoff(currentCal, cutoffTime)) {
43              // go back one day
44              currentCal.add(Calendar.DAY_OF_MONTH, 1);
45              adjustTimeOfDay(currentCal, true);
46          } else {
47              adjustTimeOfDay(currentCal, false);
48          }
49  
50          return currentCal.getTime();
51      }
52  
53      /**
54       * Adjusts the time of day if necessary, possibly depending on whether the execution time was before or after cutoff time
55       *
56       * @param calendar
57       * @param appliedCutoff true if the execution time was before the cutoff
58       */
59      protected void adjustTimeOfDay(Calendar calendar, boolean appliedCutoff) {
60          calendar.set(Calendar.HOUR_OF_DAY, 0);
61          calendar.set(Calendar.MINUTE, 0);
62          calendar.set(Calendar.SECOND, 0);
63          calendar.set(Calendar.MILLISECOND, 0);
64      }
65  
66      /**
67       * Determines if the given calendar time is before the given cutoff time
68       *
69       * @param currentCal the current time
70       * @param cutoffTime the "start of the day" cut off time
71       * @return true if the current time is before the cutoff, false otherwise
72       */
73      protected boolean isCurrentDateAfterCutoff(Calendar currentCal, CutoffTime cutoffTime) {
74          if (cutoffTime != null) {
75              // if cutoff date is not properly defined
76              // 24 hour clock (i.e. hour is 0 - 23)
77  
78              // clone the calendar so we get the same month, day, year
79              // then change the hour, minute, second fields
80              // then see if the cutoff is before or after
81              Calendar cutoffCal = (Calendar) currentCal.clone();
82              cutoffCal.setLenient(false);
83              cutoffCal.set(Calendar.HOUR_OF_DAY, cutoffTime.hour);
84              cutoffCal.set(Calendar.MINUTE, cutoffTime.minute);
85              cutoffCal.set(Calendar.SECOND, cutoffTime.second);
86              cutoffCal.set(Calendar.MILLISECOND, 0);
87  
88              return currentCal.after(cutoffCal);
89          }
90          // if cutoff date is not properly defined, then it is considered to be before the cutoff, that is, no cutoff date will be applied
91          return false;
92      }
93  
94      /**
95       * Holds the hour, minute, and second of a given cut off time
96       */
97      protected class CutoffTime {
98          /**
99           * 24 hour time, from 0-23, inclusive
100          */
101         protected int hour;
102 
103         /**
104          * From 0-59, inclusive
105          */
106         protected int minute;
107 
108         /**
109          * From 0-59, inclusive
110          */
111         protected int second;
112 
113         /**
114          * Constructs a RunDateServiceImpl instance
115          *
116          * @param hour   the cutoff hour
117          * @param minute the cutoff minute
118          * @param second the cutoff second
119          */
120         protected CutoffTime(int hour, int minute, int second) {
121             this.hour = hour;
122             this.minute = minute;
123             this.second = second;
124         }
125     }
126 
127     /**
128      * Parses a String representation of the cutoff time
129      *
130      * @param cutoffTime the cutoff time String to parse
131      * @return a record holding the cutoff time
132      */
133     protected CutoffTime parseCutoffTime(String cutoffTime) {
134         if (StringUtils.isBlank(cutoffTime)) {
135             return null;
136         } else {
137             cutoffTime = cutoffTime.trim();
138             if (LOG.isDebugEnabled()) {
139                 LOG.debug("Cutoff time value found: " + cutoffTime);
140             }
141             StringTokenizer st = new StringTokenizer(cutoffTime, ":", false);
142 
143             try {
144                 String hourStr = st.nextToken();
145                 String minuteStr = st.nextToken();
146                 String secondStr = st.nextToken();
147 
148                 int hourInt = Integer.parseInt(hourStr, 10);
149                 int minuteInt = Integer.parseInt(minuteStr, 10);
150                 int secondInt = Integer.parseInt(secondStr, 10);
151 
152                 if (hourInt < 0 || hourInt > 23 || minuteInt < 0 || minuteInt > 59 || secondInt < 0 || secondInt > 59) {
153                     throw new IllegalArgumentException("Cutoff time must be in the format \"HH:mm:ss\", where HH, mm, ss are defined in the java.text.SimpleDateFormat class.  In particular, 0 <= hour <= 23, 0 <= minute <= 59, and 0 <= second <= 59");
154                 }
155                 return new CutoffTime(hourInt, minuteInt, secondInt);
156             } catch (Exception e) {
157                 throw new IllegalArgumentException("Cutoff time should either be null, or in the format \"HH:mm:ss\", where HH, mm, ss are defined in the java.text.SimpleDateFormat class.");
158             }
159         }
160     }
161 
162     /**
163      * Retrieves the cutoff time from a repository.
164      *
165      * @return a time of day in the format "HH:mm:ss", where HH, mm, ss are defined in the java.text.SimpleDateFormat class. In
166      *         particular, 0 <= hour <= 23, 0 <= minute <= 59, and 0 <= second <= 59
167      */
168     protected String retrieveCutoffTimeValue() {
169         String value = parameterService.getParameterValueAsString(PURCHASING_BATCH.class, PurapParameterConstants.PRE_DISBURSEMENT_EXTRACT_CUTOFF_TIME);
170         if (StringUtils.isBlank(value)) {
171             LOG.info("Unable to retrieve parameter for PURAP process cutoff date.  Defaulting to no cutoff time (i.e. midnight)");
172             value = null;
173         }
174         return value;
175     }
176 
177     public void setParameterService(ParameterService parameterService) {
178         this.parameterService = parameterService;
179     }
180 }