1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.geronimo.concurrent.handlers; 18 19 import java.util.Map; 20 21 import javax.transaction.Status; 22 import javax.transaction.SystemException; 23 import javax.transaction.Transaction; 24 import javax.transaction.TransactionManager; 25 import javax.util.concurrent.ContextService; 26 27 import org.apache.commons.logging.Log; 28 import org.apache.commons.logging.LogFactory; 29 import org.apache.geronimo.concurrent.ManagedContextHandler; 30 31 /* 32 * Managed context handler that for handling transactions. Follows 33 * Bean-Managed Transaction Demarcation rules as described in EJB 3.0 specification 34 * 13.6.1 section. 35 */ 36 public abstract class TransactionContextHandler implements ManagedContextHandler { 37 38 protected final static Log LOG = LogFactory.getLog(TransactionContextHandler.class); 39 40 protected final static String TRANSACTION_MANAGER = 41 TransactionContextHandler.class.getName() + ".transactionManager"; 42 43 protected final static String CLIENT_TRANSACTION = 44 TransactionContextHandler.class.getName() + ".clientTransaction"; 45 46 private boolean isUseParentTransaction(Map<String, Object> threadContext) { 47 Object useParentTransaction = 48 threadContext.get(ContextService.USE_PARENT_TRANSACTION); 49 if (useParentTransaction instanceof String) { 50 return Boolean.valueOf((String)useParentTransaction).booleanValue(); 51 } else if (useParentTransaction instanceof Boolean) { 52 return Boolean.TRUE.equals(useParentTransaction); 53 } else { 54 return false; 55 } 56 } 57 58 public void setContext(Map<String, Object> threadContext) { 59 LOG.debug("setContext"); 60 61 if (!isUseParentTransaction(threadContext)) { 62 suspendTransaction(threadContext); 63 } 64 } 65 66 public void unsetContext(Map<String, Object> threadContext) { 67 LOG.debug("unsetContext"); 68 69 if (!isUseParentTransaction(threadContext)) { 70 resumeTransaction(threadContext); 71 } 72 } 73 74 protected TransactionManager getTransactionManager(Map<String, Object> threadContext) { 75 return (TransactionManager)threadContext.get(TRANSACTION_MANAGER); 76 } 77 78 protected void suspendTransaction(Map<String, Object> threadContext) { 79 LOG.debug("suspendTransaction"); 80 81 TransactionManager manager = getTransactionManager(threadContext); 82 83 try { 84 Transaction clientTransaction = manager.suspend(); 85 if (clientTransaction != null) { 86 threadContext.put(CLIENT_TRANSACTION, clientTransaction); 87 } 88 } catch (SystemException e) { 89 LOG.warn("Failed to suspend transaction", e); 90 } 91 } 92 93 public void resumeTransaction(Map<String, Object> threadContext) { 94 LOG.debug("resumeTransaction"); 95 96 TransactionManager manager = getTransactionManager(threadContext); 97 98 try { 99 /* 100 * The Container must detect the case in which a transaction was started, but 101 * not completed, in the business method, and handle it as follows: 102 */ 103 Transaction transaction = manager.getTransaction(); 104 105 if (transaction == null) { 106 return; 107 } 108 109 if (transaction.getStatus() != Status.STATUS_ROLLEDBACK && 110 transaction.getStatus() != Status.STATUS_COMMITTED) { 111 String message = "The task started a transaction but did not complete it."; 112 113 LOG.error(message); 114 115 try { 116 manager.rollback(); 117 } catch (Throwable t) { 118 // ignore 119 } 120 } 121 122 } catch (SystemException e) { 123 LOG.warn("Error handling transaction", e); 124 } finally { 125 Transaction clientTransaction = 126 (Transaction)threadContext.get(CLIENT_TRANSACTION); 127 if (clientTransaction != null) { 128 try { 129 manager.resume(clientTransaction); 130 } catch (Exception e) { 131 LOG.warn("Failed to resume transaction", e); 132 } 133 } 134 } 135 } 136 137 }