blob: 70b45f9d28413d5da921cfae053e36556629b444 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.sling.event.impl.support;
import java.io.Serializable;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.apache.sling.event.jobs.ScheduleInfo;
import org.quartz.CronExpression;
public class ScheduleInfoImpl implements ScheduleInfo, Serializable {
private static final long serialVersionUID = 1L;
/** Serialization version. */
private static final String VERSION = "1";
public static ScheduleInfoImpl HOURLY(final int minutes) {
return new ScheduleInfoImpl(ScheduleType.HOURLY, -1, -1, minutes, null, -1, null);
}
public static ScheduleInfoImpl CRON(final String expr) {
return new ScheduleInfoImpl(ScheduleType.CRON, -1, -1, -1, null, -1, expr);
}
public static ScheduleInfoImpl AT(final Date at) {
return new ScheduleInfoImpl(ScheduleType.DATE, -1, -1, -1, at, -1, null);
}
public static ScheduleInfoImpl YEARLY(final int month, final int day, final int hour, final int minute) {
return new ScheduleInfoImpl(ScheduleType.YEARLY, day, hour, minute, null, month, null);
}
public static ScheduleInfoImpl MONTHLY(final int day, final int hour, final int minute) {
return new ScheduleInfoImpl(ScheduleType.MONTHLY, day, hour, minute, null, -1, null);
}
public static ScheduleInfoImpl WEEKLY(final int day, final int hour, final int minute) {
return new ScheduleInfoImpl(ScheduleType.WEEKLY, day, hour, minute, null, -1, null);
}
public static ScheduleInfoImpl DAILY(final int hour, final int minute) {
return new ScheduleInfoImpl(ScheduleType.DAILY, -1, hour, minute, null, -1, null);
}
private final ScheduleType scheduleType;
private final int dayOfWeek;
private final int hourOfDay;
private final int minuteOfHour;
private final Date at;
private final int monthOfYear;
private final String expression;
private ScheduleInfoImpl(final ScheduleType scheduleType,
final int dayOfWeek,
final int hourOfDay,
final int minuteOfHour,
final Date at,
final int monthOfYear,
final String expression) {
this.scheduleType = scheduleType;
this.dayOfWeek = dayOfWeek;
this.hourOfDay = hourOfDay;
this.minuteOfHour = minuteOfHour;
this.at = at;
this.monthOfYear = monthOfYear;
this.expression = expression;
}
public static ScheduleInfoImpl deserialize(final ScheduleType scheduleType, final String s) {
final String[] parts = s.split("|");
if ( scheduleType == ScheduleType.YEARLY && parts.length == 4 ) {
try {
return new ScheduleInfoImpl(scheduleType,
Integer.parseInt(parts[0]),
Integer.parseInt(parts[1]),
Integer.parseInt(parts[2]),
null,
Integer.parseInt(parts[3]),
null);
} catch ( final IllegalArgumentException iae) {
// ignore and return null
}
} else if ( scheduleType == ScheduleType.MONTHLY && parts.length == 3 ) {
try {
return new ScheduleInfoImpl(scheduleType,
Integer.parseInt(parts[0]),
Integer.parseInt(parts[1]),
Integer.parseInt(parts[2]),
null,
-1,
null);
} catch ( final IllegalArgumentException iae) {
// ignore and return null
}
} else if ( scheduleType == ScheduleType.WEEKLY && parts.length == 3 ) {
try {
return new ScheduleInfoImpl(scheduleType,
Integer.parseInt(parts[0]),
Integer.parseInt(parts[1]),
Integer.parseInt(parts[2]),
null,
-1,
null);
} catch ( final IllegalArgumentException iae) {
// ignore and return null
}
} else if ( scheduleType == ScheduleType.DAILY && parts.length == 2 ) {
try {
return new ScheduleInfoImpl(scheduleType,
-1,
Integer.parseInt(parts[0]),
Integer.parseInt(parts[1]),
null,
-1,
null);
} catch ( final IllegalArgumentException iae) {
// ignore and return null
}
} else if ( scheduleType == ScheduleType.HOURLY && parts.length == 1 ) {
try {
return new ScheduleInfoImpl(scheduleType,
-1,
-1,
Integer.parseInt(parts[0]),
null,
-1,
null);
} catch ( final IllegalArgumentException iae) {
// ignore and return null
}
} else if ( scheduleType == ScheduleType.CRON && parts.length == 1 ) {
try {
return new ScheduleInfoImpl(scheduleType,
-1,
-1,
-1,
null,
-1,
parts[0]);
} catch ( final IllegalArgumentException iae) {
// ignore and return null
}
}
return null;
}
public static ScheduleInfoImpl deserialize(final String s) {
final String[] parts = s.split("\\|");
if ( parts.length == 8 && parts[0].equals(VERSION) ) {
try {
return new ScheduleInfoImpl(ScheduleType.valueOf(parts[1]),
Integer.parseInt(parts[2]),
Integer.parseInt(parts[3]),
Integer.parseInt(parts[4]),
(parts[5].equals("null") ? null : new Date(Long.parseLong(parts[5]))),
Integer.parseInt(parts[6]),
(parts[7].equals("null") ? null : parts[7])
);
} catch ( final IllegalArgumentException iae) {
// ignore and return null
}
}
return null;
}
public String getSerializedString() {
final StringBuilder sb = new StringBuilder();
sb.append(VERSION);
sb.append("|");
sb.append(this.scheduleType.name());
sb.append("|");
sb.append(String.valueOf(this.dayOfWeek));
sb.append("|");
sb.append(String.valueOf(this.hourOfDay));
sb.append("|");
sb.append(String.valueOf(this.minuteOfHour));
sb.append("|");
if ( at == null ) {
sb.append("null");
} else {
sb.append(String.valueOf(at.getTime()));
}
sb.append("|");
sb.append(String.valueOf(this.monthOfYear));
sb.append("|");
if ( expression == null ) {
sb.append("null");
} else {
sb.append(String.valueOf(expression));
}
return sb.toString();
}
@Override
public ScheduleType getType() {
return this.scheduleType;
}
@Override
public Date getAt() {
return this.at;
}
@Override
public int getDayOfWeek() {
return (this.scheduleType == ScheduleType.WEEKLY ? this.dayOfWeek : -1);
}
@Override
public int getHourOfDay() {
return this.hourOfDay;
}
@Override
public int getMinuteOfHour() {
return this.minuteOfHour;
}
@Override
public String getExpression() {
return this.expression;
}
@Override
public int getMonthOfYear() {
return this.monthOfYear;
}
@Override
public int getDayOfMonth() {
return (this.scheduleType == ScheduleType.MONTHLY
|| this.scheduleType == ScheduleType.YEARLY ? this.dayOfWeek : -1);
}
public void check(final List<String> errors) {
switch ( this.scheduleType ) {
case DAILY : if ( hourOfDay < 0 || hourOfDay > 23 || minuteOfHour < 0 || minuteOfHour > 59 ) {
errors.add("Wrong time information : " + minuteOfHour + ":" + minuteOfHour);
}
break;
case DATE : if ( at == null || at.getTime() <= System.currentTimeMillis() + 2000 ) {
errors.add("Date must be in the future : " + at);
}
break;
case HOURLY : if ( minuteOfHour < 0 || minuteOfHour > 59 ) {
errors.add("Minute must be between 0 and 59 : " + minuteOfHour);
}
break;
case WEEKLY : if ( hourOfDay < 0 || hourOfDay > 23 || minuteOfHour < 0 || minuteOfHour > 59 ) {
errors.add("Wrong time information : " + minuteOfHour + ":" + minuteOfHour);
}
if ( dayOfWeek < 1 || dayOfWeek > 7 ) {
errors.add("Day must be between 1 and 7 : " + dayOfWeek);
}
break;
case MONTHLY : if ( hourOfDay < 0 || hourOfDay > 23 || minuteOfHour < 0 || minuteOfHour > 59 ) {
errors.add("Wrong time information : " + minuteOfHour + ":" + minuteOfHour);
}
if ( dayOfWeek < 1 || dayOfWeek > 28 ) {
errors.add("Day must be between 1 and 28 : " + dayOfWeek);
}
break;
case YEARLY : if ( hourOfDay < 0 || hourOfDay > 23 || minuteOfHour < 0 || minuteOfHour > 59 ) {
errors.add("Wrong time information : " + minuteOfHour + ":" + minuteOfHour);
}
if ( dayOfWeek < 1 || dayOfWeek > 28 ) {
errors.add("Day must be between 1 and 28 : " + dayOfWeek);
}
if ( monthOfYear < 1 || monthOfYear > 12 ) {
errors.add("Month must be between 1 and 12 : " + dayOfWeek);
}
break;
case CRON : if ( expression == null ) {
errors.add("Expression must be specified.");
}
try {
new CronExpression(this.expression);
} catch (final ParseException e) {
errors.add("Expression must be valid: " + this.expression);
}
}
}
public Date getNextScheduledExecution() {
final Calendar now = Calendar.getInstance();
switch ( this.scheduleType ) {
case DATE : return this.at;
case DAILY : final Calendar next = Calendar.getInstance();
next.set(Calendar.HOUR_OF_DAY, this.hourOfDay);
next.set(Calendar.MINUTE, this.minuteOfHour);
if ( next.before(now) ) {
next.add(Calendar.DAY_OF_WEEK, 1);
}
return next.getTime();
case WEEKLY : final Calendar nextW = Calendar.getInstance();
nextW.set(Calendar.HOUR_OF_DAY, this.hourOfDay);
nextW.set(Calendar.MINUTE, this.minuteOfHour);
nextW.set(Calendar.DAY_OF_WEEK, this.dayOfWeek);
if ( nextW.before(now) ) {
nextW.add(Calendar.WEEK_OF_YEAR, 1);
}
return nextW.getTime();
case HOURLY : final Calendar nextH = Calendar.getInstance();
nextH.set(Calendar.MINUTE, this.minuteOfHour);
if ( nextH.before(now) ) {
nextH.add(Calendar.HOUR_OF_DAY, 1);
}
return nextH.getTime();
case MONTHLY : final Calendar nextM = Calendar.getInstance();
nextM.set(Calendar.HOUR_OF_DAY, this.hourOfDay);
nextM.set(Calendar.MINUTE, this.minuteOfHour);
nextM.set(Calendar.DAY_OF_MONTH, this.dayOfWeek);
if ( nextM.before(now) ) {
nextM.add(Calendar.MONTH, 1);
}
return nextM.getTime();
case YEARLY : final Calendar nextY = Calendar.getInstance();
nextY.set(Calendar.HOUR_OF_DAY, this.hourOfDay);
nextY.set(Calendar.MINUTE, this.minuteOfHour);
nextY.set(Calendar.DAY_OF_MONTH, this.dayOfWeek);
nextY.set(Calendar.MONTH, this.monthOfYear - 1);
if ( nextY.before(now) ) {
nextY.add(Calendar.YEAR, 1);
}
return nextY.getTime();
case CRON : try {
final CronExpression exp = new CronExpression(this.expression);
return exp.getNextValidTimeAfter(new Date());
} catch (final ParseException e) {
// as we check the expression in check() everything should be fine here
}
}
return null;
}
/**
* If the job is scheduled daily or weekly, return the cron expression
*/
public String getCronExpression() {
if ( this.scheduleType == ScheduleType.DAILY ) {
final StringBuilder sb = new StringBuilder("0 ");
sb.append(String.valueOf(this.minuteOfHour));
sb.append(' ');
sb.append(String.valueOf(this.hourOfDay));
sb.append(" * * ?");
return sb.toString();
} else if ( this.scheduleType == ScheduleType.WEEKLY ) {
final StringBuilder sb = new StringBuilder("0 ");
sb.append(String.valueOf(this.minuteOfHour));
sb.append(' ');
sb.append(String.valueOf(this.hourOfDay));
sb.append(" ? * ");
sb.append(String.valueOf(this.dayOfWeek));
return sb.toString();
} else if ( this.scheduleType == ScheduleType.HOURLY ) {
final StringBuilder sb = new StringBuilder("0 ");
sb.append(String.valueOf(this.minuteOfHour));
sb.append(" * * * ?");
return sb.toString();
} else if ( this.scheduleType == ScheduleType.MONTHLY ) {
final StringBuilder sb = new StringBuilder("0 ");
sb.append(String.valueOf(this.minuteOfHour));
sb.append(' ');
sb.append(String.valueOf(this.hourOfDay));
sb.append(' ');
sb.append(String.valueOf(this.dayOfWeek));
sb.append(" * ?");
return sb.toString();
} else if ( this.scheduleType == ScheduleType.YEARLY ) {
final StringBuilder sb = new StringBuilder("0 ");
sb.append(String.valueOf(this.minuteOfHour));
sb.append(' ');
sb.append(String.valueOf(this.hourOfDay));
sb.append(' ');
sb.append(String.valueOf(this.dayOfWeek));
sb.append(' ');
sb.append(String.valueOf(this.monthOfYear - 1));
sb.append(" ?");
return sb.toString();
} else if ( this.scheduleType == ScheduleType.CRON ) {
return this.expression;
}
return null;
}
@Override
public String toString() {
return "ScheduleInfo [scheduleType=" + scheduleType
+ ", dayOfWeek=" + dayOfWeek + ", hourOfDay=" + hourOfDay
+ ", minuteOfHour=" + minuteOfHour + ", at=" + at
+ ", monthOfYear=" + monthOfYear + ", expression=" + expression
+ "]";
}
}