de.raion.xmppbot.command.core.ScheduleCommand.java Source code

Java tutorial

Introduction

Here is the source code for de.raion.xmppbot.command.core.ScheduleCommand.java

Source

package de.raion.xmppbot.command.core;

/*
 * #%L
 * XmppBot Core
 * %%
 * Copyright (C) 2012 Bernd Kiefer
 * %%
 * Licensed 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.
 * #L%
 */

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.dharwin.common.tools.cli.api.annotations.CLICommand;

import org.joda.time.LocalTime;
import org.joda.time.format.ISODateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.beust.jcommander.Parameter;

import de.raion.xmppbot.XmppContext;
import de.raion.xmppbot.schedule.ScheduledCommand;
import de.raion.xmppbot.schedule.ScheduledCommandExecutor;
import de.raion.xmppbot.schedule.WorkingDayScheduledCommand;

/**
 * <pre>
 * {@code
 * Usage: schedule [options] parameters belonging to the cmd/command
   Options:
-cmd, -command    the command to execute, see help for list of commands
-d, -daily        schedules daily at HH:mm, (HH 0-23)
-l, -list         shows all configured schedules
                  Default: false
-m, -minutes      schedules once in x minutes
-r, -remove       deletes the scheduled command with the given id
-w, -workingday   schedules MO-FR at HH:mm
 *}
 *</pre>
 *
 */
@CLICommand(name = "schedule", description = "schedules another command")
public class ScheduleCommand extends AbstractXmppCommand {

    /** '([0-9]{2}):([0-9]{2})'  */
    protected static final String TIME_FORMAT_PATTERN = "([0-9]{2}):([0-9]{2})";

    private static Logger log = LoggerFactory.getLogger(AbstractXmppCommand.class);

    @Parameter(names = { "-d", "-daily" }, required = false, description = "schedules daily at HH:mm, (HH 0-23)")
    String daily;

    @Parameter(names = { "-w", "-workingday" }, required = false, description = "schedules MO-FR at HH:mm")
    String workingDay;

    @Parameter(names = { "-m", "-minutes" }, required = false, description = "schedules once in x minutes")
    Integer minutes;

    @Parameter(names = { "-cmd",
            "-command" }, required = false, description = "the command to execute, see help for list of commands")
    String command;

    //   @Parameter(names = { "-e", "-every" }, required = false, description = "schedules every x(min)utes |(hour)s| (day)s (1m, 2h, 3d")
    //   PeriodParam everyOption;

    @Parameter(names = { "-l", "-list" }, required = false, description = "shows all configured schedules")
    Boolean showSchedules = false;

    @Parameter(names = { "-r",
            "-remove" }, required = false, description = "deletes the scheduled command with the given id")
    List<String> idsToRemoveList;

    @Parameter(description = "parameters belonging to the cmd/command")
    List<String> commandParamList;

    @Parameter(names = "-muc", description = "name of the multiuserchat to execute the command to", hidden = true)
    String multiUserChatName;

    @Parameter(names = "-chat", description = "name of the chat to execute the command to", hidden = true)
    String chatName;

    @Parameter(names = "-timestamp", description = "timestamp when the command was received/parsed", hidden = true, converter = ISODateTimeConverter.class)
    Date creationDate = new Date(System.currentTimeMillis());

    @Override
    public void executeCommand(XmppContext context) {

        if (showSchedules) {
            printSchedules(context);
        } else if (idsToRemoveList != null) {
            removeFromSchedule(context);
        } else {
            schedule(context);
        }
    }

    private void removeFromSchedule(XmppContext context) {

        ScheduledCommandExecutor scheduleExecutor = context.getScheduler();

        List<Integer> idList = convertToIntegerList(idsToRemoveList);

        for (Integer id : idList) {
            if (scheduleExecutor.isCommandScheduled(id)) {
                boolean removed = scheduleExecutor.remove(id);

                if (removed) {
                    println("command " + id + " removed from schedule");
                    log.info("command " + id + " removed from schedule");
                }
            }
        }
    }

    private List<Integer> convertToIntegerList(List<String> aList) {

        List<Integer> list = new ArrayList<Integer>(aList.size());

        for (String sid : aList) {
            try {
                list.add(new Integer(sid));
            } catch (NumberFormatException e) {
                println(sid + " is not a valid id");
            }
        }
        return list;
    }

    private void printSchedules(XmppContext context) {

        ScheduledCommandExecutor scheduleExecutor = context.getScheduler();
        List<ScheduledCommand> list = scheduleExecutor.scheduledCommands();

        for (ScheduledCommand cmd : list) {
            println(cmd.toString());
        }
    }

    private void schedule(XmppContext context) {
        ScheduledCommandExecutor scheduleExecutor = context.getScheduler();

        if (isCommandAvailable(context) && scheduleTimeIsAvailable()) {

            if (minutes != null) {
                scheduleIn(context, scheduleExecutor, minutes, TimeUnit.MINUTES);
            } else if (daily != null) {
                scheduleDaily(context, scheduleExecutor);
            } else if (workingDay != null) {
                scheduleWorkingDay(context, scheduleExecutor);
            }
        }
    }

    /**
     * checks if the given command is expired by adding the timeInMillisToAdd to
     * the {@link #creationDate} and compares it to to current system time
     * @param timeInMillisToAdd the millis to add to {@link #creationDate}
     * @return true if expired, otherwise false
     */
    private boolean expired(long timeInMillisToAdd) {

        if ((creationDate.getTime() + timeInMillisToAdd) < System.currentTimeMillis()) {
            return true;
        }

        return false;
    }

    private void scheduleIn(XmppContext context, ScheduledCommandExecutor scheduleExecutor, int in,
            TimeUnit timeUnit) {

        ScheduledCommand scheduledCommand = new ScheduledCommand(context, command, commandParamList);

        scheduledCommand = setParameters(context, scheduledCommand);

        if (!expired(TimeUnit.MILLISECONDS.convert(in, TimeUnit.MINUTES))) {
            scheduleExecutor.schedule(scheduledCommand, in, timeUnit);
            println("scheduled with id [" + scheduledCommand.getId() + "]");
        } else {

            String cmdAsString = scheduledCommand.toCommandString();

            log.info("command is expired and will not be added to the scheduler: " + cmdAsString);

            boolean removed = scheduleExecutor.remove(cmdAsString);

            log.info("removed from schedule configuration = {}", removed);
        }
    }

    private void scheduleWorkingDay(XmppContext context, ScheduledCommandExecutor scheduleExecutor) {
        Matcher matcher = Pattern.compile(TIME_FORMAT_PATTERN).matcher(workingDay);

        if (matcher.matches()) {
            Integer hour = new Integer(matcher.group(1));
            Integer min = new Integer(matcher.group(2));

            LocalTime time = new LocalTime(hour, min);

            ScheduledCommand scheduledCommand = new WorkingDayScheduledCommand(context, command, commandParamList);

            scheduledCommand = setParameters(context, scheduledCommand);

            scheduleExecutor.scheduleAtFixedRate(scheduledCommand, time);

            //TODO print information when task is executed etc
            //               log.info("Command '{}' will be executed in '{} ms'",
            //                     command, initialDelay);
            println("scheduled with id [" + scheduledCommand.getId() + "]");
        }
    }

    private void scheduleDaily(XmppContext context, ScheduledCommandExecutor scheduleExecutor) {
        Matcher matcher = Pattern.compile(TIME_FORMAT_PATTERN).matcher(daily);

        if (matcher.matches()) {
            Integer hour = new Integer(matcher.group(1));
            Integer min = new Integer(matcher.group(2));

            LocalTime time = new LocalTime(hour, min);

            ScheduledCommand scheduledCommand = new ScheduledCommand(context, command, commandParamList);

            scheduledCommand = setParameters(context, scheduledCommand);

            scheduleExecutor.scheduleAtFixedRate(scheduledCommand, time);

            println("scheduled with id [" + scheduledCommand.getId() + "]");
        } else {
            println("invalid value '" + daily + "' for parameter -d -daily");
        }
    }

    private ScheduledCommand setParameters(XmppContext context, ScheduledCommand command) {

        // command received from a multiuserchannel
        if (context.getMultiUserChat() != null && (multiUserChatName == null)) {
            command.setMultiUserChatName(context.getMultiUserChat().getRoom());
        } else if (context.getChat() != null && (chatName == null)) {
            command.setParticipant(context.getChat().getParticipant());
        } else if (multiUserChatName != null) {
            command.setMultiUserChatName(multiUserChatName);
        } else if (chatName != null) {
            command.setParticipant(chatName);
        }

        if (daily != null) {
            command.putOption("-daily", daily);
        }
        if (workingDay != null) {
            command.putOption("-workingday", workingDay);
        }
        if (minutes != null) {
            command.putOption("-minutes", minutes.toString());
        }

        command.putOption("-timestamp", ISODateTimeFormat.basicDateTime().print(creationDate.getTime()));

        return command;
    }

    private boolean isCommandAvailable(XmppContext context) {
        if (!context.getBot().hasCommand(command)) {
            println("can't schedule, command '" + command + "' does not exist");
            return false;
        }
        return true;
    }

    private boolean scheduleTimeIsAvailable() {
        if (daily != null) {
            return true;
        } else if (workingDay != null) {
            return true;
        } else if (minutes != null) {
            return true;
        }

        println("schedule time is missing, try options -d, -w, -m, -e or --help");
        return false;
    }
}