KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openejb > resource > SharedLocalConnectionManager


1 /**
2  * Redistribution and use of this software and associated documentation
3  * ("Software"), with or without modification, are permitted provided
4  * that the following conditions are met:
5  *
6  * 1. Redistributions of source code must retain copyright
7  * statements and notices. Redistributions must also contain a
8  * copy of this document.
9  *
10  * 2. Redistributions in binary form must reproduce the
11  * above copyright notice, this list of conditions and the
12  * following disclaimer in the documentation and/or other
13  * materials provided with the distribution.
14  *
15  * 3. The name "Exolab" must not be used to endorse or promote
16  * products derived from this Software without prior written
17  * permission of Exoffice Technologies. For written permission,
18  * please contact info@exolab.org.
19  *
20  * 4. Products derived from this Software may not be called "Exolab"
21  * nor may "Exolab" appear in their names without prior written
22  * permission of Exoffice Technologies. Exolab is a registered
23  * trademark of Exoffice Technologies.
24  *
25  * 5. Due credit should be given to the Exolab Project
26  * (http://www.exolab.org/).
27  *
28  * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32  * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39  * OF THE POSSIBILITY OF SUCH DAMAGE.
40  *
41  * Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
42  *
43  * $Id: SharedLocalConnectionManager.java 1447 2004-10-25 12:34:45Z pmlopes $
44  */

45  package org.openejb.resource;
46
47 import java.util.HashMap JavaDoc;
48 import java.util.HashSet JavaDoc;
49 import java.util.Set JavaDoc;
50
51 import javax.resource.spi.ConnectionEvent JavaDoc;
52 import javax.resource.spi.ConnectionRequestInfo JavaDoc;
53 import javax.resource.spi.LocalTransaction JavaDoc;
54 import javax.resource.spi.ManagedConnection JavaDoc;
55 import javax.resource.spi.ManagedConnectionFactory JavaDoc;
56 import javax.transaction.Transaction JavaDoc;
57
58 import org.openejb.OpenEJB;
59 /**
60  * This ConnectionManager provides a simple algorithm for managing <i>shared-local</i> transactions for multiple
61  * connectors. It ensures that components participating in the same logical thread of execution share physical connections
62  * to resources like JDBC connections or JMS connections. For example, Component A calls Component B within one transaction.
63  * If both components access the same resource (e.g. some database), they will transparently share the same physical connection.
64  * This makes it possible to group the resource work of both components with the same local transaction (all or nothing tx semantics),
65  * as well as conserving resources.
66  * <p>
67  * This ConnectionManager relies on the the container's transaction manager to delineate the scope of the transaction using the
68  * TransactionManager's synchronization facilities. The shared-local resources are not enlisted in 2PC transactions; they execute
69  * only in local transactions.
70  * <p>
71  * Multiple connectors can be managed by one instance of the this class. The instance will ensure that components share
72  * access to the correct connectors within the context of a same thread of execution.
73  *
74  * @author <a HREF="richard@monson-haefel.com">Richard Monson-Haefel</a>
75  * @version $ $
76  */

77 public class SharedLocalConnectionManager implements javax.resource.spi.ConnectionManager JavaDoc,
78 javax.resource.spi.ConnectionEventListener JavaDoc,
79 java.io.Serializable JavaDoc {
80
81     private Set JavaDoc connSet;
82     private SpecialHashThreadLocal threadLocal = new SpecialHashThreadLocal();
83     private HashMap JavaDoc factoryMap = new HashMap JavaDoc();
84
85     public void init(java.util.Properties JavaDoc props){
86         // just for test purposes
87
//props = props;
88
}
89
90     public SharedLocalConnectionManager() throws javax.resource.spi.ApplicationServerInternalException JavaDoc{
91         connSet = java.util.Collections.synchronizedSet(new HashSet JavaDoc());
92     }
93     public java.lang.Object JavaDoc allocateConnection(ManagedConnectionFactory JavaDoc factory,
94                                                ConnectionRequestInfo JavaDoc cxRequestInfo)
95     throws javax.resource.ResourceException JavaDoc {
96
97         //Object securityIdentity = OpenEJB.getSecurityService().getSecurityIdentity();
98
//Subject subject = (Subject)OpenEJB.getSecurityService().translateTo(securityIdentity, Subject.class);
99

100         ManagedConnection JavaDoc conn = (ManagedConnection JavaDoc)threadLocal.get(factory);
101         if(conn == null){
102             conn = factory.matchManagedConnections(connSet, null, cxRequestInfo);
103             if (conn != null)
104                 connSet.remove(conn);
105             else { //if(conn == null)
106
conn = factory.createManagedConnection(null, cxRequestInfo);
107                 conn.addConnectionEventListener(this);
108             }
109             conn.getLocalTransaction().begin();
110
111             try{
112                 /*
113                 * The transaction manager has a wrapper that ensures that any Synchronization
114                 * objects are handled after the EntityBean.ejbStore and SessionSynchronization methods of beans.
115                 * In the StatefulContainer and EntityContainer enterprise beans are wrapped
116                 * Synchronization wrappers, which must be handled
117                 * before the LocalTransaction objects in this connection manager.
118                 */

119                 Transaction JavaDoc tx = OpenEJB.getTransactionManager().getTransaction();
120                 if(tx!=null)
121                 tx.registerSynchronization(new Synchronizer(conn.getLocalTransaction()));
122             }catch(javax.transaction.SystemException JavaDoc se){
123                 throw new javax.resource.spi.ApplicationServerInternalException JavaDoc("Can not obtain a Transaction object from TransactionManager. "+se.getMessage());
124             }catch(javax.transaction.RollbackException JavaDoc re){
125                 throw new javax.resource.spi.ApplicationServerInternalException JavaDoc("Can not register org.openejb.resource.LocalTransacton with transaciton manager. Transaction has already been rolled back"+re.getMessage());
126             }
127
128             threadLocal.put(factory,conn);
129         }
130         // FIXME: Where do I get the javax.security.auth.Subject for the first parameter
131
Object JavaDoc handle = conn.getConnection(null, cxRequestInfo);
132         return handle;
133     }
134
135     public void connectionClosed(ConnectionEvent JavaDoc event){
136         try{
137         if(OpenEJB.getTransactionManager().getTransaction()==null){
138             ManagedConnection JavaDoc conn = (ManagedConnection JavaDoc)event.getSource();
139             conn.getLocalTransaction().commit();
140             this.cleanup(conn);
141         }
142         }catch(javax.transaction.SystemException JavaDoc se){
143             // this is a connection event notification so the exception can not be propagated.
144
// log the exception but no action required.
145
}catch(javax.resource.ResourceException JavaDoc re){
146             // this exception is thrown bby the event.getSource() no processing required.
147
}
148     }
149
150     public void connectionErrorOccurred(ConnectionEvent JavaDoc event){
151         ManagedConnection JavaDoc conn = (ManagedConnection JavaDoc)event.getSource();
152         // fetching the factory before doing clean up is important: The equals() value of the
153
// ManagedConnection may change after it has been cleaned up, which impacts hash lookups.
154
ManagedConnectionFactory JavaDoc mcf = (ManagedConnectionFactory JavaDoc)threadLocal.getKey(conn);
155         try{
156         conn.destroy();
157             if ( threadLocal.get(mcf)==conn ) threadLocal.put(mcf,null);
158         }catch(javax.resource.ResourceException JavaDoc re){
159             // do nothing. Allow conneciton to be garbage collected
160
}
161     }
162
163     public void localTransactionCommitted(ConnectionEvent JavaDoc event){
164         cleanup((ManagedConnection JavaDoc)event.getSource());
165     }
166
167     public void localTransactionRolledback(ConnectionEvent JavaDoc event){
168         cleanup((ManagedConnection JavaDoc)event.getSource());
169     }
170
171     private void cleanup(ManagedConnection JavaDoc conn){
172         if(conn!=null){
173             // fetching the factory before doing clean up is important: The equals() value of the
174
// ManagedConnection may change after it has been cleaned up, which impacts hash lookups.
175
ManagedConnectionFactory JavaDoc mcf = (ManagedConnectionFactory JavaDoc)threadLocal.getKey(conn);
176             try{
177                 conn.cleanup();
178                 connSet.add(conn);
179
180             }catch(javax.resource.ResourceException JavaDoc re){
181                 try{
182                 // FIXME: log connection loss
183
conn.destroy();
184                 }catch(javax.resource.ResourceException JavaDoc re2){
185                     // do nothing
186
}
187             }
188             threadLocal.put(mcf,null);
189         }
190     }
191     public void localTransactionStarted(ConnectionEvent JavaDoc event){
192         // do nothing. This object started the transaction so its already aware of this event
193
}
194
195
196     static class Synchronizer implements javax.transaction.Synchronization JavaDoc{
197         LocalTransaction JavaDoc localTx;
198
199         public Synchronizer(LocalTransaction JavaDoc lt){
200             localTx = lt;
201         }
202         public void beforeCompletion(){
203         }
204
205         public void afterCompletion(int status){
206             if ( status == javax.transaction.Status.STATUS_COMMITTED ){
207                 try{
208                 localTx.commit();
209                 } catch ( javax.resource.ResourceException JavaDoc re ) {
210                     throw new RuntimeException JavaDoc("JDBC driver failed to commit transaction. "+ re.getMessage());
211                 }
212             } else {
213                 try{
214                 localTx.rollback();
215                 } catch ( javax.resource.ResourceException JavaDoc re ) {
216                     throw new RuntimeException JavaDoc("JDBC driver failed to rollback transaction. "+ re.getMessage());
217                 }
218             }
219         }
220     }
221
222     /*
223     * This class allows the ConnectionManager to determine the key used for
224     * any object stored in this type of HashThreadLocal. Its needed when handling
225     * ConnectionListner events because the key (ManagedConnectionFactory) used to
226     * store values (ManagedConnecitons) is not available.
227     */

228     static class SpecialHashThreadLocal extends org.openejb.util.HashThreadLocal{
229         HashMap JavaDoc keyMap = new HashMap JavaDoc();
230         public synchronized void put(Object JavaDoc key, Object JavaDoc value){
231             if(!keyMap.containsKey(key))keyMap.put(value,key);
232             super.put(key,value);
233         }
234         public synchronized Object JavaDoc getKey(Object JavaDoc value){
235             return keyMap.get(value);
236         }
237     }
238
239 }
Popular Tags