001/*
002 * Copyright 2002-2015 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.scheduling.support;
018
019import java.util.Date;
020import java.util.TimeZone;
021
022import org.springframework.scheduling.Trigger;
023import org.springframework.scheduling.TriggerContext;
024
025/**
026 * {@link Trigger} implementation for cron expressions.
027 * Wraps a {@link CronSequenceGenerator}.
028 *
029 * @author Juergen Hoeller
030 * @since 3.0
031 * @see CronSequenceGenerator
032 */
033public class CronTrigger implements Trigger {
034
035        private final CronSequenceGenerator sequenceGenerator;
036
037
038        /**
039         * Build a {@link CronTrigger} from the pattern provided in the default time zone.
040         * @param expression a space-separated list of time fields, following cron
041         * expression conventions
042         */
043        public CronTrigger(String expression) {
044                this.sequenceGenerator = new CronSequenceGenerator(expression);
045        }
046
047        /**
048         * Build a {@link CronTrigger} from the pattern provided in the given time zone.
049         * @param expression a space-separated list of time fields, following cron
050         * expression conventions
051         * @param timeZone a time zone in which the trigger times will be generated
052         */
053        public CronTrigger(String expression, TimeZone timeZone) {
054                this.sequenceGenerator = new CronSequenceGenerator(expression, timeZone);
055        }
056
057
058        /**
059         * Return the cron pattern that this trigger has been built with.
060         */
061        public String getExpression() {
062                return this.sequenceGenerator.getExpression();
063        }
064
065
066        /**
067         * Determine the next execution time according to the given trigger context.
068         * <p>Next execution times are calculated based on the
069         * {@linkplain TriggerContext#lastCompletionTime completion time} of the
070         * previous execution; therefore, overlapping executions won't occur.
071         */
072        @Override
073        public Date nextExecutionTime(TriggerContext triggerContext) {
074                Date date = triggerContext.lastCompletionTime();
075                if (date != null) {
076                        Date scheduled = triggerContext.lastScheduledExecutionTime();
077                        if (scheduled != null && date.before(scheduled)) {
078                                // Previous task apparently executed too early...
079                                // Let's simply use the last calculated execution time then,
080                                // in order to prevent accidental re-fires in the same second.
081                                date = scheduled;
082                        }
083                }
084                else {
085                        date = new Date();
086                }
087                return this.sequenceGenerator.next(date);
088        }
089
090
091        @Override
092        public boolean equals(Object other) {
093                return (this == other || (other instanceof CronTrigger &&
094                                this.sequenceGenerator.equals(((CronTrigger) other).sequenceGenerator)));
095        }
096
097        @Override
098        public int hashCode() {
099                return this.sequenceGenerator.hashCode();
100        }
101
102        @Override
103        public String toString() {
104                return this.sequenceGenerator.toString();
105        }
106
107}