001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.timer;
019
020 import java.util.TimerTask;
021
022 import javax.transaction.RollbackException;
023 import javax.transaction.SystemException;
024 import javax.transaction.Synchronization;
025 import javax.transaction.Status;
026
027 import org.apache.commons.logging.Log;
028 import org.apache.commons.logging.LogFactory;
029
030 /**
031 *
032 *
033 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
034 *
035 * */
036 public class ExecutorFeedingTimerTask extends TimerTask {
037
038 private static final Log log = LogFactory.getLog(ExecutorFeedingTimerTask.class);
039
040 private final WorkInfo workInfo;
041 private final ThreadPooledTimer threadPooledTimer;
042 boolean cancelled = false;
043
044 public ExecutorFeedingTimerTask(WorkInfo workInfo, ThreadPooledTimer threadPooledTimer) {
045 this.workInfo = workInfo;
046 this.threadPooledTimer = threadPooledTimer;
047 }
048
049 public void run() {
050 try {
051 threadPooledTimer.getExecutor().execute(workInfo.getExecutorTask());
052 } catch (Throwable t) {
053 log.error("Error occurred during execution of ExpirationMonitor TimerTask", t);
054 }
055 }
056
057 public boolean cancel() {
058 threadPooledTimer.removeWorkInfo(workInfo);
059 try {
060 threadPooledTimer.registerSynchronization(new CancelSynchronization(this));
061 } catch (RollbackException e) {
062 log.warn("Exception canceling task", e);
063 throw (IllegalStateException) new IllegalStateException("RollbackException when trying to register Cancel Synchronization").initCause(e);
064 } catch (SystemException e) {
065 log.warn("Exception canceling task", e);
066 throw (IllegalStateException) new IllegalStateException("SystemException when trying to register Cancel Synchronization").initCause(e);
067 }
068 // One cancels the task at this specific time. If the transaction is
069 // rolled-back, one will recreate it.
070 cancelled = true;
071 return super.cancel();
072 }
073
074 public boolean isCancelled() {
075 return cancelled;
076 }
077
078 private void doCancel() {
079 try {
080 // Impacts the timer storage only if the timer is cancelled
081 // in the scope of a committed transactions.
082 threadPooledTimer.getWorkerPersistence().cancel(workInfo.getId());
083 } catch (PersistenceException e) {
084 log.warn("Exception canceling task", e);
085 }
086 }
087
088 private void rollbackCancel() {
089 threadPooledTimer.addWorkInfo(workInfo);
090
091 // The transaction has been rolled-back, we need to restore the
092 // task as if cancel has been called.
093 if ( workInfo.isOneTime() ) {
094 threadPooledTimer.getTimer().schedule(
095 new ExecutorFeedingTimerTask(workInfo, threadPooledTimer),
096 workInfo.getTime());
097 } else if ( workInfo.getAtFixedRate() ) {
098 threadPooledTimer.getTimer().scheduleAtFixedRate(
099 new ExecutorFeedingTimerTask(workInfo, threadPooledTimer),
100 workInfo.getTime(), workInfo.getPeriod().longValue());
101 } else {
102 threadPooledTimer.getTimer().schedule(
103 new ExecutorFeedingTimerTask(workInfo, threadPooledTimer),
104 workInfo.getTime(), workInfo.getPeriod().longValue());
105 }
106 }
107
108 private static class CancelSynchronization implements Synchronization {
109
110 private final ExecutorFeedingTimerTask worker;
111
112 public CancelSynchronization(ExecutorFeedingTimerTask worker) {
113 this.worker = worker;
114 }
115
116 public void beforeCompletion() {
117 }
118
119 public void afterCompletion(int status) {
120 if (status == Status.STATUS_COMMITTED) {
121 worker.doCancel();
122 } else if (status == Status.STATUS_ROLLEDBACK) {
123 worker.rollbackCancel();
124 }
125 }
126
127 }
128
129 }