View Javadoc

1   /**
2    *
3    *  Licensed to the Apache Software Foundation (ASF) under one or more
4    *  contributor license agreements.  See the NOTICE file distributed with
5    *  this work for additional information regarding copyright ownership.
6    *  The ASF licenses this file to You under the Apache License, Version 2.0
7    *  (the "License"); you may not use this file except in compliance with
8    *  the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing, software
13   *  distributed under the License is distributed on an "AS IS" BASIS,
14   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *  See the License for the specific language governing permissions and
16   *  limitations under the License.
17   */
18  package org.apache.geronimo.connector;
19  
20  import java.util.Map;
21  import java.util.HashMap;
22  import java.util.Iterator;
23  
24  import javax.transaction.Transaction;
25  import javax.transaction.Synchronization;
26  import javax.transaction.RollbackException;
27  import javax.transaction.SystemException;
28  
29  import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
30  import org.apache.geronimo.connector.outbound.TransactionCachingInterceptor;
31  
32  /**
33   * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
34   */
35  public class ConnectorTransactionContext {
36      private static final ConcurrentHashMap DATA_INDEX = new ConcurrentHashMap();
37  
38      public static ConnectorTransactionContext get(Transaction transaction) {
39          if (transaction == null) {
40              throw new NullPointerException("transaction is null");
41          }
42  
43          ConnectorTransactionContext ctx = (ConnectorTransactionContext) DATA_INDEX.get(transaction);
44          if (ctx == null) {
45              ctx = new ConnectorTransactionContext();
46  
47              try {
48                  transaction.registerSynchronization(new ConnectorSynchronization(ctx, transaction));
49              } catch (RollbackException e) {
50                  throw (IllegalStateException) new IllegalStateException("Transaction is already rolled back").initCause(e);
51              } catch (SystemException e) {
52                  throw new RuntimeException("Unable to register ejb transaction synchronization callback", e);
53              }
54  
55              // Note: no synchronization is necessary here.  Since a transaction can only be associated with a single
56              // thread at a time, it should not be possible for someone else to have snuck in and created a
57              // ConnectorTransactionContext for this transaction.  We still protect against that with the putIfAbsent
58              // call below, and we simply have an extra transaction synchronization registered that won't do anything
59              DATA_INDEX.putIfAbsent(transaction, ctx);
60          }
61          return ctx;
62      }
63  
64      public static TransactionCachingInterceptor.ManagedConnectionInfos get(Transaction transaction, ConnectionReleaser key) {
65          ConnectorTransactionContext ctx = get(transaction);
66          TransactionCachingInterceptor.ManagedConnectionInfos infos = ctx.getManagedConnectionInfo(key);
67          if (infos == null) {
68              infos = new TransactionCachingInterceptor.ManagedConnectionInfos();
69              ctx.setManagedConnectionInfo(key, infos);
70          }
71          return infos;
72      }
73  
74      private static void remove(Transaction transaction) {
75          DATA_INDEX.remove(transaction);
76      }
77  
78      private Map managedConnections;
79  
80      private synchronized TransactionCachingInterceptor.ManagedConnectionInfos getManagedConnectionInfo(ConnectionReleaser key) {
81          if (managedConnections == null) {
82              return null;
83          }
84          return (TransactionCachingInterceptor.ManagedConnectionInfos) managedConnections.get(key);
85      }
86  
87      private synchronized void setManagedConnectionInfo(ConnectionReleaser key, TransactionCachingInterceptor.ManagedConnectionInfos info) {
88          if (managedConnections == null) {
89              managedConnections = new HashMap();
90          }
91          managedConnections.put(key, info);
92      }
93  
94      private static class ConnectorSynchronization implements Synchronization {
95          private final ConnectorTransactionContext ctx;
96          private final Transaction transaction;
97  
98          public ConnectorSynchronization(ConnectorTransactionContext ctx, Transaction transaction) {
99              this.ctx = ctx;
100             this.transaction = transaction;
101         }
102 
103         public void beforeCompletion() {
104         }
105 
106         public void afterCompletion(int status) {
107             try {
108                 synchronized (ctx) {
109                     if (ctx.managedConnections != null) {
110                         for (Iterator entries = ctx.managedConnections.entrySet().iterator(); entries.hasNext();) {
111                             Map.Entry entry = (Map.Entry) entries.next();
112                             ConnectionReleaser key = (ConnectionReleaser) entry.getKey();
113                             key.afterCompletion(entry.getValue());
114                         }
115                         //If BeanTransactionContext never reuses the same instance for sequential BMT, this
116                         //clearing is unnecessary.
117                         ctx.managedConnections.clear();
118                     }
119                 }
120             } finally {
121                 remove(transaction);
122             }
123         }
124     }
125 }