/********************************************************************************
* CruiseControl, a Continuous Integration Toolkit
* Copyright (c) 2001, ThoughtWorks, Inc.
* 200 E. Randolph, 25th Floor
* Chicago, IL 60601 USA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* + Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
********************************************************************************/
package net.sourceforge.cruisecontrol.sourcecontrols;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import net.sourceforge.cruisecontrol.Builder;
import net.sourceforge.cruisecontrol.CruiseControlException;
import net.sourceforge.cruisecontrol.Modification;
import net.sourceforge.cruisecontrol.util.DateUtil;
import net.sourceforge.cruisecontrol.util.ValidationHelper;
import org.apache.log4j.Logger;
/**
* Provide a "time" using hhmm format that specifies when a build should be
* triggered. Once one successful build occurs, no more occur. If a build occurs
* successfully via other means as the time threshold is crossed then this build
* won't occur.
*
* The is useful when you need a project to be built on a time basis despite no
* changes to source control.
*
* @author <a href="mailto:epugh@opensourceconnections.com">Eric Pugh </a>
* @version $Id$
*/
public class TimeBuild extends FakeUserSourceControl {
private static final Logger LOG = Logger.getLogger(TimeBuild.class);
private int time = Builder.NOT_SET;
/**
* The threshold time to cross that starts triggering a build
*
* @param timeString
* The time in hhmm format
*/
public void setTime(final String timeString) {
time = Integer.parseInt(timeString);
}
public void validate() throws CruiseControlException {
ValidationHelper.assertFalse(time == Builder.NOT_SET, "the 'time' attribute is mandatory");
}
/**
* Check if TimeBuild "time" threshold has passed with out a successful
* build. If so, trigger the build.
*
* @param lastBuild
* date of last build
* @param now
* current time
*/
public List<Modification> getModifications(final Date lastBuild, final Date now) {
LOG.debug("LastBuild:" + lastBuild + ", now:" + now);
final List<Modification> modifications = new ArrayList<Modification>();
/*
*
* if now and lastbuild occur on the same day, only trigger a build when
* lastbuildtime is before 'time' and 'time' is before nowtime
*
* if now and lastbuild do not occur on the same day, only trigger a
* build when nowtime is after 'time'
*
*
*/
// TODO trigger at time, not just after it
final int lastBuildTime = DateUtil.getTimeFromDate(lastBuild);
final int nowTime = DateUtil.getTimeFromDate(now);
if (onSameDay(lastBuild, now)) {
if (lastBuildTime < time && time < nowTime) {
modifications.add(getMod(now));
}
} else {
if (nowTime > time || lastBuildTime < time || moreThanOneDay(lastBuild, now)) {
modifications.add(getMod(now));
}
}
if (!modifications.isEmpty()) {
getSourceControlProperties().modificationFound();
}
return modifications;
}
private boolean moreThanOneDay(Date lastBuild, Date now) {
final Calendar lastBuildCal = Calendar.getInstance();
lastBuildCal.setTime(lastBuild);
final Calendar nowCal = Calendar.getInstance();
nowCal.setTime(now);
lastBuildCal.add(Calendar.DAY_OF_MONTH, 1);
return lastBuildCal.before(nowCal);
}
private boolean onSameDay(final Date date1, final Date date2) {
final Calendar calendar = Calendar.getInstance();
calendar.setTime(date1);
final int day1 = calendar.get(Calendar.DAY_OF_MONTH);
calendar.setTime(date2);
final int day2 = calendar.get(Calendar.DAY_OF_MONTH);
return day1 == day2;
}
private Modification getMod(final Date now) {
final Modification mod = new Modification("always");
final Modification.ModifiedFile modfile = mod.createModifiedFile("time build", "time build");
modfile.action = "change";
mod.userName = getUserName();
final Calendar nowTimeBuild = Calendar.getInstance();
nowTimeBuild.setTime(now);
final int modifHour = this.time / 100;
final int modifMinute = this.time - modifHour * 100;
nowTimeBuild.set(Calendar.HOUR_OF_DAY, modifHour);
nowTimeBuild.set(Calendar.MINUTE, modifMinute);
nowTimeBuild.set(Calendar.MILLISECOND, 0);
mod.modifiedTime = nowTimeBuild.getTime();
mod.comment = "";
return mod;
}
public String toString() {
return getUserName() + ", " + time;
}
}