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}