Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / derby-10.3.2.1 / java / engine / org / apache / derby / jdbc / XATransactionState.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/jdbc/XATransactionState.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/jdbc/XATransactionState.java
new file mode 100644 (file)
index 0000000..886f42d
--- /dev/null
@@ -0,0 +1,393 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.jdbc.XATransactionState\r
+\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+      http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.jdbc;\r
+\r
+\r
+import java.sql.SQLException;\r
+import java.util.Timer;\r
+import java.util.TimerTask;\r
+import org.apache.derby.iapi.services.monitor.Monitor;\r
+import org.apache.derby.iapi.services.timer.TimerFactory;\r
+import org.apache.derby.impl.jdbc.EmbedConnection;\r
+import javax.transaction.xa.XAResource;\r
+import org.apache.derby.iapi.services.context.ContextImpl;\r
+import org.apache.derby.iapi.services.context.ContextManager;\r
+import org.apache.derby.iapi.error.ExceptionSeverity;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.store.access.xa.XAXactId;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import java.util.HashMap;\r
+import javax.transaction.xa.XAException;\r
+\r
+/** \r
+*/\r
+final class XATransactionState extends ContextImpl {\r
+\r
+    /** Rollback-only due to timeout */\r
+    final static int TRO_TIMEOUT                = -3;\r
+       /** Rollback-only due to deadlock */\r
+       final static int TRO_DEADLOCK                           = -2;\r
+       /** Rollback-only due to end(TMFAIL) */\r
+       final static int TRO_FAIL                                       = -1;\r
+       final static int T0_NOT_ASSOCIATED                      = 0;\r
+       final static int T1_ASSOCIATED                          = 1;\r
+       // final static int T2_ASSOCIATION_SUSPENDED    = 2;\r
+       final static int TC_COMPLETED                           = 3; // rollback/commit called\r
+\r
+       final EmbedConnection   conn;\r
+       final EmbedXAResource creatingResource;\r
+        // owning XAResource\r
+       private EmbedXAResource  associatedResource;    \r
+       final XAXactId                  xid;    \r
+       /**\r
+               When an XAResource suspends a transaction (end(TMSUSPEND)) it must be resumed\r
+               using the same XAConnection. This has been the traditional Cloudscape/Derby behaviour,\r
+               though there does not seem to be a specific reference to this behaviour in\r
+               the JTA spec. Note that while the transaction is suspended by this XAResource,\r
+               another XAResource may join the transaction and suspend it after the join.\r
+       */\r
+       HashMap suspendedList;\r
+\r
+\r
+       /**\r
+               Association state of the transaction.\r
+       */\r
+       int associationState;\r
+\r
+       int rollbackOnlyCode;\r
+\r
+\r
+       /**\r
+               has this transaction been prepared.\r
+       */\r
+       boolean isPrepared;\r
+\r
+    /** Has this transaction been finished (committed\r
+      * or rolled back)? */\r
+    boolean isFinished;\r
+\r
+    /** A timer task scheduled for the time when the transaction will timeout. */\r
+    CancelXATransactionTask timeoutTask = null;\r
+\r
+\r
+    /** The implementation of TimerTask to cancel a global transaction. */\r
+    private class CancelXATransactionTask extends TimerTask {\r
+\r
+        /** Creates the cancelation object to be passed to a timer. */\r
+        public CancelXATransactionTask() {\r
+            XATransactionState.this.timeoutTask = this;\r
+        }\r
+\r
+        /** Runs the cancel task of the global transaction */\r
+        public void run() {\r
+            try {\r
+                XATransactionState.this.cancel();\r
+            } catch (XAException ex) {\r
+                Monitor.logThrowable(ex);\r
+            }\r
+        }\r
+    }\r
+\r
+\r
+\r
+       XATransactionState(ContextManager cm, EmbedConnection conn, \r
+                EmbedXAResource resource, XAXactId xid) {\r
+\r
+               super(cm, "XATransactionState");\r
+               this.conn = conn;\r
+               this.associatedResource = resource;\r
+               this.creatingResource = resource;\r
+               this.associationState = XATransactionState.T1_ASSOCIATED;\r
+               this.xid = xid;\r
+        this.isFinished = false;\r
+\r
+       }\r
+\r
+       public void cleanupOnError(Throwable t) {\r
+\r
+               if (t instanceof StandardException) {\r
+\r
+                       StandardException se = (StandardException) t;\r
+            \r
+            if (se.getSeverity() >= ExceptionSeverity.SESSION_SEVERITY) {\r
+                popMe();\r
+                return;\r
+            }\r
+\r
+                       if (se.getSeverity() == ExceptionSeverity.TRANSACTION_SEVERITY) {\r
+\r
+                               synchronized (this) {\r
+                                       // disable use of the connection until it is cleaned up.\r
+                                       conn.setApplicationConnection(null);\r
+                                       notifyAll();\r
+                                       associationState = TRO_FAIL;\r
+                                       if (SQLState.DEADLOCK.equals(se.getMessageId()))\r
+                                               rollbackOnlyCode = XAException.XA_RBDEADLOCK;\r
+                                       else if (SQLState.LOCK_TIMEOUT.equals(se.getMessageId()))\r
+                                               rollbackOnlyCode = XAException.XA_RBTIMEOUT;                                    \r
+                                       else\r
+                                               rollbackOnlyCode = XAException.XA_RBOTHER;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       void start(EmbedXAResource resource, int flags) throws XAException {\r
+\r
+               synchronized (this) {\r
+                       if (associationState == XATransactionState.TRO_FAIL)\r
+                               throw new XAException(rollbackOnlyCode);\r
+\r
+                       boolean isSuspendedByResource = (suspendedList != null) && (suspendedList.get(resource) != null);\r
+\r
+                       if (flags == XAResource.TMRESUME) {\r
+                               if (!isSuspendedByResource)\r
+                                       throw new XAException(XAException.XAER_PROTO);\r
+\r
+                       } else {\r
+                               // cannot join a transaction we have suspended.\r
+                               if (isSuspendedByResource)\r
+                                       throw new XAException(XAException.XAER_PROTO);\r
+                       }\r
+\r
+                       while (associationState == XATransactionState.T1_ASSOCIATED) {\r
+                               \r
+                               try {\r
+                                       wait();\r
+                               } catch (InterruptedException ie) {\r
+                                       throw new XAException(XAException.XA_RETRY);\r
+                               }\r
+                       }\r
+\r
+\r
+                       switch (associationState) {\r
+                       case XATransactionState.T0_NOT_ASSOCIATED:\r
+                               break;\r
+\r
+            case XATransactionState.TRO_DEADLOCK:\r
+            case XATransactionState.TRO_TIMEOUT:\r
+                       case XATransactionState.TRO_FAIL:\r
+                               throw new XAException(rollbackOnlyCode);\r
+\r
+                       default:\r
+                               throw new XAException(XAException.XAER_NOTA);\r
+                       }\r
+\r
+                       if (isPrepared)\r
+                               throw new XAException(XAException.XAER_PROTO);\r
+\r
+                       if (isSuspendedByResource) {\r
+                               suspendedList.remove(resource);\r
+                       }\r
+\r
+                       associationState = XATransactionState.T1_ASSOCIATED;\r
+                       associatedResource = resource;\r
+\r
+               }\r
+       }\r
+\r
+       boolean end(EmbedXAResource resource, int flags, \r
+                boolean endingCurrentXid) throws XAException {\r
+\r
+               boolean rollbackOnly = false;\r
+               synchronized (this) {\r
+\r
+\r
+                       boolean isSuspendedByResource = (suspendedList != null) && (suspendedList.get(resource) != null);\r
+\r
+                       if (!endingCurrentXid) {\r
+                               while (associationState == XATransactionState.T1_ASSOCIATED) {\r
+                                       \r
+                                       try {\r
+                                               wait();\r
+                                       } catch (InterruptedException ie) {\r
+                                               throw new XAException(XAException.XA_RETRY);\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       switch (associationState) {\r
+                       case XATransactionState.TC_COMPLETED:\r
+                               throw new XAException(XAException.XAER_NOTA);\r
+                       case XATransactionState.TRO_FAIL:\r
+                               if (endingCurrentXid)\r
+                                       flags = XAResource.TMFAIL;\r
+                               else\r
+                                       throw new XAException(rollbackOnlyCode);\r
+                       }\r
+\r
+                       boolean notify = false;\r
+                       switch (flags) {\r
+                       case XAResource.TMSUCCESS:\r
+                               if (isSuspendedByResource) {\r
+                                       suspendedList.remove(resource);\r
+                               }\r
+                               else {\r
+                                       if (resource != associatedResource)\r
+                                               throw new XAException(XAException.XAER_PROTO);\r
+\r
+                                       associationState = XATransactionState.T0_NOT_ASSOCIATED;\r
+                                       associatedResource = null;\r
+                                       notify = true;\r
+                               }\r
+\r
+                               conn.setApplicationConnection(null);\r
+                               break;\r
+\r
+                       case XAResource.TMFAIL:\r
+\r
+                               if (isSuspendedByResource) {\r
+                                       suspendedList.remove(resource);\r
+                               } else {\r
+                                       if (resource != associatedResource)\r
+                                               throw new XAException(XAException.XAER_PROTO);\r
+                                       associatedResource = null;\r
+                               }\r
+                               \r
+                               if (associationState != XATransactionState.TRO_FAIL) {\r
+                                       associationState = XATransactionState.TRO_FAIL;\r
+                                       rollbackOnlyCode = XAException.XA_RBROLLBACK;\r
+                               }\r
+                               conn.setApplicationConnection(null);\r
+                               notify = true;\r
+                               rollbackOnly = true;\r
+                               break;\r
+\r
+                       case XAResource.TMSUSPEND:\r
+                               if (isSuspendedByResource)\r
+                                       throw new XAException(XAException.XAER_PROTO);\r
+                               \r
+                               if (resource != associatedResource)\r
+                                       throw new XAException(XAException.XAER_PROTO);\r
+\r
+                               if (suspendedList == null)\r
+                                       suspendedList = new HashMap();\r
+                               suspendedList.put(resource, this);\r
+\r
+                               associationState = XATransactionState.T0_NOT_ASSOCIATED;\r
+                               associatedResource = null;\r
+                               conn.setApplicationConnection(null);\r
+                               notify = true;\r
+\r
+                               break;\r
+\r
+                       default:\r
+                               throw new XAException(XAException.XAER_INVAL);\r
+                       }\r
+\r
+                       if (notify)\r
+                               notifyAll();\r
+\r
+                       return rollbackOnly;\r
+               }\r
+       }\r
+\r
+   /**\r
+    * Schedule a timeout task wich will rollback the global transaction\r
+    * after the specified time will elapse.\r
+    *\r
+    * @param timeoutMillis The number of milliseconds to be elapsed before\r
+    *                      the transaction will be rolled back.\r
+    */\r
+    synchronized void scheduleTimeoutTask(long timeoutMillis) {\r
+        // schedule a time out task if the timeout was specified\r
+        if (timeoutMillis > 0) {\r
+            // take care of the transaction timeout\r
+            TimerTask cancelTask = new CancelXATransactionTask();\r
+            TimerFactory timerFactory = Monitor.getMonitor().getTimerFactory();\r
+            Timer timer = timerFactory.getCancellationTimer();\r
+            timer.schedule(cancelTask, timeoutMillis);\r
+        } else {\r
+            timeoutTask = null;\r
+        }\r
+    }\r
+\r
+   /**\r
+     * Rollback the global transaction and cancel the timeout task.\r
+     */\r
+    synchronized void xa_rollback() throws SQLException {\r
+        conn.xa_rollback();\r
+        xa_finalize();\r
+    }\r
+\r
+   /**\r
+     * Commit the global transaction and cancel the timeout task.\r
+     * @param onePhase Indicates whether to use one phase commit protocol.\r
+     *                Otherwise two phase commit protocol will be used.\r
+     */\r
+    synchronized void xa_commit(boolean onePhase) throws SQLException {\r
+        conn.xa_commit(onePhase);\r
+        xa_finalize();\r
+    }\r
+\r
+   /**\r
+     * Prepare the global transaction for commit.\r
+     */\r
+    synchronized int xa_prepare() throws SQLException {\r
+        int retVal = conn.xa_prepare();\r
+        return retVal;\r
+    }\r
+\r
+    /** This method cancels timeoutTask and marks the transaction\r
+      * as finished by assigning 'isFinished = true'.\r
+      */\r
+    synchronized void xa_finalize() {\r
+        if (timeoutTask != null) {\r
+            timeoutTask.cancel();\r
+        }\r
+        isFinished = true;\r
+    }\r
+\r
+    /**\r
+     * This function is called from the timer task when the transaction\r
+     * times out.\r
+     *\r
+     * @see CancelXATransactionTask\r
+     */\r
+    private synchronized void cancel() throws XAException {\r
+        // Check isFinished just to be sure that\r
+        // the cancellation task was not started\r
+        // just before the xa_commit/rollback\r
+        // obtained this object's monitor.\r
+        if (!isFinished) {\r
+            // Check whether the transaction is associated\r
+            // with any EmbedXAResource instance.\r
+            if (associationState == XATransactionState.T1_ASSOCIATED) {\r
+                conn.cancelRunningStatement();\r
+                EmbedXAResource assocRes = associatedResource;\r
+                end(assocRes, XAResource.TMFAIL, true);\r
+            }\r
+\r
+            // Rollback the global transaction\r
+            try {\r
+                conn.xa_rollback();\r
+            } catch (SQLException sqle) {\r
+                XAException ex = new XAException(XAException.XAER_RMERR);\r
+                ex.initCause(sqle);\r
+                throw ex;\r
+            }\r
+\r
+            // Do the cleanup on the resource\r
+            creatingResource.returnConnectionToResource(this, xid);\r
+        }\r
+    }\r
+}\r