KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openejb > core > stateful > SessionSynchronizationCoordinator


1 package org.openejb.core.stateful;
2
3 import javax.ejb.EnterpriseBean JavaDoc;
4 import javax.ejb.SessionSynchronization JavaDoc;
5 import javax.transaction.Status JavaDoc;
6 import javax.transaction.Transaction JavaDoc;
7 import javax.transaction.TransactionManager JavaDoc;
8
9 import org.openejb.ApplicationException;
10 import org.openejb.OpenEJB;
11 import org.openejb.SystemException;
12 import org.openejb.core.Operations;
13 import org.openejb.core.ThreadContext;
14 import org.openejb.core.transaction.TransactionContext;
15 import org.openejb.util.Logger;
16
17 /**
18  * This class manages all the SessionSynchronization instances for a given
19  * transaction.
20  *
21  * The SessionSynchronizationCoordinator registers with the transaction and
22  * receives the beforeCompletion and afterCompletion events when the transaction
23  * completes.
24  *
25  * When this object receives the beforeCompletion and afterCompletion events,
26  * it invokes the appropriate container-callback on the SessionSynchronization
27  * objects registered with this coordinator.
28  *
29  * @author <a HREF="mailto=David.Blevins@visi.com">David Blevins</a>
30  * @author <a HREF="mailto=Richard@Monson-Haefel.com">Richard Monson-Haefel</a>
31  * @version $Revision: 1096 $ $Date: 2004-03-26 13:41:16 -0800 (Fri, 26 Mar 2004) $
32  */

33 public class SessionSynchronizationCoordinator implements javax.transaction.Synchronization JavaDoc{
34     
35
36     private static java.util.HashMap JavaDoc coordinators = new java.util.HashMap JavaDoc();
37     public static Logger logger = Logger.getInstance( "OpenEJB", "org.openejb.util.resources" );
38
39     /**
40      * The actual instances are not stored in this hash as we cannot forsee how
41      * long the transaction will take. It is very possible that the stateful
42      * session instance is passivated and activated several times. Instead, we
43      * hold the primary key of the stateful session instance and ask the
44      * StatefulInstanceManager for the instance when the time is right.
45      * key: primaryKey value: ThreadContext
46      */

47     private java.util.HashMap JavaDoc sessionSynchronizations = new java.util.HashMap JavaDoc();
48     
49
50     public static void registerSessionSynchronization(SessionSynchronization JavaDoc session, TransactionContext context) throws javax.transaction.SystemException JavaDoc, javax.transaction.RollbackException JavaDoc{
51         SessionSynchronizationCoordinator coordinator = null;
52         
53         coordinator = (SessionSynchronizationCoordinator)coordinators.get( context.currentTx );
54
55         if (coordinator == null) {
56             coordinator = new SessionSynchronizationCoordinator();
57             try{
58                 context.currentTx.registerSynchronization( coordinator);
59             }catch(Exception JavaDoc e) {
60                 // this should never fail because of the bahavior defined in TransactionManagerWrapper
61
logger.error("", e);
62                 return;
63             }
64             coordinators.put( context.currentTx, coordinator );
65         }
66
67         coordinator._registerSessionSynchronization( session, context.callContext );
68     }
69     
70     private void _registerSessionSynchronization(SessionSynchronization JavaDoc session, ThreadContext callContext){
71         boolean registered = sessionSynchronizations.containsKey( callContext.getPrimaryKey() );
72
73         if ( registered ) return;
74
75         try{
76             callContext = (ThreadContext)callContext.clone();
77         }catch(Exception JavaDoc e) {}
78         sessionSynchronizations.put(callContext.getPrimaryKey(), callContext);
79
80         byte currentOperation = callContext.getCurrentOperation();
81         callContext.setCurrentOperation(Operations.OP_AFTER_BEGIN);
82         try{
83             
84             session.afterBegin();
85         
86         } catch (Exception JavaDoc e){
87             String JavaDoc message = "An unexpected system exception occured while invoking the afterBegin method on the SessionSynchronization object: "+e.getClass().getName()+" "+e.getMessage();
88             logger.error(message, e);
89             throw new RuntimeException JavaDoc( message );
90
91         } finally {
92            callContext.setCurrentOperation(currentOperation);
93         }
94     }
95
96     /**
97     * This method is called by the transaction
98     * manager prior to the start of the transaction completion process.
99     */

100     public void beforeCompletion() {
101         
102         ThreadContext originalContext = ThreadContext.getThreadContext();
103         
104         Object JavaDoc[] contexts = sessionSynchronizations.values().toArray();
105
106         for(int i = 0; i < contexts.length; i++){
107
108             // Have to reassocaite the original thread context with the thread before invoking
109
ThreadContext callContext = (ThreadContext)contexts[i];
110             
111             ThreadContext.setThreadContext(callContext);
112             StatefulInstanceManager instanceManager = null;
113             
114             try{
115                 StatefulContainer container = (StatefulContainer)callContext.getDeploymentInfo().getContainer();
116                 instanceManager = container.getInstanceManager();
117                 /*
118                 * the operation must be set before the instance is obtained from the pool, so
119                 * that the instance manager doesn't mistake this as a concurrent access.
120                 */

121                 callContext.setCurrentOperation(Operations.OP_BEFORE_COMPLETION);
122                 
123                 SessionSynchronization JavaDoc bean = (SessionSynchronization JavaDoc)instanceManager.obtainInstance(callContext.getPrimaryKey(), callContext);
124                 bean.beforeCompletion();
125                 instanceManager.poolInstance(callContext.getPrimaryKey(), (EnterpriseBean JavaDoc)bean);
126             }catch(org.openejb.InvalidateReferenceException inv) {
127                 // the bean doesn't exist anymore, e.g. a system exception occured
128
// and the bean hass been discarded. No container callbacks
129
// are allowed at this point
130
// therefore we simply do nothing() here....
131
}catch(Exception JavaDoc e){
132                 // This exception should go back to the TransactionManager where
133
// it will be rethrown by the TransactionManager as the appropriate
134
// exception type ( TransactionRolledBackException or whatever) to the
135
// bean or client that requested the transaction to be commited or rolledback.
136
// The TransactionManager will not understand the OpenEJBException, the
137
// RemoteException is understandable.
138

139                 // EJB 2.0: 18.3.3 Exceptions from container-invoked callbacks
140
String JavaDoc message = "An unexpected system exception occured while invoking the beforeCompletion method on the SessionSynchronization object: "+e.getClass().getName()+" "+e.getMessage();
141                 
142                 /* [1] Log the exception or error */
143                 logger.error( message, e);
144                 
145                 /* [2] If the instance is in a transaction, mark the transaction for rollback. */
146                 Transaction JavaDoc tx = null;
147                 try{
148                     tx = getTxMngr().getTransaction();
149                 } catch (Throwable JavaDoc t){
150                     logger.error("Could not retreive the current transaction from the transaction manager while handling a callback exception from the beforeCompletion method of bean "+callContext.getPrimaryKey());
151                 }
152                 try{
153                     markTxRollbackOnly( tx );
154                 } catch (Throwable JavaDoc t){
155                     logger.error("Could not mark the current transaction for rollback while handling a callback exception from the beforeCompletion method of bean "+callContext.getPrimaryKey());
156                 }
157
158                 /* [3] Discard the instance */
159                 discardInstance( instanceManager, callContext );
160             
161                 /* [4] throw the java.rmi.RemoteException to the client */
162                 throw new RuntimeException JavaDoc( message );
163             } finally {
164                 ThreadContext.setThreadContext( originalContext );
165             }
166         }
167     }
168     
169     /**
170      * This method is called by the transaction
171      * manager after the transaction is committed or rolled back.
172      *
173      * @param status The status of the transaction completion.
174      */

175     public void afterCompletion(int status) {
176         
177         ThreadContext originalContext = ThreadContext.getThreadContext();
178         
179         Object JavaDoc[] contexts = sessionSynchronizations.values().toArray();
180
181         try{
182             Transaction JavaDoc tx = getTxMngr().getTransaction();
183             coordinators.remove( tx );
184         }catch(Exception JavaDoc e) {
185             logger.error("", e);
186         }
187         for(int i = 0; i < contexts.length; i++){
188
189             // Have to reassocaite the original thread context with the thread before invoking
190
ThreadContext callContext = (ThreadContext)contexts[i];
191             
192             ThreadContext.setThreadContext(callContext);
193             StatefulInstanceManager instanceManager = null;
194             
195             try{
196                 StatefulContainer container = (StatefulContainer)callContext.getDeploymentInfo().getContainer();
197                 instanceManager = container.getInstanceManager();
198                 /*
199                 * the operation must be set before the instance is obtained from the pool, so
200                 * that the instance manager doesn't mistake this as a concurrent access.
201                 */

202                 callContext.setCurrentOperation(Operations.OP_AFTER_COMPLETION);
203                 
204                 SessionSynchronization JavaDoc bean = (SessionSynchronization JavaDoc)instanceManager.obtainInstance(callContext.getPrimaryKey(), callContext);
205                 
206                 bean.afterCompletion( status == Status.STATUS_COMMITTED );
207                 instanceManager.poolInstance(callContext.getPrimaryKey(), (EnterpriseBean JavaDoc)bean);
208             }catch(org.openejb.InvalidateReferenceException inv) {
209                 // the bean doesn't exist anymore, e.g. a system exception occured
210
// and the bean has been discarded. No container callbacks
211
// are allowed at this point
212
// therefore we simply do nothing() here....
213
}catch(Exception JavaDoc e){
214                 // EJB 2.0: 18.3.3 Exceptions from container-invoked callbacks
215
String JavaDoc message = "An unexpected system exception occured while invoking the afterCompletion method on the SessionSynchronization object: "+e.getClass().getName()+" "+e.getMessage();
216                 
217                 /* [1] Log the exception or error */
218                 logger.error( message, e);
219                 
220                 /* [2] If the instance is in a transaction, mark the transaction for rollback. */
221                 Transaction JavaDoc tx = null;
222                 try{
223                     tx = getTxMngr().getTransaction();
224                 } catch (Throwable JavaDoc t){
225                     logger.error("Could not retreive the current transaction from the transaction manager while handling a callback exception from the afterCompletion method of bean "+callContext.getPrimaryKey());
226                 }
227                 try{
228                     markTxRollbackOnly( tx );
229                 } catch (Throwable JavaDoc t){
230                     logger.error("Could not mark the current transaction for rollback while handling a callback exception from the afterCompletion method of bean "+callContext.getPrimaryKey());
231                 }
232
233                 /* [3] Discard the instance */
234                 discardInstance( instanceManager, callContext );
235             
236                 /* [4] throw the java.rmi.RemoteException to the client */
237                 // this will be caught in TransactionManagerWrapper
238
throw new RuntimeException JavaDoc( message );
239             } finally {
240                 ThreadContext.setThreadContext( originalContext );
241             }
242         }
243     }
244
245     protected void discardInstance(StatefulInstanceManager instanceManager, ThreadContext callContext){
246         try{
247             instanceManager.freeInstance( callContext.getPrimaryKey() );
248         }catch(org.openejb.OpenEJBException oee){
249             // stateful session interface doesn't throw an exception
250
}
251     }
252     
253     protected void markTxRollbackOnly( Transaction JavaDoc tx ) throws SystemException{
254         try {
255             if ( tx != null ) tx.setRollbackOnly();
256         } catch ( javax.transaction.SystemException JavaDoc se ) {
257             throw new org.openejb.SystemException(se);
258         }
259     }
260
261     protected TransactionManager JavaDoc getTxMngr( ) {
262         return OpenEJB.getTransactionManager();
263     }
264     
265     /**
266      * Throw RemoteException to remote client; throw EJBException to local client.
267      *
268      * @param sysException
269      * @exception ApplicationException
270      */

271     protected void throwExceptionToServer( Throwable JavaDoc sysException ) throws ApplicationException{
272         // Throw RemoteException to remote client.
273

274         // See section 2.1.3.7 of the OpenEJB Specification
275
throw new ApplicationException( sysException );
276
277         // TODO:3: throw EJBException to local client.
278

279     }
280 }
281
Popular Tags