
org.apache.geronimo.timer.ThreadPooledTimer Maven / Gradle / Ivy
The newest version!
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.geronimo.timer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import java.util.concurrent.Executor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geronimo.gbean.GBeanLifecycle;
/**
*
*
* @version $Rev: 520573 $ $Date: 2007-03-21 04:48:26 +0800 (Wed, 21 Mar 2007) $
*
* */
public class ThreadPooledTimer implements PersistentTimer, GBeanLifecycle {
private static final Log log = LogFactory.getLog(ThreadPooledTimer.class);
private final ExecutorTaskFactory executorTaskFactory;
private final WorkerPersistence workerPersistence;
private final Executor executor;
private final TransactionManager transactionManager;
private Timer delegate;
private final Map idToWorkInfoMap = Collections.synchronizedMap(new HashMap());
//default constructor for use as reference endpoint.
public ThreadPooledTimer() {
this(null, null, null, null);
}
public ThreadPooledTimer(ExecutorTaskFactory executorTaskFactory, WorkerPersistence workerPersistence, Executor executor, TransactionManager transactionManager) {
this.executorTaskFactory = executorTaskFactory;
this.workerPersistence = workerPersistence;
this.executor = executor;
this.transactionManager = transactionManager;
}
public void doStart() throws Exception {
delegate = new Timer(true);
}
public void doStop() {
if (delegate != null) {
delegate.cancel();
delegate = null;
}
}
public void doFail() {
doStop();
}
public WorkInfo schedule(UserTaskFactory userTaskFactory, String key, Object userId, Object userInfo, long delay) throws PersistenceException, RollbackException, SystemException {
if (delay < 0) {
throw new IllegalArgumentException("Negative delay: " + delay);
}
Date time = new Date(System.currentTimeMillis() + delay);
return schedule(key, userTaskFactory, userId, userInfo, time);
}
public WorkInfo schedule(String key, UserTaskFactory userTaskFactory, Object userId, Object userInfo, Date time) throws PersistenceException, RollbackException, SystemException {
if (time ==null) {
throw new IllegalArgumentException("No time supplied");
}
if (time.getTime() < 0) {
throw new IllegalArgumentException("Negative time: " + time.getTime());
}
WorkInfo worker = createWorker(key, userTaskFactory, executorTaskFactory, userId, userInfo, time, null, false);
registerSynchronization(new ScheduleSynchronization(worker.getExecutorFeedingTimerTask(), time));
addWorkInfo(worker);
return worker;
}
public WorkInfo schedule(String key, UserTaskFactory userTaskFactory, Object userInfo, long delay, long period, Object userId) throws PersistenceException, RollbackException, SystemException {
if (delay < 0) {
throw new IllegalArgumentException("Negative delay: " + delay);
}
if (period < 0) {
throw new IllegalArgumentException("Negative period: " + period);
}
Date time = new Date(System.currentTimeMillis() + delay);
return schedule(key, userTaskFactory, userId, userInfo, time, period);
}
public WorkInfo schedule(String key, UserTaskFactory userTaskFactory, Object userId, Object userInfo, Date firstTime, long period) throws PersistenceException, RollbackException, SystemException {
if (firstTime ==null) {
throw new IllegalArgumentException("No time supplied");
}
if (firstTime.getTime() < 0) {
throw new IllegalArgumentException("Negative time: " + firstTime.getTime());
}
if (period < 0) {
throw new IllegalArgumentException("Negative period: " + period);
}
WorkInfo worker = createWorker(key, userTaskFactory, executorTaskFactory, userId, userInfo, firstTime, new Long(period), false);
registerSynchronization(new ScheduleRepeatedSynchronization(worker.getExecutorFeedingTimerTask(), firstTime, period));
addWorkInfo(worker);
return worker;
}
public WorkInfo scheduleAtFixedRate(String key, UserTaskFactory userTaskFactory, Object userId, Object userInfo, long delay, long period) throws PersistenceException, RollbackException, SystemException {
if (delay < 0) {
throw new IllegalArgumentException("Negative delay: " + delay);
}
if (period < 0) {
throw new IllegalArgumentException("Negative period: " + period);
}
Date time = new Date(System.currentTimeMillis() + delay);
return scheduleAtFixedRate(key, userTaskFactory, userId, userInfo, time, period);
}
public WorkInfo scheduleAtFixedRate(String key, UserTaskFactory userTaskFactory, Object userId, Object userInfo, Date firstTime, long period) throws PersistenceException, RollbackException, SystemException {
if (firstTime ==null) {
throw new IllegalArgumentException("No time supplied");
}
if (firstTime.getTime() < 0) {
throw new IllegalArgumentException("Negative time: " + firstTime.getTime());
}
if (period < 0) {
throw new IllegalArgumentException("Negative period: " + period);
}
WorkInfo worker = createWorker(key, userTaskFactory, executorTaskFactory, userId, userInfo, firstTime, new Long(period), true);
registerSynchronization(new ScheduleAtFixedRateSynchronization(worker.getExecutorFeedingTimerTask(), firstTime, period));
addWorkInfo(worker);
return worker;
}
public Collection playback(String key, UserTaskFactory userTaskFactory) throws PersistenceException {
PlaybackImpl playback = new PlaybackImpl(userTaskFactory);
workerPersistence.playback(key, playback);
return playback.getWorkInfos();
}
public Collection getIdsByKey(String key, Object userId) throws PersistenceException {
return workerPersistence.getIdsByKey(key, userId);
}
public WorkInfo getWorkInfo(Long id) {
return (WorkInfo) idToWorkInfoMap.get(id);
}
/**
* Called when client, eg. ejb container, is stopped and needs to cancel its timertasks without
* affecting persisted timer data.
* @param ids list of ids to have their corresponding workInfo timertasks cancelled.
*/
public void cancelTimerTasks(Collection ids) {
for (Iterator iterator = ids.iterator(); iterator.hasNext();) {
Long idLong = (Long) iterator.next();
WorkInfo workInfo = getWorkInfo(idLong);
if (workInfo != null) {
TimerTask timerTask = workInfo.getExecutorFeedingTimerTask();
timerTask.cancel();
}
}
}
void addWorkInfo(WorkInfo worker) {
idToWorkInfoMap.put(new Long(worker.getId()), worker);
}
void removeWorkInfo(WorkInfo workInfo) {
idToWorkInfoMap.remove(new Long(workInfo.getId()));
}
void workPerformed(WorkInfo workInfo) throws PersistenceException {
if (workInfo.isOneTime()) {
workerPersistence.cancel(workInfo.getId());
} else if (workInfo.getAtFixedRate()) {
workerPersistence.fixedRateWorkPerformed(workInfo.getId());
workInfo.nextTime();
} else {
workInfo.nextInterval();
workerPersistence.intervalWorkPerformed(workInfo.getId(), workInfo.getPeriod().longValue());
}
}
Timer getTimer() {
if (delegate == null) {
throw new IllegalStateException("Timer is stopped");
}
return delegate;
}
WorkerPersistence getWorkerPersistence() {
return workerPersistence;
}
Executor getExecutor() {
return executor;
}
private WorkInfo createWorker(String key, UserTaskFactory userTaskFactory, ExecutorTaskFactory executorTaskFactory, Object userId, Object userInfo, Date time, Long period, boolean atFixedRate) throws PersistenceException {
if (time == null) {
throw new IllegalArgumentException("Null initial time");
}
WorkInfo workInfo = new WorkInfo(key, userId, userInfo, time, period, atFixedRate);
//save and assign id
workerPersistence.save(workInfo);
Runnable userTask = userTaskFactory.newTask(workInfo.getId());
ExecutorTask executorTask = executorTaskFactory.createExecutorTask(userTask, workInfo, this);
ExecutorFeedingTimerTask worker = new ExecutorFeedingTimerTask(workInfo, this);
workInfo.initialize(worker, executorTask);
return workInfo;
}
void registerSynchronization(Synchronization sync) throws RollbackException, SystemException {
Transaction transaction = transactionManager.getTransaction();
int status = transaction == null ? Status.STATUS_NO_TRANSACTION : transaction.getStatus();
if (transaction != null && status == Status.STATUS_ACTIVE || status == Status.STATUS_MARKED_ROLLBACK) {
transaction.registerSynchronization(sync);
} else {
sync.beforeCompletion();
sync.afterCompletion(Status.STATUS_COMMITTED);
}
}
private class ScheduleSynchronization implements Synchronization {
private final ExecutorFeedingTimerTask worker;
private final Date time;
public ScheduleSynchronization(ExecutorFeedingTimerTask worker, Date time) {
this.worker = worker;
this.time = time;
}
public void beforeCompletion() {
}
public void afterCompletion(int status) {
if (status == Status.STATUS_COMMITTED) {
if (worker.isCancelled()) {
log.trace("Worker is already cancelled, not scheduling");
return;
}
try {
getTimer().schedule(worker, time);
} catch (IllegalStateException e) {
//TODO consider again if catching this exception is appropriate
log.warn("Couldn't schedule worker " + e.getMessage() + "at (now) " + System.currentTimeMillis() + " for " + time.getTime());
}
}
}
}
private class ScheduleRepeatedSynchronization implements Synchronization {
private final ExecutorFeedingTimerTask worker;
private final Date time;
private final long period;
public ScheduleRepeatedSynchronization(ExecutorFeedingTimerTask worker, Date time, long period) {
this.worker = worker;
this.time = time;
this.period = period;
}
public void beforeCompletion() {
}
public void afterCompletion(int status) {
if (status == Status.STATUS_COMMITTED) {
if (worker.isCancelled()) {
log.trace("Worker is already cancelled, not scheduling/period");
return;
}
try {
getTimer().schedule(worker, time, period);
} catch (Exception e) {
log.warn("Couldn't schedule/period worker " + e.getMessage() + "at (now) " + System.currentTimeMillis() + " for " + time.getTime());
}
}
}
}
private class ScheduleAtFixedRateSynchronization implements Synchronization {
private final ExecutorFeedingTimerTask worker;
private final Date time;
private final long period;
public ScheduleAtFixedRateSynchronization(ExecutorFeedingTimerTask worker, Date time, long period) {
this.worker = worker;
this.time = time;
this.period = period;
}
public void beforeCompletion() {
}
public void afterCompletion(int status) {
if (status == Status.STATUS_COMMITTED) {
if (worker.isCancelled()) {
log.trace("Worker is already cancelled, not scheduleAtFixedRate");
return;
}
try {
getTimer().scheduleAtFixedRate(worker, time, period);
} catch (Exception e) {
log.warn("Couldn't scheduleAtFixedRate worker " + e.getMessage() + "at (now) " + System.currentTimeMillis() + " for " + time.getTime());
}
}
}
}
private class PlaybackImpl implements Playback {
private final UserTaskFactory userTaskFactory;
private final Collection workInfos = new ArrayList();
public PlaybackImpl(UserTaskFactory userTaskFactory) {
this.userTaskFactory = userTaskFactory;
}
public void schedule(WorkInfo workInfo) {
Runnable userTask = userTaskFactory.newTask(workInfo.getId());
ExecutorTask executorTask = executorTaskFactory.createExecutorTask(userTask, workInfo, ThreadPooledTimer.this);
ExecutorFeedingTimerTask worker = new ExecutorFeedingTimerTask(workInfo, ThreadPooledTimer.this);
workInfo.initialize(worker, executorTask);
if (workInfo.getPeriod() == null) {
getTimer().schedule(worker, workInfo.getTime());
} else if (!workInfo.getAtFixedRate()) {
getTimer().schedule(worker, workInfo.getTime(), workInfo.getPeriod().longValue());
} else {
getTimer().scheduleAtFixedRate(worker, workInfo.getTime(), workInfo.getPeriod().longValue());
}
addWorkInfo(workInfo);
workInfos.add(workInfo);
}
public Collection getWorkInfos() {
return workInfos;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy