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: 514870 $ $Date: 2007-03-05 16:18:26 -0500 (Mon, 05 Mar 2007) $ 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 }