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}