KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jotm > ControlImpl


1 /*
2  * @(#) ControlImpl.java 1.2 02/01/15
3  *
4  * JOTM: Java Open Transaction Manager
5  *
6  * This module was originally developed by
7  *
8  * - Bull S.A. as part of the JOnAS application server code released in
9  * July 1999 (www.bull.com)
10  *
11  * --------------------------------------------------------------------------
12  * The original code and portions created by Bull SA are
13  * Copyright (c) 1999 BULL SA
14  * All rights reserved.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions are met:
18  *
19  * -Redistributions of source code must retain the above copyright notice, this
20  * list of conditions and the following disclaimer.
21  *
22  * -Redistributions in binary form must reproduce the above copyright notice,
23  * this list of conditions and the following disclaimer in the documentation
24  * and/or other materials provided with the distribution.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  * --------------------------------------------------------------------------
38  *
39  * Contributor:
40  * 02/01/15 Dean Jennings - ArrayList for resourceList and synchronizationList
41  * 02/09/10 Riviere Guillaume (Guillaume.Riviere@inrialpes.fr) - RemoteControl added
42  *
43  * --------------------------------------------------------------------------
44  * $Id: ControlImpl.java,v 1.30 2005/04/22 17:47:44 tonyortiz Exp $
45  * --------------------------------------------------------------------------
46  */

47 package org.objectweb.jotm;
48
49 import java.rmi.RemoteException JavaDoc;
50 import java.rmi.NoSuchObjectException JavaDoc;
51 import java.rmi.ServerException JavaDoc;
52
53 import javax.rmi.PortableRemoteObject JavaDoc;
54
55 import java.util.List JavaDoc;
56 import java.util.ArrayList JavaDoc;
57 import javax.transaction.Status JavaDoc;
58 import javax.transaction.TransactionRolledbackException JavaDoc;
59 import javax.transaction.xa.Xid JavaDoc;
60
61 import org.objectweb.carol.util.configuration.ConfigurationRepository;
62 import org.objectweb.carol.rmi.exception.RmiUtility;
63
64 /**
65  * Implementation of the object that represents a transaction.
66  * This remote object has been created by a TransactionFactory.
67  * It extends The RemoteControl Remote Interface
68  *
69  * @see org.objectweb.jotm.TransactionFactory
70  *
71  */

72 public class ControlImpl
73     extends PortableRemoteObject JavaDoc
74     implements Control, Resource, Coordinator, Terminator JavaDoc, RecoveryCoordinator, TimerEventListener {
75
76     // ===============================================================
77
// Private data
78
// ===============================================================
79
/**
80      * @serial
81      */

82     private List JavaDoc resourceList = new ArrayList JavaDoc();
83     /**
84      * @serial
85      */

86     private List JavaDoc synchronizationList = new ArrayList JavaDoc();
87     /**
88      * @serial
89      */

90     private int mystatus = Status.STATUS_UNKNOWN;
91     /**
92      * @serial
93      */

94     private boolean hasSupCoord = false;
95     /**
96      * @serial
97      */

98     private TimerEvent mytimer = null;
99     /**
100      * @serial
101      */

102     private Xid xid;
103     /**
104      * @serial
105      */

106     private Log mylog;
107
108     // ---------------------------------------------------------------
109
// Constructors
110
// ---------------------------------------------------------------
111

112     /**
113      * Constructor for create or recreate
114      *
115      * @param timeout Timeout in seconds for this transaction
116      * @param x Xid allocated to this transaction
117      * @param supco Superior coordinator (null if create); must be a
118      * org.objectweb.jotm.Coordinator or a org.omg.CosTransactions.Coordinator
119      */

120     ControlImpl(int timeout, Xid x, Object JavaDoc supco) throws RemoteException JavaDoc {
121         if (TraceTm.jotm.isDebugEnabled()) {
122             TraceTm.jotm.debug("timeout="+ timeout +", xid="+ x +", supco="+ supco);
123         }
124
125         // init object state
126
mystatus = Status.STATUS_ACTIVE;
127         xid = x;
128         hasSupCoord = (supco != null);
129
130         // XXX In case of sub-coordinator, should we arm a timer for rollback ???
131

132         mytimer = TimerManager.getInstance().addTimer(this, timeout, new Integer JavaDoc(1), false);
133
134         // If sub-coord, register resource
135
if (supco != null) {
136             try {
137                 if (supco instanceof Coordinator)
138                      ((Coordinator) supco).register_resource(this);
139                 else
140                     // XXX CORBA Cordinator not taken into account
141
// register the control as a CORBA resource in the remote CORBA Coordinator (we use a wraper)
142
//((org.omg.CosTransactions.Coordinator) supco).register_resource(new ControlResourceImpl(this));
143
throw new RemoteException JavaDoc("Not Implemented");
144             } catch (Exception JavaDoc e) {
145                 TraceTm.jotm.error("Cannot register sub-coordinator:\n", e);
146             }
147         }
148     }
149
150     // ---------------------------------------------------------------
151
// Control Interface
152
// ---------------------------------------------------------------
153

154     /**
155      * Gets the Terminator object for this transaction
156      *
157      * @return Terminator for this transaction
158      */

159     public Terminator JavaDoc get_terminator() throws RemoteException JavaDoc {
160
161         return this;
162     }
163
164     /**
165      * Gets the Coordinator object for this transaction
166      *
167      * @return Coordinator for this transaction
168      */

169     public Coordinator get_coordinator() throws RemoteException JavaDoc {
170         if (TraceTm.jotm.isDebugEnabled()) {
171             TraceTm.jotm.debug("ControlImpl.get_coordinator");
172         }
173         return this;
174     }
175
176     // ---------------------------------------------------------------
177
// Coordinator Interface
178
// ---------------------------------------------------------------
179

180     /**
181      * Gets the current status of this transaction
182      *
183      * @return current transaction status
184      */

185     public int get_status() throws RemoteException JavaDoc {
186         if (TraceTm.jotm.isDebugEnabled()) {
187             TraceTm.jotm.debug("ControlImpl.get_status()");
188         }
189         return mystatus;
190     }
191
192     /**
193      * Tests if the given coordinator represents this transaction
194      *
195      * @param tc Coordinator to be compared to this transaction
196      * @return true if it is the same transaction
197      */

198     public boolean is_same_transaction(Coordinator tc) throws RemoteException JavaDoc {
199         if (TraceTm.jotm.isDebugEnabled()) {
200             TraceTm.jotm.debug("ControlImpl.is_same_transaction(Coordinator)");
201         }
202
203         String JavaDoc other = null;
204
205         try {
206             other = tc.get_transaction_name();
207         } catch (Exception JavaDoc e) {
208             if (TraceTm.jotm.isDebugEnabled()) {
209                 TraceTm.jotm.error("ControlImpl.is_same_transaction() raised exception:\n", e);
210             }
211             return false;
212         }
213         
214         return other.equals(get_transaction_name());
215     }
216
217     /**
218      * Registers a Resource object for this transaction
219      *
220      * @param res Resource to be registered
221      * @return RecoveryCoordinator used for replay_completion
222      */

223     public synchronized RecoveryCoordinator register_resource(Resource res) throws RemoteException JavaDoc {
224         if (TraceTm.jotm.isDebugEnabled()) {
225             TraceTm.jotm.debug("resource="+ res);
226             TraceTm.jotm.debug("mystatus="+ StatusHelper.getStatusName(mystatus));
227         }
228
229         switch (mystatus) {
230
231             case Status.STATUS_ACTIVE :
232                 // Normal case
233
resourceList.add(res);
234                 if (TraceTm.jotm.isDebugEnabled()) {
235                     TraceTm.jotm.debug("Resource registered");
236                 }
237                 break;
238
239             case Status.STATUS_MARKED_ROLLBACK :
240             case Status.STATUS_ROLLEDBACK :
241             case Status.STATUS_ROLLING_BACK :
242                 TraceTm.jotm.error("ControlImpl.register_resource(): Transaction Rolled back");
243                 TraceTm.jotm.error("mystatus= "+ StatusHelper.getStatusName(mystatus));
244                 throw new TransactionRolledbackException JavaDoc();
245
246             default :
247                 TraceTm.jotm.error("ControlImpl.register_resource(): Transaction Inactive");
248                 TraceTm.jotm.error("mystatus= "+ StatusHelper.getStatusName(mystatus));
249                 throw new InactiveException("Cannot register resource, status " + StatusHelper.getStatusName(mystatus));
250         }
251         return this;
252     }
253
254     /**
255      * Registers a Synchronization object for this transaction
256      *
257      * @param sync RemoteSynchro to be registered
258      */

259     public synchronized void register_synchronization(RemoteSynchro sync) throws RemoteException JavaDoc {
260         if (TraceTm.jotm.isDebugEnabled()) {
261             TraceTm.jotm.debug("sync="+ sync);
262             TraceTm.jotm.debug("mystatus="+ StatusHelper.getStatusName(mystatus));
263         }
264
265         switch (mystatus) {
266
267             case Status.STATUS_ACTIVE :
268                 // Normal case
269
synchronizationList.add(sync);
270                 if (TraceTm.jotm.isDebugEnabled()) {
271                     TraceTm.jotm.debug("ControlImpl.register_synchronization(): RemoteSynchro registered");
272                 }
273                 break;
274
275             case Status.STATUS_MARKED_ROLLBACK :
276             case Status.STATUS_ROLLEDBACK :
277             case Status.STATUS_ROLLING_BACK :
278                 TraceTm.jotm.error("ControlImpl.register_synchronization(): Transaction Rolled back");
279                 TraceTm.jotm.error("mystatus= "+ StatusHelper.getStatusName(mystatus));
280                 throw new TransactionRolledbackException JavaDoc();
281
282             default :
283                 TraceTm.jotm.error("ControlImpl.register_synchronization(): Transaction Inactive");
284                 TraceTm.jotm.error("mystatus= "+ StatusHelper.getStatusName(mystatus));
285                 throw new InactiveException("Cannot register synchronization, status " + StatusHelper.getStatusName(mystatus));
286         }
287     }
288
289     /**
290      * Asks to rollback the transaction
291      *
292      */

293     public synchronized void rollback_only() throws RemoteException JavaDoc {
294         if (TraceTm.jotm.isDebugEnabled()) {
295             TraceTm.jotm.debug("mystatus="+ StatusHelper.getStatusName(mystatus));
296         }
297
298         switch (mystatus) {
299
300             case Status.STATUS_MARKED_ROLLBACK :
301                 // nothing to do: Already marked rolledback.
302
if (TraceTm.jotm.isDebugEnabled()) {
303                     TraceTm.jotm.debug("ControlImpl.rollback_only(): Already marked rolledback");
304                 }
305                 break;
306
307             case Status.STATUS_ACTIVE :
308             // case Status.STATUS_COMMITTING :
309
mystatus = Status.STATUS_MARKED_ROLLBACK;
310                 if (TraceTm.jotm.isDebugEnabled()) {
311                     TraceTm.jotm.debug("ControlImpl.rollback_only(): Marked rollback");
312                 }
313                 break;
314
315             default :
316                 // already prepared
317
TraceTm.jotm.error("ControlImpl.rollback_only(): Inactive");
318                 TraceTm.jotm.error("mystatus= "+ StatusHelper.getStatusName(mystatus));
319                 throw new InactiveException("Cannot rollback transaction, status " + StatusHelper.getStatusName(mystatus));
320         }
321     }
322
323     /**
324      * Gets a String that represents the transaction name.
325      * Only the Format Id and the Global Id are used to build it :
326      * The Branch Qualifier is not used.
327      *
328      * @return Transaction Name
329      */

330     public String JavaDoc get_transaction_name() throws RemoteException JavaDoc {
331         if (TraceTm.jotm.isDebugEnabled()) {
332             TraceTm.jotm.debug("ControlImpl.get_transaction_name()");
333         }
334
335         return xid.toString();
336     }
337
338     // ---------------------------------------------------------------
339
// Terminator Interface
340
// ---------------------------------------------------------------
341

342     /**
343      * Commits this transaction
344      *
345      * @param report_heuristics want to report heuristics if any
346      *
347      * @exception TransactionRolledbackException the transaction has been rolled back
348      * @exception HeuristicMixed Resources have rolled back
349      * @exception HeuristicHazard Resources may have rolled back
350      */

351     public synchronized void commit(boolean report_heuristics) throws RemoteException JavaDoc {
352         if (TraceTm.jotm.isDebugEnabled()) {
353             TraceTm.jotm.debug("report_heuristics="+ report_heuristics);
354             TraceTm.jotm.debug("mystatus="+ StatusHelper.getStatusName(mystatus));
355         }
356
357         String JavaDoc protocol = ConfigurationRepository.getCurrentConfiguration().getProtocol().getName();
358         
359         // Stops the Timer.
360
if (mytimer != null) {
361             mytimer.stop();
362         }
363
364         // Checks status
365
switch (mystatus) {
366
367             case Status.STATUS_ACTIVE :
368                 // normal case
369
break;
370
371             case Status.STATUS_COMMITTED :
372                 TraceTm.jotm.error("ControlImpl.commit(boolean): already done");
373                 return;
374
375             case Status.STATUS_ROLLEDBACK :
376                 TraceTm.jotm.error("ControlImpl.commit(boolean): already rolled back");
377                 // We should be here in case of timeout expired.
378
// In this case, completed() was not called.
379
completed(true);
380                 
381                 if (protocol == null || !(protocol.equals("iiop"))) {
382                     throw new TransactionRolledbackException JavaDoc();
383                 }
384                 
385                 RmiUtility.rethrowRmiException(new TransactionRolledbackException JavaDoc());
386
387             case Status.STATUS_MARKED_ROLLBACK :
388                 // Synchronization objects
389
int errors = do_before_completion();
390             
391                 if (errors > 0) {
392                     TraceTm.jotm.info("ControlImpl.commit(boolean): before completion error at rollback");
393                 }
394                 
395                 do_rollback(report_heuristics);
396                 completed(true);
397                 
398                 if (protocol == null || !(protocol.equals("iiop"))) {
399                     throw new TransactionRolledbackException JavaDoc();
400                 }
401                 
402                 RmiUtility.rethrowRmiException(new TransactionRolledbackException JavaDoc());
403
404             default :
405                 TraceTm.jotm.error("ControlImpl.commit(boolean): bad status");
406                 TraceTm.jotm.error("mystatus= "+ StatusHelper.getStatusName(mystatus));
407                 
408                 if (protocol == null || !(protocol.equals("iiop"))) {
409                     throw new HeuristicMixed();
410                 }
411
412                 RmiUtility.rethrowRmiException(new HeuristicMixed());
413         }
414
415         // Only one resource -> one phase commit.
416
// If Resource raises an heuristic, forward it to the client.
417
if (resourceList.size() == 1) {
418             TraceTm.jotm.debug("1 resource");
419
420             // Synchronization objects
421
int errors = do_before_completion();
422             
423             if (errors > 0) {
424                 TraceTm.jotm.info("before completion error -> rollback");
425                 do_rollback(report_heuristics);
426                 completed(true);
427                 
428                 if (protocol == null || !(protocol.equals("iiop"))) {
429                     throw new TransactionRolledbackException JavaDoc();
430                 }
431
432                 RmiUtility.rethrowRmiException(new TransactionRolledbackException JavaDoc());
433             }
434
435             mystatus = Status.STATUS_COMMITTING;
436             
437             try {
438                 Resource res = (Resource) resourceList.get(0);
439                 res.commit_one_phase();
440                 mystatus = Status.STATUS_COMMITTED;
441             } catch (TransactionRolledbackException JavaDoc e) {
442                 TraceTm.jotm.info("commit_one_phase = TransactionRolledbackException");
443                 mystatus = Status.STATUS_ROLLEDBACK;
444             } catch (HeuristicHazard e) {
445                 TraceTm.jotm.info("commit_one_phase = HeuristicException");
446                 mystatus = Status.STATUS_UNKNOWN;
447             } catch (NoSuchObjectException JavaDoc e) {
448                 // nothing done: can rollback transaction
449
TraceTm.jotm.info("commit_one_phase = NoSuchObjectException");
450                 mystatus = Status.STATUS_ROLLEDBACK;
451             } catch (ServerException JavaDoc e) { // with RMI, may encapsulate TransactionRolledbackException
452
TraceTm.jotm.info("commit_one_phase = ServerException: "+ e);
453                 mystatus = Status.STATUS_ROLLEDBACK;
454             } catch (Exception JavaDoc e) {
455                 TraceTm.jotm.error("commit_one_phase = Unexpected exception: ", e);
456                 mystatus = Status.STATUS_UNKNOWN;
457             }
458
459             // Synchronization objects
460
do_after_completion();
461
462             // Possibly report heuristics to the caller
463
switch (mystatus) {
464                 case Status.STATUS_COMMITTED :
465                     completed(true);
466                     break;
467                 case Status.STATUS_ROLLEDBACK :
468                     completed(true);
469                 
470                     if (protocol == null || !(protocol.equals("iiop"))) {
471                        throw new TransactionRolledbackException JavaDoc();
472                     }
473           
474                     RmiUtility.rethrowRmiException(new TransactionRolledbackException JavaDoc());
475                 case Status.STATUS_UNKNOWN :
476                     completed(false);
477                 
478                     if (report_heuristics) {
479                         if (protocol == null || !(protocol.equals("iiop"))) {
480                             throw new HeuristicHazard();
481                         }
482
483                         RmiUtility.rethrowRmiException(new HeuristicHazard());
484                     }
485             }
486             return;
487         }
488
489         // 2PC - phase 1
490
int v = do_prepare(report_heuristics);
491
492         if (TraceTm.jotm.isDebugEnabled()) {
493             TraceTm.jotm.debug("Vote = " + v);
494         }
495         
496         // Depending on vote, commits or rollbacks transaction
497
switch (v) {
498             case Resource.VOTE_COMMIT :
499                 if (TraceTm.jotm.isDebugEnabled()) {
500                     TraceTm.jotm.debug("ControlImpl.commit(boolean): committing Tx");
501                 }
502                 break;
503             case Resource.VOTE_ROLLBACK :
504                 if (TraceTm.jotm.isDebugEnabled()) {
505                     TraceTm.jotm.debug("ControlImpl.commit(boolean): rolling back Tx");
506                 }
507                 do_rollback(report_heuristics);
508                 completed(true);
509                 
510                 if (protocol == null || !(protocol.equals("iiop"))) {
511                     throw new TransactionRolledbackException JavaDoc();
512                 }
513
514                 RmiUtility.rethrowRmiException(new TransactionRolledbackException JavaDoc());
515             case Resource.VOTE_READONLY :
516                 // No commit phase.
517
if (TraceTm.jotm.isDebugEnabled()) {
518                     TraceTm.jotm.debug("ControlImpl.commit(boolean): readonly resources");
519                 }
520                 mystatus = Status.STATUS_COMMITTED;
521                 completed(true);
522                 return;
523         }
524
525         // Prepare was OK: Decision to commit.
526
mylog.flushLog(Log.DECISION_TO_COMMIT);
527
528         // 2PC - phase 2
529
if (do_commit(report_heuristics) == 0) {
530             completed(true);
531         } else {
532             completed(false);
533         }
534     }
535
536     // ---------------------------------------------------------------
537
// Resource or Terminator Interface
538
// rollback() has the same signature in Terminator and Resource!
539
// ---------------------------------------------------------------
540

541     /**
542      * Rolls back this transaction branch. Can be a sub-coordinator or
543      * a normal coordinator.
544      *
545      */

546     public synchronized void rollback() throws RemoteException JavaDoc {
547         if (TraceTm.jotm.isDebugEnabled()) {
548             TraceTm.jotm.debug("mystatus="+ StatusHelper.getStatusName(mystatus));
549         }
550
551         String JavaDoc protocol = ConfigurationRepository.getCurrentConfiguration().getProtocol().getName();
552
553         // Stops the Timer.
554
if (mytimer != null) {
555             mytimer.stop();
556         }
557
558         // Checks status
559
switch (mystatus) {
560
561             case Status.STATUS_ACTIVE :
562             case Status.STATUS_MARKED_ROLLBACK :
563                 // normal case
564
break;
565
566             case Status.STATUS_ROLLEDBACK :
567                 TraceTm.jotm.error("ControlImpl.rollback(): already rolled back");
568                 TraceTm.jotm.error("mystatus= "+ StatusHelper.getStatusName(mystatus));
569                 return;
570
571             default :
572                 TraceTm.jotm.error("ControlImpl.rollback(): rollback: bad status");
573                 TraceTm.jotm.error("mystatus= "+ StatusHelper.getStatusName(mystatus));
574                 completed(false);
575                 
576                 if (protocol == null || !(protocol.equals("iiop"))) {
577                     throw new HeuristicMixed("rollback: bad status");
578                 }
579
580                 RmiUtility.rethrowRmiException(new TransactionRolledbackException JavaDoc());
581         }
582
583         // Superior coordinator.
584
if (!hasSupCoord) {
585             // Synchronization objects
586
int errors = do_before_completion();
587             if (errors > 0) {
588                 TraceTm.jotm.info("ControlImpl.rollback(): before completion error at rollback");
589             }
590         }
591
592         // rollback Tx
593
try {
594             do_rollback(false);
595         } catch (Exception JavaDoc e) {
596             TraceTm.jotm.error("ControlImpl.rollback(): rollback raised exception ", e);
597         }
598         completed(true);
599     }
600
601     // ---------------------------------------------------------------
602
// Resource Interface (for sub-coordinators)
603
// ---------------------------------------------------------------
604

605     /**
606      * Sub-coordinator has received prepare from its superior.
607      * It must more or less do the same things that the phase 1 of the 2PC.
608      *
609      * @return Vote : commit, roollback or read-only.
610      */

611     public synchronized int prepare() throws RemoteException JavaDoc {
612         if (TraceTm.jotm.isDebugEnabled()) {
613             TraceTm.jotm.debug("mystatus="+ StatusHelper.getStatusName(mystatus));
614         }
615
616         // Stops the Timer.
617
if (mytimer != null) {
618             mytimer.stop();
619         }
620
621         // Checks status
622
switch (mystatus) {
623
624             case Status.STATUS_ACTIVE :
625                 // normal case
626
break;
627
628             case Status.STATUS_COMMITTED :
629                 // Should not occur ?
630
TraceTm.jotm.error("ControlImpl.prepare(): transaction already commited");
631                 TraceTm.jotm.error("mystatus= "+ StatusHelper.getStatusName(mystatus));
632                 return Resource.VOTE_COMMIT;
633
634             case Status.STATUS_ROLLEDBACK :
635                 // Should not occur ?
636
TraceTm.jotm.error("ControlImpl.prepare(): transaction already rolled back");
637                 TraceTm.jotm.error("mystatus= "+ StatusHelper.getStatusName(mystatus));
638                 return Resource.VOTE_ROLLBACK;
639
640             case Status.STATUS_MARKED_ROLLBACK :
641                 do_rollback(false);
642                 completed(true);
643                 return Resource.VOTE_ROLLBACK;
644
645             default :
646                 // Don't know what to do here...
647
TraceTm.jotm.error("ControlImpl.prepare(): bad status");
648                 TraceTm.jotm.error("mystatus= "+ StatusHelper.getStatusName(mystatus));
649                 completed(false);
650                 return Resource.VOTE_ROLLBACK;
651         }
652
653         int ret = do_prepare(false);
654
655         switch (ret) {
656             case Resource.VOTE_COMMIT :
657                 if (TraceTm.jotm.isDebugEnabled()) {
658                     TraceTm.jotm.debug("ControlImpl.prepare(): vote commit");
659                 }
660                 break;
661             case Resource.VOTE_ROLLBACK :
662                 if (TraceTm.jotm.isDebugEnabled()) {
663                     TraceTm.jotm.debug("ControlImpl.prepare(): vote rollback");
664                 }
665                 do_rollback(false);
666                 completed(true);
667                 return ret;
668             case Resource.VOTE_READONLY :
669                 if (TraceTm.jotm.isDebugEnabled()) {
670                     TraceTm.jotm.debug("ControlImpl.prepare(): vote readonly");
671                 }
672                 mystatus = Status.STATUS_COMMITTED;
673                 completed(true);
674                 return ret;
675         }
676
677         // Flush log + recovery coordinator
678
// TODO
679

680         return ret;
681     }
682
683     /**
684      * Sub-coordinator received commit from its superior.
685      * It must more or less do the same things that the phase 2 of the 2PC.
686      */

687     public synchronized void commit() throws RemoteException JavaDoc {
688         if (TraceTm.jotm.isDebugEnabled()) {
689             TraceTm.jotm.debug("mystatus="+ StatusHelper.getStatusName(mystatus));
690         }
691
692         // check status
693
switch (mystatus) {
694             case Status.STATUS_PREPARED :
695                 // normal case
696
break;
697             default :
698                 // Don't know what to do here...
699
TraceTm.jotm.error("ControlImpl.commit(): commit: bad status");
700                 TraceTm.jotm.error("mystatus= "+ StatusHelper.getStatusName(mystatus));
701                 completed(false);
702                 return;
703         }
704
705         // send commit to resources
706
if (do_commit(true) == 0) {
707             completed(true);
708         } else {
709             completed(false);
710         }
711     }
712
713     /**
714      * Sub-coordinator received commit_one_phase from its superior.
715      * It is more or less a Terminator.commit().
716      */

717     public void commit_one_phase() throws RemoteException JavaDoc {
718         if (TraceTm.jotm.isDebugEnabled()) {
719             TraceTm.jotm.debug("ControlImpl.commit_one_phase()");
720         }
721
722         // Just call Terminator.commit
723
commit(true);
724     }
725
726     /**
727      * forget transaction
728      *
729      */

730     public synchronized void forget() throws RemoteException JavaDoc {
731         if (TraceTm.jotm.isDebugEnabled()) {
732             TraceTm.jotm.debug("ControlImpl.forget()");
733         }
734
735         completed(true);
736     }
737
738     // ---------------------------------------------------------------
739
// RecoveryCoordinator Interface
740
// ---------------------------------------------------------------
741

742     /**
743      * Asks the status of this transaction, after recovery of a Resource
744      *
745      * @param res Resource recovering
746      */

747     public int replay_completion(Resource res) throws RemoteException JavaDoc {
748         if (TraceTm.jotm.isDebugEnabled()) {
749             TraceTm.jotm.debug("res="+ res);
750         }
751         return mystatus;
752     }
753
754     // ===============================================================
755
// TimerEventListener implementation
756
// ===============================================================
757

758     /**
759      * The transaction timeout has expired
760      * Do not synchronize this method to avoid deadlocks!
761      */

762     public void timeoutExpired(Object JavaDoc arg) {
763         if (TraceTm.jotm.isDebugEnabled()) {
764             TraceTm.jotm.debug("arg="+ arg);
765         }
766         
767         int argvalue = ((Integer JavaDoc) arg).intValue();
768         
769         switch (argvalue) {
770             case 1 :
771                 if (TraceTm.jotm.isDebugEnabled()) {
772                     TraceTm.jotm.debug("ControlImpl.timeoutExpired(Object): timeout expired");
773                 }
774                 
775                 try {
776                     do_rollback(false);
777                 } catch (Exception JavaDoc e) {
778                     TraceTm.jotm.error("ControlImpl.timeoutExpired(Object): rollback raised exception ", e);
779                 }
780                 break;
781             case 2 :
782                 if (TraceTm.jotm.isDebugEnabled()) {
783                     TraceTm.jotm.debug("ControlImpl.timeoutExpired(Object): removing ControlImpl");
784                 }
785                 explicit_destroy();
786                 break;
787             default :
788                 TraceTm.jotm.error("ControlImpl.timeoutExpired(Object): timeoutExpired bad value="+ argvalue);
789                 break;
790         }
791     }
792
793     // ===============================================================
794
// Private methods
795
// ===============================================================
796

797     /**
798      * timeout expired on this transaction.
799      * This method is not private, because it's used by Timers
800      */

801     void ding() {
802         if (TraceTm.jotm.isDebugEnabled()) {
803             TraceTm.jotm.debug("");
804         }
805     }
806
807     /**
808      * Phase 1 of the 2-Phase-Commit:
809      * Sends prepare to each registered resource
810      * This internal routine should be used either for prepare on sub-coordinator
811      * or for commit on Terminator.
812      *
813      * @return global vote
814      */

815     private int do_prepare(boolean report_heuristics) {
816         if (TraceTm.jotm.isDebugEnabled()) {
817             TraceTm.jotm.debug("report_heuristics="+ report_heuristics);
818         }
819
820         int errors = 0;
821         int ret = Resource.VOTE_READONLY;
822
823         // Synchronization objects
824
errors = do_before_completion();
825         
826         if (errors > 0) {
827             if (TraceTm.jotm.isDebugEnabled()) {
828                 TraceTm.jotm.debug("before_completion failed -> rollback");
829             }
830             return Resource.VOTE_ROLLBACK;
831         }
832
833         // No resource -> just forget transaction.
834
if (resourceList.size() == 0) {
835             TraceTm.jotm.error("commit: no resource");
836             mystatus = Status.STATUS_COMMITTED;
837             do_after_completion();
838             completed(true);
839             return ret;
840         }
841
842         // Creates a log for that transaction, where we will add all the
843
// resources that replied VOTE_COMMIT to prepare.
844
// Do not flush the log on disk before decision to commit.
845
mylog = new Log();
846
847         // Sends prepare to each resource.
848
// In case of prepare on sub-coord. we may have only 1 resource.
849
// In case of phase 1 of the 2PC, we have several resources, because
850
// the case of 1 resource is treated with commit_one_phase (optimization)
851
mystatus = Status.STATUS_PREPARING;
852         
853         for (int i = 0; i < resourceList.size(); i++) {
854             Resource res = (Resource) resourceList.get(i);
855             
856             if (errors > 0) {
857                 if (TraceTm.jotm.isWarnEnabled()) {
858                     TraceTm.jotm.warn("Vote stopped: at least one resource has voted rollback.");
859                 }
860                 break;
861             } else {
862                 // No error yet: Send prepare to the resource.
863
try {
864                     if (TraceTm.jotm.isDebugEnabled()) {
865                         TraceTm.jotm.debug("send prepare to resource");
866                     }
867                     
868                     switch (res.prepare()) {
869                         case Resource.VOTE_COMMIT :
870                             // Log resource
871
mylog.addResource(res);
872                             TraceTm.jotm.info("Resource replied commit to prepare");
873                             ret = Resource.VOTE_COMMIT;
874                             break;
875                         case Resource.VOTE_ROLLBACK :
876                             TraceTm.jotm.info("Resource replied rollback to prepare");
877                             ret = Resource.VOTE_ROLLBACK;
878                             errors++;
879                             break;
880                         case Resource.VOTE_READONLY :
881                             if (TraceTm.jotm.isDebugEnabled()) {
882                                 TraceTm.jotm.debug("Resource replied readonly to prepare");
883                             }
884                             break;
885                     }
886                 } catch (HeuristicHazard e) { // Subcoordinator only
887
TraceTm.jotm.error("HeuristicHazard on prepare");
888                     ret = Resource.VOTE_ROLLBACK;
889                     errors++;
890                 } catch (HeuristicMixed e) { // Subcoordinator only
891
TraceTm.jotm.error("HeuristicMixed on prepare");
892                     ret = Resource.VOTE_ROLLBACK;
893                     errors++;
894                 } catch (Exception JavaDoc e) {
895                     TraceTm.jotm.error("exception on prepare: ", e);
896                     ret = Resource.VOTE_ROLLBACK;
897                     errors++;
898                 }
899             }
900         }
901         
902         if (ret == Resource.VOTE_READONLY) {
903             if (TraceTm.jotm.isDebugEnabled()) {
904                 TraceTm.jotm.debug("All resources returned Readonly");
905             }
906             mystatus = Status.STATUS_COMMITTED;
907             // Synchronization objects
908
do_after_completion();
909         }
910         if (ret == Resource.VOTE_COMMIT) {
911             mystatus = Status.STATUS_PREPARED;
912         }
913         
914         if (TraceTm.jotm.isDebugEnabled()) {
915             if (TraceTm.jotm.isDebugEnabled()) {
916                 TraceTm.jotm.debug("Vote = " + ret);
917             }
918         }
919         return ret;
920     }
921
922     /**
923      * Phase 2 of the 2-Phase-Commit:
924      * Sends commit to each registered resource
925      * This internal routine should be used either for commit on sub-coordinator
926      * or for commit on Terminator.
927      *
928      * @return 0 if commit OK.
929      */

930     private int do_commit(boolean report_heuristics)
931         throws TransactionRolledbackException JavaDoc, HeuristicMixed, HeuristicHazard, HeuristicRollback {
932         
933         if (TraceTm.jotm.isDebugEnabled()) {
934             TraceTm.jotm.debug("report_heuristics="+ report_heuristics);
935         }
936
937         // First check that a log is initialized
938
if (mylog == null) {
939             TraceTm.jotm.error("no log");
940             return -1;
941         }
942
943         // Status Transaction = committing
944
mystatus = Status.STATUS_COMMITTING;
945
946         // Sends commit to each resource "prepared".
947
int commitnb = 0;
948         int heuristicnb = 0;
949         int errors = 0;
950         int heuristicstate = 0;
951         
952         for (int i = 0; i < mylog.resourceLogged.size(); i++) {
953             ResourceInfo resinfo = (ResourceInfo) mylog.resourceLogged.elementAt(i);
954             
955             if (resinfo.mystate != ResourceInfo.PREPARED) {
956                 TraceTm.jotm.info("resource not prepared");
957                 continue;
958             }
959             
960             // aborts transaction if error and no resource committed yet
961
if (commitnb == 0 && errors > 0) {
962                 try {
963                     TraceTm.jotm.info("Send rollback to resource");
964                     resinfo.getResource().rollback();
965                     resinfo.mystate = ResourceInfo.ROLLEDBACK;
966                 } catch (HeuristicCommit e) {
967                     TraceTm.jotm.error("Heuristic commit");
968                     resinfo.mystate = ResourceInfo.HEURISTIC_COMMIT;
969                     heuristicstate = ResourceInfo.HEURISTIC_COMMIT;
970                     commitnb++;
971                     heuristicnb++;
972                 } catch (Exception JavaDoc e) {
973                     TraceTm.jotm.error("exception on rollback: ", e);
974                 }
975                 continue;
976             }
977             
978             // commits resource
979

980             try {
981                 TraceTm.jotm.debug("Send commit to resource");
982                 resinfo.getResource().commit();
983                 resinfo.mystate = ResourceInfo.COMMITTED;
984                 commitnb++;
985             } catch (HeuristicRollback e) {
986                 TraceTm.jotm.error("Heuristic Rollback");
987                 resinfo.mystate = ResourceInfo.HEURISTIC_ROLLBACK;
988                 heuristicstate = ResourceInfo.HEURISTIC_ROLLBACK;
989                 errors++;
990                 if (commitnb > 0)
991                     heuristicnb++;
992             } catch (HeuristicMixed e) {
993                 TraceTm.jotm.error("Heuristic Mixed");
994                 resinfo.mystate = ResourceInfo.HEURISTIC_MIXED;
995                 heuristicstate = ResourceInfo.HEURISTIC_MIXED;
996                 errors++;
997                 commitnb++;
998                 heuristicnb++;
999             } catch (HeuristicHazard e) {
1000                TraceTm.jotm.error("Heuristic Hazard");
1001                resinfo.mystate = ResourceInfo.HEURISTIC_HAZARD;
1002                heuristicstate = ResourceInfo.HEURISTIC_HAZARD;
1003                errors++;
1004                commitnb++;
1005                heuristicnb++;
1006            } catch (NotPreparedException e) {
1007                TraceTm.jotm.error("Resource Not Prepared");
1008                resinfo.mystate = ResourceInfo.REGISTERED;
1009                errors++;
1010            } catch (NoSuchObjectException JavaDoc e) {
1011                TraceTm.jotm.error("invalid objref - assume committed");
1012                resinfo.mystate = ResourceInfo.COMMITTED;
1013                commitnb++;
1014            } catch (Exception JavaDoc e) {
1015                TraceTm.jotm.error("exception on commit: ", e);
1016                errors++;
1017            }
1018        }
1019        
1020        if (errors == 0) {
1021            // Everything's fine.
1022
if (TraceTm.jotm.isDebugEnabled()) {
1023                TraceTm.jotm.debug("transaction committed");
1024            }
1025            
1026            mystatus = Status.STATUS_COMMITTED;
1027            mylog.forgetLog();
1028            // Synchronization Objects
1029
do_after_completion();
1030            return 0;
1031        }
1032        
1033        if (heuristicnb == 0) {
1034            // Transaction has been eventually rolled back
1035
TraceTm.jotm.info("transaction rolled back");
1036            mystatus = Status.STATUS_ROLLEDBACK;
1037            mylog.forgetLog();
1038            // Synchronization Objects
1039
do_after_completion();
1040            throw new TransactionRolledbackException JavaDoc();
1041        }
1042        
1043        // Heuristics must be logged
1044
TraceTm.jotm.info("Heuristics must be logged");
1045        mystatus = Status.STATUS_UNKNOWN;
1046        mylog.updateLog();
1047        
1048        // Synchronization Objects
1049
do_after_completion();
1050        
1051        if (report_heuristics) {
1052            switch (heuristicstate) {
1053                case (ResourceInfo.HEURISTIC_ROLLBACK): {
1054                    throw new HeuristicRollback();
1055                }
1056                case (ResourceInfo.HEURISTIC_MIXED): {
1057                    throw new HeuristicMixed();
1058                }
1059                case (ResourceInfo.HEURISTIC_HAZARD): {
1060                    throw new HeuristicHazard();
1061                }
1062            }
1063        }
1064        
1065        return -1;
1066    }
1067
1068    /**
1069     * Rollbacks the transaction
1070     * This internal routine should be used either for rollback on sub-coordinator
1071     * or for commit on Terminator when prepare returned a vote RollBack.
1072     */

1073    private void do_rollback(boolean report_heuristics) throws HeuristicMixed {
1074        if (TraceTm.jotm.isDebugEnabled()) {
1075            TraceTm.jotm.debug("report_heuristics="+ report_heuristics);
1076        }
1077
1078        mystatus = Status.STATUS_ROLLEDBACK;
1079
1080        // Rollback resources
1081
int commitnb = 0;
1082        
1083        for (int i = 0; i < resourceList.size(); i++) {
1084            Resource res = (Resource) resourceList.get(i);
1085            try {
1086                if (TraceTm.jotm.isDebugEnabled()) {
1087                    TraceTm.jotm.debug("Send rollback to Resource");
1088                }
1089                res.rollback();
1090            } catch (HeuristicCommit e) {
1091                TraceTm.jotm.error("Rollback raised HeuristicCommit");
1092                commitnb++;
1093            } catch (Exception JavaDoc e) {
1094                TraceTm.jotm.error("Cannot rollback resource: ", e);
1095            }
1096        }
1097
1098        // Synchronization objects
1099
do_after_completion();
1100
1101        if (commitnb > 0 && report_heuristics) {
1102            // May be should throw HeuristicCommit instead
1103
throw new HeuristicMixed();
1104        }
1105    }
1106
1107    /**
1108     * Destroys transaction object.
1109     */

1110    private void explicit_destroy() {
1111        if (TraceTm.jotm.isDebugEnabled()) {
1112            TraceTm.jotm.debug("");
1113        }
1114        
1115        // unexportObject explicitly
1116
try {
1117            unexportObject(this);
1118        } catch (Exception JavaDoc e) {}
1119    }
1120
1121    /**
1122     * Delay destroy of the ControlImpl object.
1123     * We must keep alive this object a little while for recovery reasons,
1124     * and also in case of Jeremie because we may propagate a reference to
1125     * this object inside the propagation context.
1126     */

1127    private void completed(boolean removeit) {
1128        if (TraceTm.jotm.isDebugEnabled()) {
1129            TraceTm.jotm.debug("removeit="+ removeit);
1130        }
1131        
1132        if (mytimer != null) {
1133            if (removeit) {
1134                // Convert the timer to make a delayed removal of this object
1135
mytimer.change(60, new Integer JavaDoc(2));
1136            } else {
1137                // In case of heuristic, must keep ControlImpl.
1138
// No more timer is needed.
1139
mytimer.unset();
1140                mytimer = null;
1141            }
1142        }
1143    }
1144
1145    /**
1146     * Sends before_completion to the registered synchronizations
1147     *
1148     * @return 0 if no error
1149     */

1150    private int do_before_completion() {
1151        if (TraceTm.jotm.isDebugEnabled()) {
1152            TraceTm.jotm.debug("ControlImpl.do_before_completion()");
1153            TraceTm.jotm.debug("synchronizationList.size()="+ synchronizationList.size());
1154        }
1155
1156        int errors = 0;
1157        
1158        for (int i = 0; i < synchronizationList.size(); i++) {
1159
1160            RemoteSynchro sync = (RemoteSynchro) synchronizationList.get(i);
1161            
1162            try {
1163                sync.before_completion(this);
1164            } catch (Exception JavaDoc e) {
1165                TraceTm.jotm.error("before_completion raised exception ", e);
1166                errors++;
1167            }
1168        }
1169        return errors;
1170    }
1171
1172    /**
1173     * Sends after_completion to the registered synchronizations
1174     */

1175    private void do_after_completion() {
1176
1177        if (TraceTm.jotm.isDebugEnabled()) {
1178            TraceTm.jotm.debug("ControlImpl.do_after_completion()");
1179            TraceTm.jotm.debug("status="+ mystatus);
1180            TraceTm.jotm.debug("synchronizationList.size()="+ synchronizationList.size());
1181        }
1182        
1183        for (int i = 0; i < synchronizationList.size(); i++) {
1184            RemoteSynchro sync = (RemoteSynchro) synchronizationList.get(i);
1185            
1186            try {
1187                sync.after_completion(this, mystatus);
1188            } catch (Exception JavaDoc e) {
1189                TraceTm.jotm.error("after_completion raised exception ", e);
1190            }
1191        }
1192    }
1193}
1194
Popular Tags