/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.gl.batch.service.impl; import java.util.Calendar; import java.util.Date; import java.util.StringTokenizer; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.gl.GeneralLedgerConstants; import org.kuali.kfs.gl.batch.ScrubberStep; import org.kuali.kfs.gl.batch.service.RunDateService; import org.kuali.rice.coreservice.framework.parameter.ParameterService; /** * The default implementation of RunDateService */ public class RunDateServiceImpl implements RunDateService { private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RunDateServiceImpl.class); private ParameterService parameterService; /** * * @see org.kuali.kfs.gl.batch.service.RunDateService#calculateRunDate(java.util.Date) */ public Date calculateRunDate(Date executionDate) { Calendar currentCal = Calendar.getInstance(); currentCal.setTime(executionDate); CutoffTime cutoffTime = parseCutoffTime(retrieveCutoffTimeValue()); if (isCurrentDateBeforeCutoff(currentCal, cutoffTime)) { // time to set the date to the previous day's last minute/second currentCal.add(Calendar.DAY_OF_MONTH, -1); // per old COBOL code (see KULRNE-70), // the time is set to 23:59:59 (assuming 0 ms) currentCal.set(Calendar.HOUR_OF_DAY, 23); currentCal.set(Calendar.MINUTE, 59); currentCal.set(Calendar.SECOND, 59); currentCal.set(Calendar.MILLISECOND, 0); return new Date(currentCal.getTimeInMillis()); } return new Date(executionDate.getTime()); } /** * Determines if the given calendar time is before the given cutoff time * * @param currentCal the current time * @param cutoffTime the "start of the day" cut off time * @return true if the current time is before the cutoff, false otherwise */ protected boolean isCurrentDateBeforeCutoff(Calendar currentCal, CutoffTime cutoffTime) { if (cutoffTime != null) { // if cutoff date is not properly defined // 24 hour clock (i.e. hour is 0 - 23) // clone the calendar so we get the same month, day, year // then change the hour, minute, second fields // then see if the cutoff is before or after Calendar cutoffCal = (Calendar) currentCal.clone(); cutoffCal.setLenient(false); cutoffCal.set(Calendar.HOUR_OF_DAY, cutoffTime.hour); cutoffCal.set(Calendar.MINUTE, cutoffTime.minute); cutoffCal.set(Calendar.SECOND, cutoffTime.second); cutoffCal.set(Calendar.MILLISECOND, 0); return currentCal.before(cutoffCal); } // if cutoff date is not properly defined, then it is considered to be after the cutoff return false; } /** * Holds the hour, minute, and second of a given cut off time */ protected class CutoffTime { /** * 24 hour time, from 0-23, inclusive */ protected int hour; /** * From 0-59, inclusive */ protected int minute; /** * From 0-59, inclusive */ protected int second; /** * Constructs a RunDateServiceImpl instance * @param hour the cutoff hour * @param minute the cutoff minute * @param second the cutoff second */ protected CutoffTime(int hour, int minute, int second) { this.hour = hour; this.minute = minute; this.second = second; } } /** * Parses a String representation of the cutoff time * * @param cutoffTime the cutoff time String to parse * @return a record holding the cutoff time */ protected CutoffTime parseCutoffTime(String cutoffTime) { if (StringUtils.isBlank(cutoffTime)) { return new CutoffTime(0, 0, 0); } else { cutoffTime = cutoffTime.trim(); if (LOG.isDebugEnabled()) { LOG.debug("Cutoff time value found: " + cutoffTime); } StringTokenizer st = new StringTokenizer(cutoffTime, ":", false); try { String hourStr = st.nextToken(); String minuteStr = st.nextToken(); String secondStr = st.nextToken(); int hourInt = Integer.parseInt(hourStr, 10); int minuteInt = Integer.parseInt(minuteStr, 10); int secondInt = Integer.parseInt(secondStr, 10); if (hourInt < 0 || hourInt > 23 || minuteInt < 0 || minuteInt > 59 || secondInt < 0 || secondInt > 59) { 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"); } return new CutoffTime(hourInt, minuteInt, secondInt); } catch (Exception e) { 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."); } } } /** * Retrieves the cutoff time from a repository. * * @return a time of day 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 */ protected String retrieveCutoffTimeValue() { String value = parameterService.getParameterValueAsString(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.SCRUBBER_CUTOFF_TIME); if (StringUtils.isBlank(value)) { LOG.error("Unable to retrieve parameter for GL process cutoff date. Defaulting to no cutoff time (i.e. midnight)"); value = null; } return value; } public void setParameterService(ParameterService parameterService) { this.parameterService = parameterService; } }