001 /*
002 * Copyright 2011 The Kuali Foundation.
003 *
004 * Licensed under the Educational Community License, Version 2.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/ecl2.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.kfs.gl.batch.service.impl;
017
018 import java.util.Calendar;
019 import java.util.Date;
020 import java.util.StringTokenizer;
021
022 import org.apache.commons.lang.StringUtils;
023 import org.kuali.kfs.gl.GeneralLedgerConstants;
024 import org.kuali.kfs.gl.batch.ScrubberStep;
025 import org.kuali.kfs.gl.batch.service.RunDateService;
026 import org.kuali.rice.kns.service.ParameterService;
027
028 /**
029 * The default implementation of RunDateService
030 */
031 public class RunDateServiceImpl implements RunDateService {
032 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RunDateServiceImpl.class);
033
034 private ParameterService parameterService;
035
036 /**
037 *
038 * @see org.kuali.kfs.gl.batch.service.RunDateService#calculateRunDate(java.util.Date)
039 */
040 public Date calculateRunDate(Date executionDate) {
041 Calendar currentCal = Calendar.getInstance();
042 currentCal.setTime(executionDate);
043
044 CutoffTime cutoffTime = parseCutoffTime(retrieveCutoffTimeValue());
045
046 if (isCurrentDateBeforeCutoff(currentCal, cutoffTime)) {
047 // time to set the date to the previous day's last minute/second
048 currentCal.add(Calendar.DAY_OF_MONTH, -1);
049 // per old COBOL code (see KULRNE-70),
050 // the time is set to 23:59:59 (assuming 0 ms)
051 currentCal.set(Calendar.HOUR_OF_DAY, 23);
052 currentCal.set(Calendar.MINUTE, 59);
053 currentCal.set(Calendar.SECOND, 59);
054 currentCal.set(Calendar.MILLISECOND, 0);
055 return new Date(currentCal.getTimeInMillis());
056 }
057 return new Date(executionDate.getTime());
058 }
059
060 /**
061 * Determines if the given calendar time is before the given cutoff time
062 *
063 * @param currentCal the current time
064 * @param cutoffTime the "start of the day" cut off time
065 * @return true if the current time is before the cutoff, false otherwise
066 */
067 protected boolean isCurrentDateBeforeCutoff(Calendar currentCal, CutoffTime cutoffTime) {
068 if (cutoffTime != null) {
069 // if cutoff date is not properly defined
070 // 24 hour clock (i.e. hour is 0 - 23)
071
072 // clone the calendar so we get the same month, day, year
073 // then change the hour, minute, second fields
074 // then see if the cutoff is before or after
075 Calendar cutoffCal = (Calendar) currentCal.clone();
076 cutoffCal.setLenient(false);
077 cutoffCal.set(Calendar.HOUR_OF_DAY, cutoffTime.hour);
078 cutoffCal.set(Calendar.MINUTE, cutoffTime.minute);
079 cutoffCal.set(Calendar.SECOND, cutoffTime.second);
080 cutoffCal.set(Calendar.MILLISECOND, 0);
081
082 return currentCal.before(cutoffCal);
083 }
084 // if cutoff date is not properly defined, then it is considered to be after the cutoff
085 return false;
086 }
087
088 /**
089 * Holds the hour, minute, and second of a given cut off time
090 */
091 protected class CutoffTime {
092 /**
093 * 24 hour time, from 0-23, inclusive
094 */
095 protected int hour;
096
097 /**
098 * From 0-59, inclusive
099 */
100 protected int minute;
101
102 /**
103 * From 0-59, inclusive
104 */
105 protected int second;
106
107 /**
108 * Constructs a RunDateServiceImpl instance
109 * @param hour the cutoff hour
110 * @param minute the cutoff minute
111 * @param second the cutoff second
112 */
113 protected CutoffTime(int hour, int minute, int second) {
114 this.hour = hour;
115 this.minute = minute;
116 this.second = second;
117 }
118 }
119
120 /**
121 * Parses a String representation of the cutoff time
122 *
123 * @param cutoffTime the cutoff time String to parse
124 * @return a record holding the cutoff time
125 */
126 protected CutoffTime parseCutoffTime(String cutoffTime) {
127 if (StringUtils.isBlank(cutoffTime)) {
128 return new CutoffTime(0, 0, 0);
129 }
130 else {
131 cutoffTime = cutoffTime.trim();
132 LOG.debug("Cutoff time value found: " + cutoffTime);
133 StringTokenizer st = new StringTokenizer(cutoffTime, ":", false);
134
135 try {
136 String hourStr = st.nextToken();
137 String minuteStr = st.nextToken();
138 String secondStr = st.nextToken();
139
140 int hourInt = Integer.parseInt(hourStr, 10);
141 int minuteInt = Integer.parseInt(minuteStr, 10);
142 int secondInt = Integer.parseInt(secondStr, 10);
143
144 if (hourInt < 0 || hourInt > 23 || minuteInt < 0 || minuteInt > 59 || secondInt < 0 || secondInt > 59) {
145 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");
146 }
147 return new CutoffTime(hourInt, minuteInt, secondInt);
148 }
149 catch (Exception e) {
150 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.");
151 }
152 }
153 }
154
155 /**
156 * Retrieves the cutoff time from a repository.
157 *
158 * @return a time of day in the format "HH:mm:ss", where HH, mm, ss are defined in the java.text.SimpleDateFormat class. In
159 * particular, 0 <= hour <= 23, 0 <= minute <= 59, and 0 <= second <= 59
160 */
161 protected String retrieveCutoffTimeValue() {
162 String value = parameterService.getParameterValue(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.SCRUBBER_CUTOFF_TIME);
163 if (StringUtils.isBlank(value)) {
164 LOG.error("Unable to retrieve parameter for GL process cutoff date. Defaulting to no cutoff time (i.e. midnight)");
165 value = null;
166 }
167 return value;
168 }
169
170 public void setParameterService(ParameterService parameterService) {
171 this.parameterService = parameterService;
172 }
173
174 }