net.stickycode.scheduled.aligned.AlignedPeriodicSchedule.java Source code

Java tutorial

Introduction

Here is the source code for net.stickycode.scheduled.aligned.AlignedPeriodicSchedule.java

Source

/**
 * Copyright (c) 2011 RedEngine Ltd, http://www.RedEngine.co.nz. All rights reserved.
 *
 * This program is licensed to you under the Apache License Version 2.0,
 * and you may not use this file except in compliance with the Apache License Version 2.0.
 * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the Apache License Version 2.0 is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
 */
package net.stickycode.scheduled.aligned;

import java.util.concurrent.TimeUnit;

import net.stickycode.scheduled.PeriodicSchedule;

import org.joda.time.DateTime;

public class AlignedPeriodicSchedule extends PeriodicSchedule {

    private final long alignment;

    private final TimeUnit alignmentUnit;

    public AlignedPeriodicSchedule(long alignment, TimeUnit alignmentUnit, long period, TimeUnit periodUnit) {
        super(period, periodUnit);
        if (alignment < 1)
            throw new AlignmentOfLessThanOneIsMeaninglessException(alignment);

        if (alignmentUnit.compareTo(periodUnit) > 0)
            throw new AlignmentCannotBeLessThanPeriodUnitsException(alignmentUnit, periodUnit);

        if (alignment > alignmentUnit.convert(period, periodUnit))
            throw new AlignmentMustBeLessThanPeriodException(alignment, alignmentUnit, period, periodUnit);

        this.alignment = alignment;
        this.alignmentUnit = alignmentUnit;
    }

    @Override
    public long getPeriod() {
        return alignmentUnit.convert(super.getPeriod(), super.getUnits());
    }

    @Override
    public TimeUnit getUnits() {
        return alignmentUnit;
    }

    /**
     * The delay in seconds to wait before the initial execution to align the schedule as specified.
     * <b>An alignment of 0 means there is no delay</b>
     * <p>
     * e.g.
     * <ul>
     * <li>if the user configured a schedule as 'every hour at 15 minutes past'</li>
     * <li>and the service started at 10 minutes past</li>
     * <li>then the period would be 60 * 60 seconds</li>
     * <li>and the delay would be 5 * 60 seconds such that the first execution is 15 minutes past</li>
     * </ul>
     * </p>
     */
    @Override
    public long getInitialDelay() {
        if (alignment == 0)
            return 0;

        DateTime time = new DateTime();
        switch (alignmentUnit) {
        case HOURS:
            return calculateDelay(time.getHourOfDay(), alignment, 24);

        case MINUTES:
            return calculateDelay(time.getMinuteOfHour(), alignment, 60);

        case SECONDS:
            return calculateDelay(time.getSecondOfMinute(), alignment, 60);

        case MILLISECONDS:
            return calculateDelay(time.getMillisOfSecond(), alignment, 1000);

        default:
            throw new AlignmentNotSupportedException(alignmentUnit);
        }
    }

    private long calculateDelay(int current, long offset, long max) {
        if (current < offset)
            return offset - current;

        return max - current + offset;
    }

    @Override
    public String toString() {
        String units = getUnits().toString().toLowerCase();
        return String.format("period %d %s starting in %d %s", getPeriod(), units, getInitialDelay(),
                alignmentUnit.toString().toLowerCase());
    }
}