001/* 002 * Copyright 2002-2018 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.commonj; 018 019import java.util.Date; 020import java.util.concurrent.Delayed; 021import java.util.concurrent.FutureTask; 022import java.util.concurrent.ScheduledFuture; 023import java.util.concurrent.TimeUnit; 024 025import commonj.timers.Timer; 026import commonj.timers.TimerListener; 027 028import org.springframework.lang.Nullable; 029import org.springframework.scheduling.TaskScheduler; 030import org.springframework.scheduling.Trigger; 031import org.springframework.scheduling.support.SimpleTriggerContext; 032import org.springframework.scheduling.support.TaskUtils; 033import org.springframework.util.Assert; 034import org.springframework.util.ErrorHandler; 035 036/** 037 * Implementation of Spring's {@link TaskScheduler} interface, wrapping 038 * a CommonJ {@link commonj.timers.TimerManager}. 039 * 040 * @author Juergen Hoeller 041 * @author Mark Fisher 042 * @since 3.0 043 * @deprecated as of 5.1, in favor of EE 7's 044 * {@link org.springframework.scheduling.concurrent.DefaultManagedTaskScheduler} 045 */ 046@Deprecated 047public class TimerManagerTaskScheduler extends TimerManagerAccessor implements TaskScheduler { 048 049 @Nullable 050 private volatile ErrorHandler errorHandler; 051 052 053 /** 054 * Provide an {@link ErrorHandler} strategy. 055 */ 056 public void setErrorHandler(ErrorHandler errorHandler) { 057 this.errorHandler = errorHandler; 058 } 059 060 061 @Override 062 @Nullable 063 public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) { 064 return new ReschedulingTimerListener(errorHandlingTask(task, true), trigger).schedule(); 065 } 066 067 @Override 068 public ScheduledFuture<?> schedule(Runnable task, Date startTime) { 069 TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, false)); 070 Timer timer = obtainTimerManager().schedule(futureTask, startTime); 071 futureTask.setTimer(timer); 072 return futureTask; 073 } 074 075 @Override 076 public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) { 077 TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true)); 078 Timer timer = obtainTimerManager().scheduleAtFixedRate(futureTask, startTime, period); 079 futureTask.setTimer(timer); 080 return futureTask; 081 } 082 083 @Override 084 public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) { 085 TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true)); 086 Timer timer = obtainTimerManager().scheduleAtFixedRate(futureTask, 0, period); 087 futureTask.setTimer(timer); 088 return futureTask; 089 } 090 091 @Override 092 public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay) { 093 TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true)); 094 Timer timer = obtainTimerManager().schedule(futureTask, startTime, delay); 095 futureTask.setTimer(timer); 096 return futureTask; 097 } 098 099 @Override 100 public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay) { 101 TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true)); 102 Timer timer = obtainTimerManager().schedule(futureTask, 0, delay); 103 futureTask.setTimer(timer); 104 return futureTask; 105 } 106 107 private Runnable errorHandlingTask(Runnable delegate, boolean isRepeatingTask) { 108 return TaskUtils.decorateTaskWithErrorHandler(delegate, this.errorHandler, isRepeatingTask); 109 } 110 111 112 /** 113 * ScheduledFuture adapter that wraps a CommonJ Timer. 114 */ 115 private static class TimerScheduledFuture extends FutureTask<Object> implements TimerListener, ScheduledFuture<Object> { 116 117 @Nullable 118 protected transient Timer timer; 119 120 protected transient boolean cancelled = false; 121 122 public TimerScheduledFuture(Runnable runnable) { 123 super(runnable, null); 124 } 125 126 public void setTimer(Timer timer) { 127 this.timer = timer; 128 } 129 130 @Override 131 public void timerExpired(Timer timer) { 132 runAndReset(); 133 } 134 135 @Override 136 public boolean cancel(boolean mayInterruptIfRunning) { 137 boolean result = super.cancel(mayInterruptIfRunning); 138 if (this.timer != null) { 139 this.timer.cancel(); 140 } 141 this.cancelled = true; 142 return result; 143 } 144 145 @Override 146 public long getDelay(TimeUnit unit) { 147 Assert.state(this.timer != null, "No Timer available"); 148 return unit.convert(this.timer.getScheduledExecutionTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS); 149 } 150 151 @Override 152 public int compareTo(Delayed other) { 153 if (this == other) { 154 return 0; 155 } 156 long diff = getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS); 157 return (diff == 0 ? 0 : ((diff < 0) ? -1 : 1)); 158 } 159 } 160 161 162 /** 163 * ScheduledFuture adapter for trigger-based rescheduling. 164 */ 165 private class ReschedulingTimerListener extends TimerScheduledFuture { 166 167 private final Trigger trigger; 168 169 private final SimpleTriggerContext triggerContext = new SimpleTriggerContext(); 170 171 private volatile Date scheduledExecutionTime = new Date(); 172 173 public ReschedulingTimerListener(Runnable runnable, Trigger trigger) { 174 super(runnable); 175 this.trigger = trigger; 176 } 177 178 @Nullable 179 public ScheduledFuture<?> schedule() { 180 Date nextExecutionTime = this.trigger.nextExecutionTime(this.triggerContext); 181 if (nextExecutionTime == null) { 182 return null; 183 } 184 this.scheduledExecutionTime = nextExecutionTime; 185 setTimer(obtainTimerManager().schedule(this, this.scheduledExecutionTime)); 186 return this; 187 } 188 189 @Override 190 public void timerExpired(Timer timer) { 191 Date actualExecutionTime = new Date(); 192 super.timerExpired(timer); 193 Date completionTime = new Date(); 194 this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime); 195 if (!this.cancelled) { 196 schedule(); 197 } 198 } 199 } 200 201}