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