KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jts > CosTransactions > CurrentTransaction


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * Copyright 2004-2005 Sun Microsystems, Inc. All rights reserved.
26  * Use is subject to license terms.
27  */

28 //----------------------------------------------------------------------------
29
//
30
// Module: CurrentTransaction.java
31
//
32
// Description: Transaction to thread association management.
33
//
34
// Product: com.sun.jts.CosTransactions
35
//
36
// Author: Simon Holdsworth
37
//
38
// Date: March, 1997
39
//
40
// Copyright (c): 1995-1997 IBM Corp.
41
//
42
// The source code for this program is not published or otherwise divested
43
// of its trade secrets, irrespective of what has been deposited with the
44
// U.S. Copyright Office.
45
//
46
// This software contains confidential and proprietary information of
47
// IBM Corp.
48
//----------------------------------------------------------------------------
49

50 package com.sun.jts.CosTransactions;
51
52 // Import required classes.
53

54 import java.util.*;
55
56 import org.omg.CORBA.*;
57 import org.omg.CosTransactions.*;
58
59 import com.sun.jts.otsidl.*;
60 import com.sun.jts.trace.*;
61 import java.util.logging.Logger JavaDoc;
62 import java.util.logging.Level JavaDoc;
63 import com.sun.logging.LogDomains;
64 import com.sun.jts.utils.LogFormatter;
65
66 /**This class manages association of transactions with threads in a process,
67  * and associated state/operations.
68  *
69  * @version 0.01
70  *
71  * @author Simon Holdsworth, IBM Corporation
72  *
73  * @see
74 */

75 //----------------------------------------------------------------------------
76
// CHANGE HISTORY
77
//
78
// Version By Change Description
79
// 0.01 SAJH Initial implementation.
80
//-----------------------------------------------------------------------------
81

82 public class CurrentTransaction {
83     private static Hashtable threadContexts = new Hashtable(Configuration.EXPECTED_CONCURRENT_THREADS);
84     private static Vector suspended = new Vector(Configuration.EXPECTED_CONCURRENT_TRANSACTIONS);
85
86     //store the suspended and associated transactions support only if stats are required
87
static boolean statsOn=false;
88
89     private static Hashtable importedTransactions = new Hashtable();
90     private static RegisteredStatics statics = null;
91     //private static ORB orb = null;
92
//private static TransactionFactory localFactory = null;
93

94     // Static arrays for output parameters.
95

96     private static ThreadLocal JavaDoc m_tid=new ThreadLocal JavaDoc();
97     //private static boolean[] outBoolean = new boolean[1];
98
//private static int[] outInt = new int[1];
99
//private static StatusHolder outStatus = new StatusHolder();
100

101     //$ This constant is used to represent the empty transaction context. It
102
//$ should not be required when the TRANSACTION_REQUIRED exception is
103
//$ supported.
104
/*
105         Logger to log transaction messages
106     */

107     static Logger JavaDoc _logger = LogDomains.getLogger(LogDomains.TRANSACTION_LOGGER);
108    
109     private static PropagationContext emptyContext =
110         new PropagationContext(0,new TransIdentity(null,null,new otid_t(-1,0,new byte[0])),
111                                new TransIdentity[0],null);
112
113     /**Initialises the static state of the CurrentTransaction class.
114      *
115      * @param
116      *
117      * @return
118      *
119      * @see
120      */

121     static void initialise() {
122
123         // Initialise the static state for the class.
124

125     }
126
127     /**Sets up the thread association for a Control object.
128      * <p>
129      * If the thread association already exists for the thread under which the
130      * operation was invoked and the stacking flag is set, the existing Control
131      * is stacked behind the given one, which is made the current one.
132      * <p>
133      * If the association already exists and the stacking flag is not set, no
134      * association is changed and the operation returns false.
135      * <p>
136      * For XA support, when an association is started or ended, all
137      * registered StaticResource objects are informed of the association change.
138      *
139      * @param control The Control object to be made the current one.
140      * @param stack Indicates whether the current Control should be stacked.
141      *
142      * @return Indicates success of the operation.
143      *
144      * @see
145      */

146     static boolean setCurrent( ControlImpl control,
147                                             boolean stack ) {
148
149         boolean result = false;
150
151         // Ensure that the current thread association is valid.
152
//boolean[] outBoolean = new boolean[1];
153

154         ControlImpl current = (ControlImpl)m_tid.get();
155         /*if( outBoolean[0] ) {
156         }*/

157
158         // If there is a current Control object, and we have not been asked to stack
159
// it, return FALSE to indicate that we cannot replace it.
160
// Otherwise stack the current Control object behind the new one, which
161
// becomes the current Control for the thread.
162

163         if( current != null ) {
164             if( stack ) {
165
166                 // XA support: If the remove operation was successful, inform all registered
167
// StaticResource objects of the end of the thread association.
168
// Allow any exception to percolate to the caller.
169
// This is done first so that if there is an error, we don't leave the
170
// transaction associated.
171

172                 if( statics != null )
173                     statics.distributeEnd(current,false);
174
175                 // Push the given Control object onto the current one, and remove the
176
// current association.
177

178                 StatusHolder outStatus = new StatusHolder();
179                 control.pushControl(current,outStatus);
180         if(statsOn){
181                 Thread JavaDoc thread = Thread.currentThread();
182                     result = (threadContexts.remove(thread) != null);
183         }
184         else
185             result=true;
186             m_tid.set(null);
187
188                 // The parent transaction has effectively been suspended - add it to the
189
// set of suspended transactions.
190

191         if(statsOn)
192                     suspended.addElement(current);
193             }
194         } else
195             result = true;
196
197 // If there is no current Control, then just make the new one current.
198

199         if( result ) {
200
201             // XA support: If the set_current operation was successful, inform all
202
// registered StaticResource objects of the new thread association.
203
// Allow any exception to percolate to the caller.
204
// This is done first so that if there is an error, we don't leave the
205
// transaction associated.
206

207             if( statics != null )
208                 statics.distributeStart(control,stack);
209
210             // Update the thread to Control mapping for the new Control.
211

212         if(statsOn){
213             Thread JavaDoc thread = Thread.currentThread();
214                 threadContexts.put(thread,control);
215         }
216         m_tid.set(control);
217
218             // Remove the Control from the set of suspended Control objects.
219

220         if(statsOn)
221                 suspended.removeElement(control);
222
223             // Increment the association count for the control object
224

225             control.incrementAssociation();
226         }
227
228         return result;
229     }
230
231     /**Removes the association for the thread under which the operation was
232      * invoked.
233      * <p>
234      * The (previously) associated Control object is returned.
235      * <p>
236      * If there was no association, the operation returns a NULL reference.
237      * <p>
238      * If the stacking flag is set, and there is an associated Control, the stacked
239      * context (if any) becomes the current context when the operation completes.
240      * <p>
241      * For XA support, when an association is started or ended, all
242      * registered StaticResource objects are informed of the change.
243      *
244      * @param unstack Indicates whether the stacked Control object should be made
245      * the current one.
246      *
247      * @return The current Control object.
248      *
249      * @see
250      */

251     static ControlImpl endCurrent( boolean unstack ) {
252
253         // Ensure that the current thread association is valid.
254

255         //boolean[] outBoolean = new boolean[1];
256
ControlImpl result = (ControlImpl)m_tid.get();
257         /*if( outBoolean[0] ) {
258         }*/

259
260         // If there is a current Control, remove its association. If we were asked
261
// to unstack, get the stacked Control, if any. If there is one, set up the
262
// thread association.
263

264         if( result != null ){
265         if(statsOn){
266             Thread JavaDoc thread = Thread.currentThread();
267                 threadContexts.remove(thread);
268         }
269         m_tid.set(null);
270
271             // Decrement the count of associations for the Control object.
272

273             result.decrementAssociation();
274
275             // Add the Control to the set of suspended Control objects, if this is
276
// a suspend and not an end.
277

278             if( !unstack && statsOn) suspended.addElement(result);
279
280                 // XA support: If there was a current Control, inform all registered
281
// StaticResource objects of the end of the thread association.
282
// Allow any exception to percolate to the caller.
283

284             if( statics != null )
285                 statics.distributeEnd(result,unstack);
286
287                 // If we were asked to unstack, get the stacked Control, if any. If there
288
// is one, set up the thread association.
289
// Now that we have identified the first active ancestor, proceed to unstack
290
// its parent.
291

292             if( unstack ) {
293                 StatusHolder outStatus = new StatusHolder();
294                 ControlImpl stacked = result.popControl(outStatus);
295                 if( stacked != null &&
296                     outStatus.value == Status.StatusActive ) {
297
298                     // XA support: If there is a stacked context, inform all registered
299
// StaticResource objects of the new thread association.
300
// Allow any exception to percolate to the caller.
301
// This is done first so that if there is an error, we don't leave the
302
// transaction associated.
303

304                     if( statics != null )
305                         statics.distributeStart(stacked,false);
306
307                     // The stacked Control is no longer suspended so is removed from the
308
// set of suspended transactions.
309

310             if(statsOn){
311                 Thread JavaDoc thread = Thread.currentThread();
312                         threadContexts.put(thread,stacked);
313                         suspended.removeElement(stacked);
314             }
315             m_tid.set(stacked);
316                 }
317             }
318         }
319
320         // If there is no current Control, just return NULL.
321

322         else
323             result = null;
324
325         return result;
326     }
327
328     // COMMENT (Ram J) 12/18/2000
329
// This is being accessed from OTS interceptors package to
330
// check to see if there is a current transaction or not.
331
public static boolean isTxAssociated() {
332         //Thread thread = Thread.currentThread();
333
//ControlImpl result = (ControlImpl) threadContexts.get(thread);
334
//return (result != null);
335
return (m_tid.get()!=null);
336     }
337
338     private static ControlImpl endAborted() {
339         return (ControlImpl)m_tid.get();
340         //return endAborted(aborted, false);
341
}
342
343     /**Ensures that an association with an aborted transaction is dealt with cleanly.
344      *
345      *
346      * TN - do not dissociate thread even if it's aborted!!
347      *
348      * If the current Control object represents a transaction that has been
349      * aborted, this method replaces the association by one with the first
350      * ancestor that has not been aborted, if any, or no association, and the
351      * method returns true as the output parameter. Otherwise the method returns
352      * false as the output parameter.
353      * <p>
354      * If there is a current Control object in either case it is returned,
355      * otherwise null is returned.
356      *
357      * @param aborted A 1-element array which will hold the aborted indicator.
358      *
359      * @return The current Control object.
360      *
361      * @see
362      */

363     private static ControlImpl
364         endAborted( boolean[/*1*/] aborted, boolean endAssociation) {
365
366         // Get the current thread identifier, and the corresponding Control object
367
// if there is one.
368

369         boolean completed = true;
370         aborted[0] = false;
371
372         ControlImpl result = (ControlImpl)m_tid.get();
373
374         // If there is a current Control object, and it represents a transaction that
375
// has been aborted, then we need to end its association with the current
376
// thread of control.
377

378         if( result != null )
379             try {
380                 completed = (result.getTranState() != Status.StatusActive);
381             } catch( Throwable JavaDoc exc ) {}
382
383         if( result != null && completed ) {
384             if (endAssociation) {
385             synchronized(CurrentTransaction.class){
386             if(statsOn){
387                     Thread JavaDoc thread = Thread.currentThread();
388                         threadContexts.remove(thread);
389             }
390             m_tid.set(null);
391
392                     // XA support: If there was a current IControl, inform all registered
393
// StaticResource objects of the end of the thread association.
394
// Allow any exception to percolate to the caller.
395

396                     if( statics != null )
397                             statics.distributeEnd(result,false);
398
399                     // Discard all stacked controls that represent aborted or unrecognised
400
// transactions.
401

402                     result = result.popAborted();
403
404                     // If there is a valid ancestor, make it the current one.
405

406                     if( result != null ) {
407                 m_tid.set(result);
408                 if(statsOn){
409                         Thread JavaDoc thread = Thread.currentThread();
410                                 threadContexts.put(thread,result);
411                                 suspended.removeElement(result);
412                 }
413                     }
414
415                     // XA support: If there is a stacked context, inform all registered
416
// StaticResource objects of the new thread association.
417
// Allow any exception to percolate to the caller.
418

419                     if( statics != null )
420                             statics.distributeStart(result,false);
421         }
422             }
423             aborted[0] = true;
424         }
425
426         if(_logger.isLoggable(Level.FINEST))
427         {
428             Thread JavaDoc thread = Thread.currentThread();
429             _logger.logp(Level.FINEST,"CurrentTransaction","endAborted()",
430                     "threadContexts.get(thread) returned " +
431                     result + " for current thread " + thread);
432         }
433
434         return result;
435     }
436
437     /**Adds the given Control object to the set of Control objects suspended in
438      * the process.
439      *
440      * @param control The Control object which has been suspended.
441      *
442      * @return
443      *
444      * @see
445      */

446     static void addSuspended( ControlImpl control ) {
447         if(statsOn)
448             suspended.addElement(control);
449     }
450
451     /**Removes the given Control object from the set of those suspended in the
452      * process. The operation returns FALSE if the Control object has not been
453      * suspended.
454      *
455      * @param control The Control object which has been resumed/destroyed.
456      *
457      * @return Indicates success of the operation.
458      *
459      * @see
460      */

461     static boolean removeSuspended( ControlImpl control ) {
462         boolean result = true;
463     if(statsOn)
464         result=suspended.removeElement(control);
465         return result;
466     }
467
468     /**Returns the current Control object.
469      * <p>
470      * That is, the Control object that corresponds to the thread
471      * under which the operation was invoked. If there is no such association the
472      * null value is returned.
473      *
474      * @param
475      *
476      * @return The current Control object.
477      *
478      *
479      * @see
480      */

481     public static ControlImpl getCurrent()
482         throws TRANSACTION_ROLLEDBACK {
483
484         //boolean[] outBoolean = new boolean[1];
485
ControlImpl result = (ControlImpl)m_tid.get();
486
487         return result;
488     }
489
490     /**Returns a reference to the current Coordinator.
491      * <p>
492      * That is, the Coordinator object that corresponds to the
493      * thread under which the operation was invoked.
494      * If there is no such association the null value is returned.
495      * <p>
496      * Note that this operation can be optimised so that the Coordinator reference is
497      * stored along with the Control reference when the thread association is set up.
498      *
499      * @param
500      *
501      * @return The current Coordinator.
502      *
503      * @exception TRANSACTION_ROLLEDBACK The Coordinator has already been rolled
504      * back.
505      * @exception Unavailable The Coordinator object is not available.
506      *
507      * @see
508      */

509     static Coordinator getCurrentCoordinator()
510         throws TRANSACTION_ROLLEDBACK, Unavailable {
511
512         /* This method has been rewritten (Ram J)
513          * in order to enable current.get_status() to be called
514          * on a completed transaction, and get the completed status.
515          * Previously, the first call to get_status() will return
516          * the right completion status, and the second call to get_status
517          * would return StatusNoTransaction, since the first call would end
518          * the thread - tx association.
519          */

520
521         // Get the current thread identifier, and the corresponding
522
// Control object if there is one.
523

524         ControlImpl control = (ControlImpl)m_tid.get();
525         Coordinator result = null;
526
527         if (control != null) {
528
529           if( Configuration.isLocalFactory()) {
530             result = (Coordinator) ((ControlImpl) control).get_localCoordinator();
531           } else {
532             // this call may throw TRANSACTION_ROLLEDBACK
533
// or INVALID_TRANSACTION
534
result = control.get_coordinator();
535           }
536         }
537
538         return result;
539
540     }
541
542     /**Returns the number of thread associations currently active for the given
543      * transaction identifier.
544      * <p>
545      * A boolean value indicating whether there are outstanding requests is returned
546      * as an output parameter.
547      *
548      * @param localTID The local transaction identifier.
549      * @param outstanding A 1-element array which will indicate outstanding requests.
550      *
551      * @return The number of active thread associations.
552      *
553      * @see
554      */

555     static int numActive( Long JavaDoc localTID,
556                                        boolean[/*1*/] outstanding ) {
557     if(!statsOn){
558         throw new NO_IMPLEMENT("statistics not on");
559     }
560
561         int result = 0;
562         outstanding[0] = false;
563         StatusHolder outStatus = new StatusHolder();
564
565         // First check whether there are any outstanding requests.
566
// Count all of the Control objects that have the same local TID as that given.
567

568         Enumeration controls = threadContexts.elements();
569         while( controls.hasMoreElements() ) {
570             ControlImpl current = (ControlImpl)controls.nextElement();
571
572             // If the Control object represents a transaction that has been completed,
573
// don't count it.
574

575             outStatus.value = Status.StatusRolledBack;
576             try {
577                 Long JavaDoc currentLocalTID = new Long JavaDoc(current.getLocalTID(outStatus));
578                 if( outStatus.value == Status.StatusActive )
579                     if( currentLocalTID.equals(localTID) ) {
580                         outstanding[0] |= current.isOutgoing();
581                         result++;
582                     }
583             } catch( Throwable JavaDoc exc ) {
584             }
585         }
586
587         return result;
588     }
589
590     /**Registers the given StaticResource object.
591      * <p>
592      * The StaticResource object will be informed whenever any association of
593      * a transaction with a thread is started or ended.
594      *
595      * @param obj The StaticResource being registered.
596      *
597      * @return
598      *
599      * @see
600      */

601     synchronized static void registerStatic( StaticResource obj ) {
602
603         // If the RegisteredStatics instance variable has not been created at this
604
// point, create it.
605

606         if( statics == null )
607             statics = new RegisteredStatics();
608
609         // Attempt to add the StaticResource reference to those already registered.
610

611         statics.addStatic(obj);
612     }
613
614     /**Returns all the transactions in the system that are currently suspended
615      * in the form of a sequence of Control objects.
616      *
617      * @param
618      *
619      * @return The list of suspended Control objects.
620      *
621      * @see
622      */

623     static Control[] getSuspendedTransactions() {
624
625     if(!statsOn){
626         throw new NO_IMPLEMENT("statistics not on");
627     }
628
629         Control[] result = null;
630
631         // Copy the contents of the suspended set into the array.
632

633         int suspNum = suspended != null ? suspended.size() : 0;
634         if( suspNum > 0 ) {
635             result = new Control[suspNum];
636
637             Enumeration controls = suspended.elements();
638             int pos = 0;
639             while( controls.hasMoreElements() )
640                 result[pos++] = ((ControlImpl)controls.nextElement()).object();
641         }
642         else
643             result = new Control[0];
644
645         return result;
646     }
647
648     /**Returns all the transactions in the system that are currently running
649      * (i.e. not suspended) in the form of a sequence of Control objects.
650      *
651      * @param
652      *
653      * @return The list of running Control objects.
654      *
655      * @see
656      */

657     static Control[] getRunningTransactions() {
658     if(!statsOn){
659         throw new NO_IMPLEMENT("statistics not on");
660     }
661
662         Control[] result = null;
663
664         // Copy the Control objects which have thread associations into the result.
665

666         int runNum = threadContexts != null ? threadContexts.size() : 0;
667         if( runNum > 0 ) {
668             result = new Control[runNum];
669
670             Enumeration controls = threadContexts.elements();
671             int pos = 0;
672             while( controls.hasMoreElements() )
673                 result[pos++] = ((ControlImpl)controls.nextElement()).object();
674         }
675         else
676             result = new Control[0];
677
678         return result;
679     }
680
681     /**Returns all the transactions in the system that are currently running
682      * or suspended in the form of a sequence of Control objects.
683      *
684      * @param
685      *
686      * @return The list of all Control objects.
687      *
688      * @see
689      */

690     static Control[] getAllTransactions() {
691
692     if(!statsOn){
693         throw new NO_IMPLEMENT("statistics not on");
694     }
695         Control[] result = null;
696
697         int allNum = threadContexts != null ? threadContexts.size()+suspended.size() : 0;
698         if( allNum > 0 ) {
699             result = new Control[allNum];
700
701             // Copy the contents of the suspended set into the array.
702

703             Enumeration controls = suspended.elements();
704             int pos = 0;
705             while( controls.hasMoreElements() )
706                 result[pos++] = ((ControlImpl)controls.nextElement()).object();
707
708             // Copy the Control objects which have thread associations into the result.
709

710             controls = threadContexts.elements();
711             while( controls.hasMoreElements() )
712                 result[pos++] = ((ControlImpl)controls.nextElement()).object();
713         }
714         else
715             result = new Control[0];
716
717         return result;
718     }
719
720     /**Informs the CurrentTransaction that a request is being sent.
721      * <p>
722      * Returns the transaction context that should be established for the object in
723      * the remote process.
724      *
725      * @param id The request identifier.
726      * @param holder The completed context object.
727      *
728      * @return
729      *
730      * @exception TRANSACTION_ROLLEDBACK The current transaction has been rolled
731      * back. The message should not be sent and TRANSACTION_ROLLEDBACK should
732      * be returned to the caller.
733      * @exception TRANSACTION_REQUIRED There is no current transaction.
734      *
735      * @see
736      */

737     static void sendingRequest( int id,
738                                              PropagationContextHolder holder )
739         throws TRANSACTION_ROLLEDBACK, TRANSACTION_REQUIRED {
740
741         // Empty out the context.
742
// Ensure that the cached reference to the ORB is set up, and that the Any
743
// value in the context is initialised.
744
//$ The following is necessary for the context to be marshallable. It is a
745
//$ waste of time when there is no transaction, in which case we should be
746
//$ throwing the TRANSACTION_REQUIRED exception.
747

748         // COMMENT(Ram J) 11/19/2000 This is taken care of by the PI OTS
749
// interceptors, so this has been commented out. If no current
750
// transaction is available simply return. The PI OTS interceptor will
751
// either raise a TRANSACTION_REQUIRED exception if the target policy
752
// requires a transaction, else it will not provide a tx context.
753
/*
754         if( emptyContext.implementation_specific_data == null ) {
755             if( orb == null )
756                 orb = Configuration.getORB();
757             emptyContext.implementation_specific_data = orb.create_any();
758             emptyContext.implementation_specific_data.insert_boolean(false);
759         }
760         holder.value = emptyContext;
761         */

762
763         // Ensure that the current Control object is valid. Return immediately if
764
// not.
765

766         boolean[] outBoolean = new boolean[1];
767         ControlImpl current = endAborted(outBoolean, false);
768         if( outBoolean[0] ) {
769             TRANSACTION_ROLLEDBACK exc = new TRANSACTION_ROLLEDBACK(0,CompletionStatus.COMPLETED_NO);
770             throw exc;
771         }
772
773         // Throw the TRANSACTION_REQUIRED exception if there is no current transaction.
774

775         if( current == null ) {
776             //$ TRANSACTION_REQUIRED exc = new TRANSACTION_REQUIRED();
777
//$ if( trc != null ) trc.event(EVT_THROW).data(exc).write();
778
//$ throw exc;
779
return;
780         }
781
782         // Get the the context from the Control object.
783
// If the context is not available, then indicate that there is no transaction.
784

785         try {
786             holder.value = current.getTXContext();
787         }
788
789         // If the Coordinator is inactive, throw the INVALID_TRANSACTION exception,
790
// as this will be because the transaction is not able to do transactional
791
// work.
792

793         catch (Unavailable exc) {
794             INVALID_TRANSACTION ex2 = new INVALID_TRANSACTION(0,CompletionStatus.COMPLETED_NO);
795             throw ex2;
796         }
797
798         // If the Coordinator has rolled back, allow the TRANSACTION_ROLLEDBACK exception,
799
// to pass to the caller.
800

801         catch( TRANSACTION_ROLLEDBACK exc ) {
802             endCurrent(true);
803             current.destroy();
804             throw (TRANSACTION_ROLLEDBACK)exc.fillInStackTrace();
805         }
806
807         // Any other exception is unexpected. Assume there is no transaction.
808

809         catch( Throwable JavaDoc exc ) {
810         }
811
812         // Increase the count of outgoing requests for this transaction, if the
813
// Control object is not a proxy.
814

815         // COMMENT(Ram J) 11/25/2000 With the PI based OTS 1.2 implementation,
816
// exception replies | location forwarded responses may not carry back
817
// a tx svc context (since the server OTS interceptor send point may
818
// not have been called. In such a case, it is impossible to enforce
819
// checked behaviour. The next revision of OTS 1.2 should address this,
820
// and provide a solution to the checked behaviour in a PI based OTS
821
// implementation. Then, these checks shall be enabled.
822
//current.incrementOutgoing();
823
}
824
825     /**Informs the CurrentTransaction that a reply has been received.
826      *
827      * @param id The request identifier.
828      * @param context The PropagationContext from the message.
829      * @param ex The exception on the message.
830      *
831      * @return
832      *
833      * @exception WrongTransaction The context returned on the reply is for a
834      * different transaction from the current one on the thread.
835      *
836      * @see
837      */

838     static void receivedReply( int id,
839                                             PropagationContext context,
840                                             org.omg.CORBA.Environment JavaDoc ex )
841         throws org.omg.CORBA.WrongTransaction JavaDoc {
842
843         // Look up the current Control object.
844

845         //Thread thread = Thread.currentThread();
846
ControlImpl current = (ControlImpl)m_tid.get();
847
848         // If there is no current transaction, or an exception was raised, then just
849
// return.
850

851         if( current == null ) {
852             return;
853         }
854
855         //$ If there is an active exception, report it.
856

857         // OMG OTS issue 1819, if there is a system exception mark the
858
// transaction for rollback
859
java.lang.Exception JavaDoc ctxExc = ex.exception();
860         if (ctxExc instanceof SystemException) {
861
862             Coordinator currentCoord = null;
863             try {
864                 if (Configuration.isLocalFactory()) {
865                     currentCoord = current.get_localCoordinator();
866                 } else {
867                     currentCoord = current.get_coordinator();
868                 }
869             } catch (Unavailable exc) {}
870
871             if (currentCoord == null) {
872                 return; // no coord, cannot mark tx for rollback
873
}
874
875             try {
876                 currentCoord.rollback_only();
877             } catch (Inactive exc) {}
878
879             // COMMENT (Ram J) (11/24/2000) This has been commented out since
880
// the exception reply could have a tx context. Do further checks.
881
//return;
882
}
883
884         // Return if there is no context on the message.
885

886         if( context == null ||
887             context.current == null ||
888             context.current.coord == null ||
889             context.current.otid.formatID == -1 ) {
890             return;
891         }
892
893         // Get the global id from the current context. If the transaction is not
894
// active, then end the current association.
895

896         StatusHolder outStatus = new StatusHolder();
897         outStatus.value = Status.StatusRolledBack;
898         GlobalTID globalTID = null;
899         try {
900             globalTID = new GlobalTID(current.getGlobalTID(outStatus));
901         } catch( Throwable JavaDoc exc ) {
902         }
903
904         // If the global identifier is NULL, then the Control object is unable to provide
905
// us with checking behaviour. We do not check in this case.
906

907         if( globalTID != null ) {
908             if( outStatus.value != Status.StatusActive ) {
909                 endCurrent(true);
910                 current.destroy();
911
912                 // org.omg.CORBA.WrongTransaction exc = new org.omg.CORBA.WrongTransaction(0,CompletionStatus.COMPLETED_YES);
913
org.omg.CORBA.WrongTransaction JavaDoc exc = new org.omg.CORBA.WrongTransaction JavaDoc();
914                 throw exc;
915             }
916
917             // If the global id is different from the one in the context, then raise the
918
// org.omg.CORBA.WrongTransaction exception.
919

920             if( !globalTID.equals(context.current.otid) ) {
921                 // org.omg.CORBA.WrongTransaction exc = new org.omg.CORBA.WrongTransaction(0,CompletionStatus.COMPLETED_YES);
922
org.omg.CORBA.WrongTransaction JavaDoc exc = new org.omg.CORBA.WrongTransaction JavaDoc();
923                 throw exc;
924             }
925         }
926
927         // If the Control object is not a proxy, then decrement the outgoing count.
928

929         // COMMENT(Ram J) 11/25/2000 With the PI based OTS 1.2 implementation,
930
// exception replies | location forwarded responses may not carry back
931
// a tx svc context (since the server OTS interceptor send point may
932
// not have been called. In such a case, it is impossible to enforce
933
// checked behaviour. The next revision of OTS 1.2 should address this,
934
// and provide a solution to the checked behaviour in a PI based OTS
935
// implementation. Then, these checks shall be enabled.
936
//current.decrementOutgoing();
937
}
938
939     /**Informs the CurrentTransaction that a request has been received.
940      * <p>
941      * The request contains the transaction context that should be established
942      * for the object.
943      *
944      * @param id The request identifier.
945      * @param context The PropagationContext from the message.
946      *
947      * @return
948      *
949      * @see
950      */

951     static void receivedRequest( int id,
952                                               PropagationContext context ) {
953
954         // Return if there is no context on the message.
955
// If the transaction identifier in the context is NULL, just return.
956

957         if( context == null ||
958             context.current == null ||
959             context.current.otid.formatID == -1 ) {
960             return;
961         }
962
963         // Use a local factory to recreate the transaction locally.
964

965         //if( localFactory == null )
966
//localFactory = Configuration.getFactory();
967
//Control current = localFactory.recreate(context);
968
Control current = Configuration.getFactory().recreate(context);
969
970         // Record the imported transaction.
971

972         importedTransactions.put(Thread.currentThread(),new GlobalTID(context.current.otid));
973
974         // Create a new Control and associate it with the thread
975

976         try {
977             ControlImpl contImpl = null;
978             if (Configuration.isLocalFactory()) {
979                 contImpl = (ControlImpl) current;
980             } else {
981                 contImpl = ControlImpl.servant(JControlHelper.narrow(current));
982             }
983             setCurrent(contImpl,false);
984         }
985
986         // If any exception was thrown during that lot, then we have failed to
987
// create a subordinate. Do something drastic.
988

989         catch( Throwable JavaDoc exc ) {
990             _logger.log(Level.WARNING,"jts.unable_to_create_subordinate_coordinator");
991              String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
992                                         "jts.unable_to_create_subordinate_coordinator");
993               throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
994         }
995     }
996
997     /**Informs the object's Coordinator that a reply is being sent to the client.
998      *
999      * @param id The request identifier.
1000     * @param holder The context to be returned on the reply.
1001     *
1002     * @exception INVALID_TRANSACTION The current transaction has outstanding work
1003     * on this reply, and has been marked rollback-only, or the reply is returning
1004     * when a different transaction is active from the one active when the request
1005     * was imported.
1006     * @exception TRANSACTION_ROLLEDBACK The current transaction has already been
1007     * rolled back.
1008     *
1009     * @see
1010     */

1011    static void sendingReply( int id,
1012                                           PropagationContextHolder holder )
1013        throws INVALID_TRANSACTION, TRANSACTION_ROLLEDBACK {
1014
1015        // Zero out context information.
1016
// Ensure that the cached reference to the ORB is set up, and that the Any
1017
// value in the context is initialised.
1018
//$ The following is necessary for the context to be marshallable. It is a
1019
//$ waste of time when there is no transaction, in which case we should be
1020
//$ throwing the TRANSACTION_REQUIRED exception (?).
1021

1022        if( emptyContext.implementation_specific_data == null ) {
1023            ORB orb = Configuration.getORB();
1024            emptyContext.implementation_specific_data = orb.create_any();
1025            emptyContext.implementation_specific_data.insert_boolean(false);
1026        }
1027
1028        // COMMENT(Ram J) There is no need to send an empty context, if a tx
1029
// is not available. The PI based OTS hooks will not send a tx context
1030
// in the reply.
1031
/*
1032        holder.value = emptyContext;
1033        */

1034
1035        // Ensure that the current Control object is valid. Return immediately if not.
1036

1037        boolean[] outBoolean = new boolean[1];
1038        ControlImpl current = endAborted(outBoolean, true); // end association
1039
if( outBoolean[0] ) {
1040            importedTransactions.remove(Thread.currentThread());
1041            TRANSACTION_ROLLEDBACK exc = new TRANSACTION_ROLLEDBACK(0,CompletionStatus.COMPLETED_YES);
1042            throw exc;
1043        }
1044
1045        // Get the global identifier of the transaction that was imported into this
1046
// thread. If there is none, that is an error.
1047

1048        Thread JavaDoc thread = Thread.currentThread();
1049        GlobalTID importedTID = (GlobalTID)importedTransactions.remove(thread);
1050
1051        // If there is no import information, and no current transaction, then return
1052
// the empty context.
1053

1054        if( importedTID == null && current == null ) {
1055            return;
1056        }
1057
1058        // Check that the current transaction matches the one that was imported.
1059

1060        StatusHolder outStatus = new StatusHolder();
1061        try {
1062            if( importedTID == null ||
1063                current == null ||
1064                !importedTID.equals(current.getGlobalTID(outStatus)) ||
1065                outStatus.value != Status.StatusActive ) {
1066                INVALID_TRANSACTION exc = new INVALID_TRANSACTION(MinorCode.WrongContextOnReply,CompletionStatus.COMPLETED_YES);
1067                throw exc;
1068            }
1069        } catch( SystemException ex ) {
1070            INVALID_TRANSACTION exc = new INVALID_TRANSACTION(MinorCode.WrongContextOnReply,CompletionStatus.COMPLETED_YES);
1071            throw exc;
1072        }
1073
1074        //$Get the Coordinator reference.
1075

1076        CoordinatorImpl coord = null;
1077        Coordinator coordRef = null;
1078        try {
1079            if (Configuration.isLocalFactory()) {
1080                coord = (CoordinatorImpl) current.get_localCoordinator();
1081            } else {
1082                coordRef = current.get_coordinator();
1083                coord = CoordinatorImpl.servant(coordRef);
1084            }
1085
1086            // _logger.log(Level.FINE,"Servant = "+coord);
1087
} catch( Throwable JavaDoc exc ) {
1088        }
1089
1090        // Check the Coordinator before sending the reply.
1091
// We must do this before ending the thread association to allow the
1092
// Coordinator to take advantage of registration on reply if available.
1093
// Note that if the Coordinator returns forgetMe, the global identifier
1094
// will have been destroyed at this point.
1095

1096        CoordinatorImpl forgetParent = null;
1097        int[] outInt = new int[1];
1098        //StatusHolder outStatus = new StatusHolder();
1099
try {
1100            forgetParent = coord.replyAction(outInt);
1101        } catch( Throwable JavaDoc exc ) {
1102        }
1103
1104        int replyAction = outInt[0];
1105        if( replyAction == CoordinatorImpl.activeChildren ) {
1106            try {
1107                coord.rollback_only();
1108            } catch( Throwable JavaDoc ex ) {}
1109
1110            INVALID_TRANSACTION exc = new INVALID_TRANSACTION(MinorCode.UnfinishedSubtransactions,
1111                                                              CompletionStatus.COMPLETED_YES);
1112            throw exc;
1113        }
1114
1115        // End the current thread association.
1116

1117        endCurrent(false);
1118
1119        // If the transaction needs to be cleaned up, do so now.
1120
// We ignore any exception the end_current may have raised in this case.
1121
// The Control object is destroyed before the Coordinator so that it is not
1122
// in the suspended set when the Coordinator is rolled back.
1123

1124        if( replyAction == CoordinatorImpl.forgetMe ) {
1125            current.destroy();
1126            coord.cleanUpEmpty(forgetParent);
1127        }
1128
1129        // Otherwise, we have to check this reply.
1130

1131        else {
1132            if( current.isAssociated() ||
1133                current.isOutgoing() ) {
1134                try {
1135                    coord.rollback_only();
1136                } catch( Throwable JavaDoc exc ) {}
1137
1138                INVALID_TRANSACTION exc = new INVALID_TRANSACTION(MinorCode.DeferredActivities,
1139                                                                  CompletionStatus.COMPLETED_YES);
1140                throw exc;
1141            }
1142
1143            current.destroy();
1144        }
1145
1146        // Create a context with the necessary information.
1147
// All we propagate back is the transaction id and implementation specific data.
1148

1149        holder.value = new PropagationContext(0,new TransIdentity(null,null,importedTID.realTID),
1150                                              new TransIdentity[0],emptyContext.implementation_specific_data);
1151
1152    }
1153
1154    /**
1155     * Recreates a transaction based on the information contained in the
1156     * transaction id (tid) and associates the current thread of control with
1157     * the recreated transaction.
1158     *
1159     * @param tid the transaction id.
1160     */

1161    public static void recreate(GlobalTID tid, int timeout) {
1162        
1163        // check if there is any concurrent activity
1164
if (RecoveryManager.readAndUpdateTxMap(tid) == false) {
1165            throw new INVALID_TRANSACTION(
1166                MinorCode.TX_CONCURRENT_WORK_DISALLOWED,
1167                CompletionStatus.COMPLETED_NO);
1168        }
1169
1170        // recreate the transaction
1171

1172        try {
1173            
1174            // Use a local factory to recreate the transaction locally.
1175
TransactionFactoryImpl factory =
1176                (TransactionFactoryImpl) Configuration.getFactory();
1177            Control current = factory.recreate(tid, timeout);
1178            
1179            // Record the imported transaction.
1180
importedTransactions.put(Thread.currentThread(), tid);
1181
1182            // Create a new Control and associate it with the thread
1183
ControlImpl contImpl = null;
1184            if (Configuration.isLocalFactory()) {
1185                contImpl = (ControlImpl) current;
1186            } else {
1187                contImpl = ControlImpl.servant(JControlHelper.narrow(current));
1188            }
1189            setCurrent(contImpl,false);
1190            
1191        } catch (Throwable JavaDoc exc) {
1192            RecoveryManager.removeFromTxMap(tid); // remove tx id from map
1193
_logger.log(Level.WARNING,"jts.unable_to_create_subordinate_coordinator");
1194             String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
1195                                        "jts.unable_to_create_subordinate_coordinator");
1196            //ErrorLog.error(Messages.SUBORDINATE_CREATE_FAILED, null, true);
1197
throw new INVALID_TRANSACTION(
1198                MinorCode.TX_RECREATE_FAILED, CompletionStatus.COMPLETED_MAYBE);
1199        }
1200    }
1201    
1202    /**
1203     * Disassociates the current thread of control from the specified
1204     * transaction.
1205     *
1206     * @param tid the transaction id.
1207     */

1208    public static void release(GlobalTID tid) {
1209
1210        Thread JavaDoc thread = (Thread JavaDoc) RecoveryManager.getThreadFromTxMap(tid);
1211
1212    if (thread == null || (thread != Thread.currentThread())) {
1213        // the current thread is not in tx, so simply return.
1214
return;
1215        } else {
1216        RecoveryManager.removeFromTxMap(tid);
1217    }
1218        
1219        // Ensure that the current Control object is valid.
1220
boolean[] outBoolean = new boolean[1];
1221        ControlImpl control = endAborted(outBoolean, true); // end association
1222
if (outBoolean[0]) {
1223            importedTransactions.remove(Thread.currentThread());
1224        return; // thread is not associated with tx, simply return
1225
}
1226
1227        // Get the global identifier of the transaction that was imported into
1228
// this thread. If there is none, that is an error.
1229
GlobalTID importedTID = (GlobalTID) importedTransactions.remove(thread);
1230
1231        // Check that the current transaction matches the one that was imported.
1232
StatusHolder outStatus = new StatusHolder();
1233        try {
1234            if (importedTID == null || control == null ||
1235                    !importedTID.equals(control.getGlobalTID(outStatus)) ||
1236                    outStatus.value != Status.StatusActive) {
1237                INVALID_TRANSACTION exc =
1238                    new INVALID_TRANSACTION(MinorCode.WrongContextOnReply,
1239                                            CompletionStatus.COMPLETED_YES);
1240                throw exc;
1241            }
1242        } catch (SystemException ex) {
1243            INVALID_TRANSACTION exc =
1244                new INVALID_TRANSACTION(MinorCode.WrongContextOnReply,
1245                                        CompletionStatus.COMPLETED_YES);
1246            throw exc;
1247        }
1248
1249        // End the current thread association.
1250
endCurrent(false);
1251        control.destroy();
1252    }
1253
1254    /**Ends all thread associations for the given transaction.
1255     *
1256     * @param globalTID The global transaction identifier.
1257     * @param aborted Indicates whether the transaction has aborted.
1258     *
1259     * @return
1260     *
1261     * @see
1262     */

1263    //not used anywhere
1264
synchronized static void endAll( GlobalTID globalTID,
1265                                     boolean aborted ) {
1266    throw new NO_IMPLEMENT("not implemented");
1267        // Modify any thread associations there may be for the transaction, to
1268
// indicate that the transaction has ended.
1269
/*StatusHolder outStatus = new StatusHolder();
1270
1271        Enumeration controls = threadContexts.elements();
1272          int cz = threadContexts.size(); // Arun 9/27/99
1273          while (cz-- > 0) {
1274            ControlImpl control = (ControlImpl)controls.nextElement();
1275
1276            // If the Control object corresponds to the transaction being removed, then
1277            // inform it that the transaction has completed.
1278
1279            try {
1280                if( globalTID.equals(control.getGlobalTID(outStatus)) &&
1281                    outStatus.value == Status.StatusActive )
1282                    control.setTranState(aborted ? Status.StatusRolledBack : Status.StatusCommitted);
1283            } catch( Throwable exc ) {
1284            }
1285        }
1286
1287        // Modify any suspended Control objects there may be for the transaction, to
1288        // indicate that the transaction has ended.
1289
1290        controls = suspended.elements();
1291          cz = suspended.size(); // Arun 9/27/99
1292          while(cz-- > 0) {
1293            try {
1294                ControlImpl control = (ControlImpl)controls.nextElement();
1295
1296                // If the Control object corresponds to the transaction being removed, then
1297                // inform it that the transaction has completed.
1298
1299                if( globalTID.equals(control.getGlobalTID(outStatus)) &&
1300                    outStatus.value == Status.StatusActive )
1301                    control.setTranState(aborted ? Status.StatusRolledBack : Status.StatusCommitted);
1302            } catch( Throwable exc ) {
1303            }
1304        }*/

1305    }
1306
1307    /**Informs the CurrentTransaction that the transaction service is being shut
1308     * down.
1309     *
1310     * For immediate shutdown,
1311     *
1312     * For quiesce,
1313     *
1314     * @param immediate Indicates whether to stop immediately.
1315     *
1316     * @return
1317     *
1318     * @see
1319     */

1320    static void shutdown( boolean immediate ) {
1321
1322        //$Continue with shutdown/quiesce.
1323
}
1324
1325    /**Dumps the static state of the class.
1326     *
1327     * @param
1328     *
1329     * @return
1330     *
1331     * @see
1332     */

1333    static void dump() {
1334    }
1335
1336    /**Reports the contents of the CurrentTransaction tables.
1337     *$Only required for debug.
1338     *
1339     * @param immediate Indicates whether to stop immediately.
1340     *
1341     * @return
1342     *
1343     * @see
1344     */

1345    /*
1346      static
1347
1348      void report()
1349      {
1350
1351      // Report on threadContexts.
1352
1353      if( threadContexts.size() > 0 )
1354      {
1355      _logger.log(Level.FINE,"CurrentTransaction.threadContexts non-empty");
1356      Enumeration keys = threadContexts.keys();
1357      while( keys.hasMoreElements() )
1358      {
1359      Thread thread = (Thread)keys.nextElement();
1360      ControlImpl contImpl = (ControlImpl)threadContexts.get(thread);
1361      if(_logger.isLoggable(Level.FINE))
1362      _logger.log(Level.FINE,"Thread :"+thread+" -> "+contImpl)
1363      }
1364      }
1365      else
1366      _logger.log(Level.FINE,"CurrentTransaction.threadContexts empty");
1367
1368      // Report on importedTransactions.
1369
1370      if( importedTransactions.size() > 0 )
1371      {
1372          _logger.log(Level.FINE,"CurrentTransaction.importedTransactions non-empty");
1373      Enumeration keys = importedTransactions.keys();
1374      while( keys.hasMoreElements() )
1375      {
1376      Thread thread = (Thread)keys.nextElement();
1377      GlobalTID tid = (GlobalTID)importedTransactions.get(thread);
1378      if(_logger.isLoggable(Level.FINE))
1379      _logger.log(Level.FINE,"Thread :"+thread+" -> "+tid)
1380      }
1381      }
1382      else
1383        _logger.log(Level.FINE,"CurrentTransaction.importedTransactions empty");
1384      // Report on suspended
1385
1386      if( suspended.size() > 0 )
1387      {
1388         _logger.log(Level.FINE,"CurrentTransaction.suspended non-empty");
1389      Enumeration keys = suspended.elements();
1390      while( keys.hasMoreElements() )
1391      {
1392          ControlImpl contImpl = (ControlImpl)keys.nextElement();
1393          _logger.log(Level.FINE,"ControlImpl:"+contImpl);
1394      }
1395      }
1396      else
1397        _logger.log(Level.FINE,"CurrentTransaction.suspended empty");
1398      } */

1399}
1400
Popular Tags