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