/** * Copyright (c) 2009--2012 Red Hat, Inc. * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or * implied, including the implied warranties of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 * along with this software; if not, see * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * Red Hat trademarks are not licensed under GPLv2. No permission is * granted to use or replicate Red Hat trademarks that are incorporated * in this software or its documentation. */ package com.redhat.rhn.common.util; import com.redhat.rhn.frontend.context.Context; import org.apache.commons.lang.StringUtils; import java.text.DateFormatSymbols; import java.util.Calendar; import java.util.Locale; import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; /** * The RecurringEventPicker * * to use this simply add this to your jsp: * * <jsp:include page="/WEB-INF/pages/common/fragments/repeat-task-picker.jspf"> * <jsp:param name="widget" value="date"/> * </jsp:include> * * * Then in your action, simply do: * * RecurringEventPicker picker = RecurringEventPicker.prepopulatePicker( * request, "date", oldCronExpr); * call picker.getCronExpr() to get the given cron expression (if submitted) * call picker.isDisabled() to see if it is disabled or not * * * @version $Rev$ */ public class RecurringEventPicker { private static final String STATUS_DISABLED = "disabled"; //Daily defines // 0 %d %d * * * private static final String STATUS_DAILY = "daily"; private static final String DAILY_REGEX = "0 +\\d+ +\\d+ +\\? +\\* +\\*"; private static final String DAILY_HOUR = "_daily_hour"; private static final String DAILY_MINUTE = "_daily_minute"; //Weekly defines // 0 %d %d * * %d private static final String STATUS_WEEKLY = "weekly"; private static final String WEEKLY_REGEX = "0 +\\d+ +\\d+ +\\? +\\* +\\d"; private static final String WEEKLY_HOUR = "_weekly_hour"; private static final String WEEKLY_MINUTE = "_weekly_minute"; private static final String WEEKLY_DAY_OF_WEEK = "_day_week"; //Monthly Defines // 0 %d %d %d * * private static final String STATUS_MONTHLY = "monthly"; private static final String MONTHLY_REGEX = "0 +\\d+ +\\d+ +\\d+ +\\* +\\?"; private static final String MONTHLY_HOUR = "_monthly_hour"; private static final String MONTHLY_MINUTE = "_monthly_minute"; private static final String MONTHLY_DAY_OF_MONTH = "_day_month"; private static final String STATUS_CRON = "cron"; private static final String CRON_ENTRY = "_cron"; private static final String WHITE_SPACE = "\\s+"; private static final Integer[] DAY_NUMBERS = {Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY, Calendar.SATURDAY}; /** .------------------- Second (0-59) | .---------------- minute (0 - 59) | | .------------- hour (0 - 23) | | | .---------- day of month (1 - 31) | | | | .------- month (1 - 12) OR jan,feb,mar,apr ... | | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat | | | | | | * * * * * * command to be executed */ private final String name; private String status; private String cronEntry; private final DatePicker dailyTimePicker; private final DatePicker weeklyTimePicker; private final DatePicker monthlyTimePicker; /** * Constructor * @param name0 the name */ public RecurringEventPicker(String name0) { name = name0; status = STATUS_DISABLED; dailyTimePicker = new DatePicker(name + "_" + STATUS_DAILY, TimeZone.getDefault(), Locale.getDefault(), DatePicker.YEAR_RANGE_POSITIVE); dailyTimePicker.setDisableDate(); weeklyTimePicker = new DatePicker(name + "_" + STATUS_WEEKLY, TimeZone.getDefault(), Locale.getDefault(), DatePicker.YEAR_RANGE_POSITIVE); weeklyTimePicker.setDisableDate(); monthlyTimePicker = new DatePicker(name + "_" + STATUS_MONTHLY, TimeZone.getDefault(), Locale.getDefault(), DatePicker.YEAR_RANGE_POSITIVE); monthlyTimePicker.setDisableDate(); } /** * Return the name of this picker. * * @return the name of this picker */ public String getName() { return name; } /** * while we could just rely on the ordering and numbering of getWeekdays, * I figured it would be best to not rely on the numbers being what we want. * @return List of day names in order from Sunday -> Saturday */ public String[] getDayNames() { String[] days = DateFormatSymbols.getInstance( Context.getCurrentContext().getLocale()).getWeekdays(); String[] toReturn = new String[7]; for (int i = 0; i < DAY_NUMBERS.length; i++) { toReturn[i] = days[DAY_NUMBERS[i]]; } return toReturn; } /** * Prepopulate the request with the picker * @param request the http request * @param name the name of the picker * @param cronEntry if non-null, will set the picker to this. * @return The created picker */ public static RecurringEventPicker prepopulatePicker( HttpServletRequest request, String name, String cronEntry) { RecurringEventPicker p = new RecurringEventPicker(name); request.setAttribute(name, p); String tmpStatus = request.getParameter(name + "_status"); if (tmpStatus != null) { p.setStatus(tmpStatus); if (tmpStatus.equals(STATUS_DAILY)) { DatePicker timePicker = p.getDailyTimePicker(); timePicker.readMap(request.getParameterMap()); String hour = String.valueOf(timePicker.getHourOfDay()); String minute = String.valueOf(timePicker.getMinute()); p.setCronEntry(buildCron(minute, hour, null, null, STATUS_DAILY)); } else if (tmpStatus.equals(STATUS_WEEKLY)) { DatePicker timePicker = p.getWeeklyTimePicker(); timePicker.readMap(request.getParameterMap()); String hour = String.valueOf(timePicker.getHourOfDay()); String minute = String.valueOf(timePicker.getMinute()); String day = request.getParameter(name + WEEKLY_DAY_OF_WEEK); p.setCronEntry(buildCron(minute, hour, null, day, STATUS_WEEKLY)); } else if (tmpStatus.equals(STATUS_MONTHLY)) { DatePicker timePicker = p.getMonthlyTimePicker(); timePicker.readMap(request.getParameterMap()); String hour = String.valueOf(timePicker.getHourOfDay()); String minute = String.valueOf(timePicker.getMinute()); String day = request.getParameter(name + MONTHLY_DAY_OF_MONTH); p.setCronEntry(buildCron(minute, hour, day, null, STATUS_MONTHLY)); } else if (tmpStatus.equals(STATUS_CRON)) { p.setCronEntry(request.getParameter(name + CRON_ENTRY)); } else if (tmpStatus.equals(STATUS_DISABLED)) { p.setStatus(STATUS_DISABLED); } } else if (cronEntry != null) { if (cronEntry.split(WHITE_SPACE).length < 6) { //The Cron Entry is too short return null; } // here do it the other way around, set the time pickers from // the cron time if (matches(cronEntry, DAILY_REGEX)) { p.setStatus(STATUS_DAILY); p.setCronEntry(cronEntry); DatePicker timePicker = p.getDailyTimePicker(); timePicker.setHourOfDay(p.getHourLong().intValue()); timePicker.setMinute(p.getMinuteLong().intValue()); } else if (matches(cronEntry, WEEKLY_REGEX)) { p.setStatus(STATUS_WEEKLY); p.setCronEntry(cronEntry); DatePicker timePicker = p.getWeeklyTimePicker(); timePicker.setHourOfDay(p.getHourLong().intValue()); timePicker.setMinute(p.getMinuteLong().intValue()); } else if (matches(cronEntry, MONTHLY_REGEX)) { p.setStatus(STATUS_MONTHLY); p.setCronEntry(cronEntry); DatePicker timePicker = p.getMonthlyTimePicker(); timePicker.setHourOfDay(p.getHourLong().intValue()); timePicker.setMinute(p.getMinuteLong().intValue()); } else { p.setStatus(STATUS_CRON); p.setCronEntry(cronEntry); } } return p; } private static String buildCron(String minute, String hour, String dayOfMonth, String dayOfWeek, String type) { if (type.equals(STATUS_DAILY)) { //0 %d %d ? * * String[] items = {"0", minute, hour, "?", "*", "*"}; return StringUtils.join(items, " "); } else if (type.equals(STATUS_WEEKLY)) { //0 %d %d ? * %d String[] items = {"0", minute, hour, "?", "*", dayOfWeek}; return StringUtils.join(items, " "); } else if (type.equals(STATUS_MONTHLY)) { //0 %d %d %d * ? String[] items = {"0", minute, hour, dayOfMonth, "*", "?"}; return StringUtils.join(items, " "); } else { return ""; } } private static boolean matches(String cronEntry, String pattern) { Pattern p = Pattern.compile(pattern); Matcher m = p.matcher(cronEntry); return m.matches(); } /** * @return Returns the status. */ public String getStatus() { return status; } /** * @param statusIn The status to set. */ public void setStatus(String statusIn) { status = statusIn; } /** * @return Returns the cronEntry. */ public String getCronEntry() { return cronEntry; } /** * @param cronEntryIn The cronEntry to set. */ public void setCronEntry(String cronEntryIn) { cronEntry = cronEntryIn; } /** * @return Returns the day. */ public String getDayOfWeek() { return getCronValue(5); } /** * @return Returns the dayOfMonth. */ public String getDayOfMonth() { return getCronValue(3); } /** * @return Returns the dayOfMonth. */ public Long getDayOfMonthLong() { String st = getCronValue(3); if (StringUtils.isNumeric(st)) { return Long.parseLong(st); } return -1L; } /** * @return Returns the dayOfMonth String. */ public String getDayOfWeekString() { String num = getCronValue(5); if (num == null || !StringUtils.isNumeric(num) || getDayNames().length < Integer.parseInt(num) || Integer.parseInt(num) < 1) { return null; } return getDayNames()[Integer.parseInt(num) - 1]; } /** * Get the hour of the day * @return the hour */ public String getHour() { return getCronValue(2); } /** * Get the hour of the day * @return the hour */ public Long getHourLong() { String st = getCronValue(2); if (StringUtils.isNumeric(st)) { return Long.parseLong(st); } return -1L; } /** * Get the minute of the hour * @return the minute */ public String getMinute() { return getCronValue(1); } /** * Get the hour of the day * @return the hour */ public Long getMinuteLong() { String st = getCronValue(1); if (StringUtils.isNumeric(st)) { return Long.parseLong(st); } return -1L; } private String getCronValue(int slot) { if (getCronEntry() == null) { return null; } String[] array = getCronEntry().split(WHITE_SPACE); if (slot >= array.length) { return null; } return array[slot]; } /** * is the picker disabled. * @return if it is disabled or not */ public boolean isDisabled() { return status.equals(STATUS_DISABLED); } /** * @return a date picker used to select the * daily time */ public DatePicker getDailyTimePicker() { return dailyTimePicker; } /** * @return a date picker used to select the * weekly time */ public DatePicker getWeeklyTimePicker() { return weeklyTimePicker; } /** * @return a date picker used to select the * monthly time */ public DatePicker getMonthlyTimePicker() { return monthlyTimePicker; } }