org.activiti.engine.impl.calendar.AdvancedCycleBusinessCalendar Maven / Gradle / Ivy
package org.activiti.engine.impl.calendar;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import org.activiti.engine.ActivitiIllegalArgumentException;
import org.activiti.engine.api.internal.Internal;
import org.activiti.engine.runtime.ClockReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An Activiti BusinessCalendar for cycle based schedules that takes into account a different daylight savings time zone than the one that the server is configured for.
*
* For CRON strings DSTZONE is used as the time zone that the CRON schedule refers to. Leave it out to use the server time zone.
*
* For ISO strings the time zone offset for the date/time specified is part of the string itself. DSTZONE is used to determine what the offset should be NOW, which may be different than when the
* workflow was scheduled if it is scheduled to run across a DST event.
*
*
* For example:
* R/2013-10-01T20:30:00/P1D DSTZONE:US/Eastern
* R/2013-10-01T20:30:00/P1D DSTZONE:UTC
* R/2013-10-01T20:30:00/P1D DSTZONE:US/Arizona
* 0 30 20 ? * MON,TUE,WED,THU,FRI * DSTZONE:US/Eastern
* 0 30 20 ? * MON,TUE,WED,THU,FRI * DSTZONE:UTC
* 0 30 20 ? * MON,TUE,WED,THU,FRI * DSTZONE:US/Arizona
*
*
* Removing the DSTZONE key will cause Activiti to use the server's time zone. This is the original behavior.
*
* Schedule strings are versioned. Version 1 strings will use the original Activiti CycleBusinessCalendar. All new properties are ignored. Version 2 strings will use the new daylight saving time
* logic.
*
*
* For example:
* R/2013-10-01T20:30:00/P1D VER:2 DSTZONE:US/Eastern
* 0 30 20 ? * MON,TUE,WED,THU,FRI * VER:1 DSTZONE:US/Arizona
*
*
* By default (if no VER key is included in the string), it assumes version 2. This can be changed by modifying the defaultScheduleVersion property.
*
*/
@Internal
public class AdvancedCycleBusinessCalendar extends CycleBusinessCalendar {
private Integer defaultScheduleVersion;
private static final Integer DEFAULT_VERSION = 2;
private static final Logger logger = LoggerFactory.getLogger(AdvancedCycleBusinessCalendar.class);
private static final Map resolvers;
static {
resolvers = new ConcurrentHashMap();
resolvers.put(1, new AdvancedSchedulerResolverWithoutTimeZone());
resolvers.put(2, new AdvancedSchedulerResolverWithTimeZone());
}
public AdvancedCycleBusinessCalendar(ClockReader clockReader) {
super(clockReader);
}
public AdvancedCycleBusinessCalendar(ClockReader clockReader, Integer defaultScheduleVersion) {
this(clockReader);
this.defaultScheduleVersion = defaultScheduleVersion;
}
public Integer getDefaultScheduleVersion() {
return defaultScheduleVersion == null ? DEFAULT_VERSION : defaultScheduleVersion;
}
public void setDefaultScheduleVersion(Integer defaultScheduleVersion) {
this.defaultScheduleVersion = defaultScheduleVersion;
}
@Override
public Date resolveDuedate(String duedateDescription, int maxIterations) {
logger.info("Resolving Due Date: " + duedateDescription);
String timeZone = getValueFrom("DSTZONE", duedateDescription);
String version = getValueFrom("VER", duedateDescription);
// START is a legacy value that is no longer used, but may still exist
// in
// deployed job schedules
// Could be used in the future as a start date for a CRON job
// String startDate = getValueFrom("START", duedateDescription);
duedateDescription = removeValueFrom("VER", removeValueFrom("START", removeValueFrom("DSTZONE", duedateDescription))).trim();
try {
logger.info("Base Due Date: " + duedateDescription);
Date date = resolvers.get(version == null ? getDefaultScheduleVersion() : Integer.valueOf(version)).resolve(duedateDescription, clockReader,
timeZone == null ? clockReader.getCurrentTimeZone() : TimeZone.getTimeZone(timeZone));
logger.info("Calculated Date: " + (date == null ? "Will Not Run Again" : date));
return date;
} catch (Exception e) {
throw new ActivitiIllegalArgumentException("Cannot parse duration", e);
}
}
private String getValueFrom(String field, String duedateDescription) {
int fieldIndex = duedateDescription.indexOf(field + ":");
if (fieldIndex > -1) {
int nextWhiteSpace = duedateDescription.indexOf(" ", fieldIndex);
fieldIndex += field.length() + 1;
if (nextWhiteSpace > -1) {
return duedateDescription.substring(fieldIndex, nextWhiteSpace);
} else {
return duedateDescription.substring(fieldIndex);
}
}
return null;
}
private String removeValueFrom(String field, String duedateDescription) {
int fieldIndex = duedateDescription.indexOf(field + ":");
if (fieldIndex > -1) {
int nextWhiteSpace = duedateDescription.indexOf(" ", fieldIndex);
if (nextWhiteSpace > -1) {
return duedateDescription.replace(duedateDescription.substring(fieldIndex, nextWhiteSpace), "");
} else {
return duedateDescription.substring(0, fieldIndex);
}
}
return duedateDescription;
}
}