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.lang.Nullable;
023import org.springframework.scheduling.Trigger;
024import org.springframework.scheduling.TriggerContext;
025
026/**
027 * {@link Trigger} implementation for cron expressions.
028 * Wraps a {@link CronSequenceGenerator}.
029 *
030 * @author Juergen Hoeller
031 * @since 3.0
032 * @see CronSequenceGenerator
033 */
034public class CronTrigger implements Trigger {
035
036        private final CronSequenceGenerator sequenceGenerator;
037
038
039        /**
040         * Build a {@link CronTrigger} from the pattern provided in the default time zone.
041         * @param expression a space-separated list of time fields, following cron
042         * expression conventions
043         */
044        public CronTrigger(String expression) {
045                this.sequenceGenerator = new CronSequenceGenerator(expression);
046        }
047
048        /**
049         * Build a {@link CronTrigger} from the pattern provided in the given time zone.
050         * @param expression a space-separated list of time fields, following cron
051         * expression conventions
052         * @param timeZone a time zone in which the trigger times will be generated
053         */
054        public CronTrigger(String expression, TimeZone timeZone) {
055                this.sequenceGenerator = new CronSequenceGenerator(expression, timeZone);
056        }
057
058
059        /**
060         * Return the cron pattern that this trigger has been built with.
061         */
062        public String getExpression() {
063                return this.sequenceGenerator.getExpression();
064        }
065
066
067        /**
068         * Determine the next execution time according to the given trigger context.
069         * <p>Next execution times are calculated based on the
070         * {@linkplain TriggerContext#lastCompletionTime completion time} of the
071         * previous execution; therefore, overlapping executions won't occur.
072         */
073        @Override
074        public Date nextExecutionTime(TriggerContext triggerContext) {
075                Date date = triggerContext.lastCompletionTime();
076                if (date != null) {
077                        Date scheduled = triggerContext.lastScheduledExecutionTime();
078                        if (scheduled != null && date.before(scheduled)) {
079                                // Previous task apparently executed too early...
080                                // Let's simply use the last calculated execution time then,
081                                // in order to prevent accidental re-fires in the same second.
082                                date = scheduled;
083                        }
084                }
085                else {
086                        date = new Date();
087                }
088                return this.sequenceGenerator.next(date);
089        }
090
091
092        @Override
093        public boolean equals(@Nullable Object other) {
094                return (this == other || (other instanceof CronTrigger &&
095                                this.sequenceGenerator.equals(((CronTrigger) other).sequenceGenerator)));
096        }
097
098        @Override
099        public int hashCode() {
100                return this.sequenceGenerator.hashCode();
101        }
102
103        @Override
104        public String toString() {
105                return this.sequenceGenerator.toString();
106        }
107
108}