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 javax.transaction.TransactionManager;
022    import javax.transaction.Status;
023    
024    import org.apache.commons.logging.Log;
025    import org.apache.commons.logging.LogFactory;
026    
027    /**
028     * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
029     */
030    public class TransactionalExecutorTask implements ExecutorTask {
031        private static final Log log = LogFactory.getLog(TransactionalExecutorTask.class);
032    
033        private final Runnable userTask;
034        private final WorkInfo workInfo;
035        private final ThreadPooledTimer threadPooledTimer;
036    
037        private final TransactionManager transactionManager;
038        private final int repeatCount;
039    
040        public TransactionalExecutorTask(Runnable userTask, WorkInfo workInfo, ThreadPooledTimer threadPooledTimer, TransactionManager transactionManager, int repeatCount) {
041            this.userTask = userTask;
042            this.workInfo = workInfo;
043            this.threadPooledTimer = threadPooledTimer;
044            this.transactionManager = transactionManager;
045            this.repeatCount = repeatCount;
046        }
047    
048        public void run() {
049            try {
050                // try to do the work until it succeeded or we reach the repeat count
051                boolean succeeded = false;
052                for (int tries = 0; !succeeded && tries < repeatCount; tries++) {
053                    try {
054                        if (!beginWork()) {
055                            break;
056                        }
057    
058                        work();
059                    } finally {
060                        succeeded = completeWork();
061                    }
062                }
063    
064                // if this was a one time thing, remove the job
065                if (workInfo.isOneTime()) {
066                    threadPooledTimer.removeWorkInfo(workInfo);
067                }
068    
069                // if we didn't succeed, log it
070                if (!succeeded) {
071                    log.warn("Failed to execute work successfully");
072                }
073            } catch (RuntimeException e) {
074                log.warn("RuntimeException occured while running user task", e);
075                throw e;
076            } catch (Error e) {
077                log.warn("Error occured while running user task", e);
078                throw e;
079            }
080        }
081    
082        private boolean beginWork() {
083            try {
084                transactionManager.begin();
085            } catch (Exception e) {
086                log.warn("Exception occured while starting container transaction", e);
087                return false;
088            }
089            return true;
090        }
091    
092        private void work() {
093            try {
094                userTask.run();
095            } catch (Exception e) {
096                log.warn("Exception occured while running user task", e);
097            }
098        }
099    
100        private boolean completeWork() {
101            try {
102                if (transactionManager.getStatus() == Status.STATUS_ACTIVE) {
103                    // clean up the work persistent data
104                    try {
105                        threadPooledTimer.workPerformed(workInfo);
106                    } catch (PersistenceException e) {
107                        log.warn("Exception occured while updating timer persistent state", e);
108                    }
109    
110                    // commit the tx
111                    transactionManager.commit();
112    
113                    // all is cool
114                    return true;
115                } else {
116                    // tx was marked rollback, so roll it back
117                    transactionManager.rollback();
118                }
119            } catch (Exception e) {
120                log.warn("Exception occured while completing container transaction", e);
121            }
122            // something bad happened
123            return false;
124        }
125    
126    }