[Mulgara-svn] r98 - branches/xafix/src/jar/resolver/java/org/mulgara/resolver

andrae at mulgara.org andrae at mulgara.org
Tue Oct 10 10:50:08 UTC 2006


Author: andrae
Date: 2006-10-10 05:50:08 -0500 (Tue, 10 Oct 2006)
New Revision: 98

Added:
   branches/xafix/src/jar/resolver/java/org/mulgara/resolver/AnswerOperation.java
   branches/xafix/src/jar/resolver/java/org/mulgara/resolver/AnswerOperationResult.java
Modified:
   branches/xafix/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java
   branches/xafix/src/jar/resolver/java/org/mulgara/resolver/TransactionalAnswer.java
Log:
More sketching.

I don't expect TransactionalAnswer to change much from this point.  I really am serious about ensuring that it is *impossible* to get the transaction semantics wrong *outside* the classes specifically tasked with ensuring correctness.

The basic pattern I intend to use to ensure this is amply illustrated in TransactionalAnswer.  The key approach is to wrap all non-transaction aware operations in a closure that is then evaluated within a transactional context that is established, and cleaned up by an enclosing transaction aware class.

The goal is to allow the partitioning of the entire system into to classes of class.  Those that are exclusively transaction-oriented.  And those that are completely non-transaction aware.



Added: branches/xafix/src/jar/resolver/java/org/mulgara/resolver/AnswerOperation.java
===================================================================
--- branches/xafix/src/jar/resolver/java/org/mulgara/resolver/AnswerOperation.java	2006-10-09 11:00:26 UTC (rev 97)
+++ branches/xafix/src/jar/resolver/java/org/mulgara/resolver/AnswerOperation.java	2006-10-10 10:50:08 UTC (rev 98)
@@ -0,0 +1,70 @@
+package org.mulgara.resolver;
+
+public abstract class AnswerOperation {
+  // Should use enum here.
+  public static final int OBJECT = 1;
+  public static final int INT = 2;
+  public static final int LONG = 3;
+  public static final int Boolean = 3;
+
+  protected int returnType;
+
+  protected Object object;
+  protected int integer;
+  protected long longint;
+  protected boolean bool;
+
+  public abstract void execute();
+
+  protected void returnObject(Object object) {
+    returnType = OBJECT;
+    this.object = object;
+  }
+
+  protected void returnInt(int integer) {
+    returnType = INT;
+    this.integer = integer;
+  }
+
+  protected void returnLong(long longint) {
+    returnType = LONG;
+    this.longint = longint;
+  }
+
+  protected void returnBoolean(boolean bool) {
+    returnType = BOOLEAN;
+    this.bool = bool;
+  }
+
+  public AnswerOperationResult getResult() {
+    return new AnswerOperationResult() {
+        public Object getObject() {
+          if (returnType != OBJECT) {
+            throw new IllegalStateException("Invalid return type accessed: " returnType);
+          }
+          return object;
+        }
+
+        public int getInt() {
+          if (returnType != INT) {
+            throw new IllegalStateException("Invalid return type accessed: " returnType);
+          }
+          return integer;
+        }
+
+        public long getLong() {
+          if (returnType != LONG) {
+            throw new IllegalStateException("Invalid return type accessed: " returnType);
+          }
+          return longint;
+        }
+
+        public boolean getBoolean() {
+          if (returnType != BOOLEAN) {
+            throw new IllegalStateException("Invalid return type accessed: " returnType);
+          }
+          return bool;
+        }
+    }
+  }
+}

Added: branches/xafix/src/jar/resolver/java/org/mulgara/resolver/AnswerOperationResult.java
===================================================================
--- branches/xafix/src/jar/resolver/java/org/mulgara/resolver/AnswerOperationResult.java	2006-10-09 11:00:26 UTC (rev 97)
+++ branches/xafix/src/jar/resolver/java/org/mulgara/resolver/AnswerOperationResult.java	2006-10-10 10:50:08 UTC (rev 98)
@@ -0,0 +1,11 @@
+package org.mulgara.resolver;
+
+public interface AnswerOperationResult {
+  public Object getObject();
+
+  public int getInt();
+
+  public long getLong();
+
+  public boolean getBoolean();
+}

Modified: branches/xafix/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java
===================================================================
--- branches/xafix/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java	2006-10-09 11:00:26 UTC (rev 97)
+++ branches/xafix/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java	2006-10-10 10:50:08 UTC (rev 98)
@@ -51,37 +51,45 @@
   private int using;
 
   public MulgaraTransaction() { 
-    inuse = 1;
+    inuse = 1; // Note: This implies implict activation as a part of construction.
     using = 0;
   }
 
-  public void activate() {
-    synchronized(this) {
-      if (!currentThread.equals(Thread.currentThread())) {
-        throw new MulgaraTransactionException("Concurrent access attempted to transaction");
-      }
+  public synchronized void activate() throws MulgaraTransactionException {
+    if (currentThread == null) {
+      currentThread = Thread.currentThread();
+    } else if (!currentThread.equals(Thread.currentThread())) {
+      throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
     }
 
     if (inuse == 0) {
-      TransactionManager.resume(transaction);
+      try {
+        TransactionManager.resume(transaction);
+      } catch (Throwable th) {
+        logger.warn("Error resuming transaction: ", th);
+        failTransaction();
+        throw new MulgaraTransactionException("Error resuming transaction", th);
     }
+
     inuse++;
   }
 
-  public void deactivate() {
+  public synchronized void deactivate() {
+
     inuse--;
+
+    if (inuse < 0) {
+      implicitRollback();
+      throw new MulgaraTransactionException("Mismatched activate/deactivate.  inuse < 0: " + inuse);
+    }
+
     if (inuse == 0) {
       if (using == 0) {
         TransactionManager.commit(transaction);
-        synchronized (this) {
-          currentThread = null;
-        }
       } else {
         TransactionManager.suspend(transaction);
-        synchronized (this) {
-          currentThread = null;
-        }
       }
+      currentThread = null;
     }
   }
 
@@ -106,4 +114,17 @@
       deactivate();
     }
   }
+
+
+  public AnswerOperationResult execute(AnswerOperation ao) {
+    activate();
+    try {
+      ao.execute();
+      return ao.getResult();
+    } catch (Throwable th) {
+      implicitRollback(th);
+    } finally {
+      deactivate();
+    }
+  }
 }

Modified: branches/xafix/src/jar/resolver/java/org/mulgara/resolver/TransactionalAnswer.java
===================================================================
--- branches/xafix/src/jar/resolver/java/org/mulgara/resolver/TransactionalAnswer.java	2006-10-09 11:00:26 UTC (rev 97)
+++ branches/xafix/src/jar/resolver/java/org/mulgara/resolver/TransactionalAnswer.java	2006-10-10 10:50:08 UTC (rev 98)
@@ -43,145 +43,125 @@
  *
  * @licence Open Software License v3.0</a>
  */
+
 public class TransactionalAnswer implements Answer {
 
   private Answer answer;
 
   private Thread currentThread;
 
-  public TransactionalAnswer(Answer answer) {
+  public TransactionalAnswer(MulgaraTransaction transaction, Answer answer) {
     this.answer = answer;
+    this.transaction = transaction;
+    transaction.reference();
   }
 
-  public Object getObject(int column) throws TuplesException {
-    pre();
-    try {
-      return answer.getObject(column);
-    } finally {
-      post();
-    }
+  public Object getObject(final int column) throws TuplesException {
+    return transaction.execute(new AnswerOperation() {
+        public void execute() {
+          returnObject(answer.getObject(column));
+        }
+      }).getObject();
   }
 
-  public Object getObject(String columnName) throws TuplesException {
-    pre();
-    try {
-      return answer.getObject(columnName);
-    } finally {
-      post();
-    }
+  public Object getObject(final String columnName) throws TuplesException {
+    return transaction.execute(new AnswerOperation() {
+        public void execute() {
+          returnObject(answer.getObject(columnName));
+        }
+      });
   }
 
   public void beforeFirst() throws TuplesException {
-    pre();
-    try {
-      answer.beforeFirst();
-    } finally {
-      post();
-    }
+    transaction.execute(new AnswerOperation() {
+        public void execute() {
+          answer.beforeFirst();
+        }
+      });
   }
 
   public void close() throws TuplesException {
-    pre();
-    try {
-      answer.close();
-    } finally {
-      post();
-    }
+    transaction.execute(new AnswerOperation() {
+        public void execute() {
+          answer.close();
+          transaction.dereference();
+        }
+      });
   }
 
-  public int getColumnIndex(Variable column) throws TuplesException {
-    pre();
-    try {
-      return answer.getColumnIndex(column);
-    } finally {
-      post();
-    }
+  public int getColumnIndex(final Variable column) throws TuplesException {
+    return transaction.execute(new AnswerOperation() {
+        public void execute() {
+          returnInt(answer.getColumnIndex(column));
+        }
+      }).getInt();
   }
 
   public int getNumberOfVariables() {
-    pre();
-    try {
-      return answer.getNumberOfVariables();
-    } finally {
-      post();
-    }
+    return transaction.execute(new AnswerOperation() {
+        public void execute() {
+          returnInt(answer.getNumberOfVariables());
+        }
+      }).getInt();
   }
 
   public Variable[] getVariables() {
-    pre();
-    try {
-      return answer.getVariables();
-    } finally {
-      post();
-    }
+    return (Variable[])transaction.execute(new AnswerOperation() {
+        public void execute() {
+          returnObject(answer.getVariables());
+        }
+      }).getObject();
   }
 
   public boolean isUnconstrained() throws TuplesException {
-    pre();
-    try {
-      return answer.isUnconstrained();
-    } finally {
-      post();
-    }
+    return (Variable[])transaction.execute(new AnswerOperation() {
+        public void execute() {
+          returnBoolean(answer.isUnconstrained());
+        }
+      }).getBoolean();
   }
 
   public long getRowCount() throws TuplesException {
-    pre();
-    try {
-      return answer.getRowCount();
-    } finally {
-      post();
-    }
+    return (Variable[])transaction.execute(new AnswerOperation() {
+        public void execute() {
+          returnLong(answer.getRowCount());
+        }
+      }).getLong();
   }
 
   public long getRowUpperBound() throws TuplesException {
-    pre();
-    try {
-      return answer.getRowUpperBound();
-    } finally {
-      post();
-    }
+    return (Variable[])transaction.execute(new AnswerOperation() {
+        public void execute() {
+          returnLong(answer.getRowUpperBound());
+        }
+      }).getLong();
   }
 
   public int getRowCardinality() throws TuplesException {
-    pre();
-    try {
-      return answer.getRowCardinality();
-    } finally {
-      post();
-    }
+    return transaction.execute(new AnswerOperation() {
+        public void execute() {
+          returnInt(answer.getRowCardinality());
+        }
+      }).getInt();
   }
 
   public boolean next() throws TuplesException {
-    pre();
-    try {
-      return answer.next();
-    } finally {
-      post();
-    }
+    return (Variable[])transaction.execute(new AnswerOperation() {
+        public void execute() {
+          returnBoolean(answer.next());
+        }
+      }).getBoolean();
   }
 
   public Object clone() {
     try {
       TransactionalAnswer c = (TransactionalAnswer)super.clone();
       c.answer = (Answer)this.answer.clone();
+      c.transaction.reference();
 
       return c;
     } catch (CloneNotSupportedException ec) {
       throw new IllegalStateException("Clone failed on Cloneable");
     }
   }
-
-  public void pre() {
-    // TM.obtainTransaction();
-    if (this.currentThread == null) {
-      this.currentThread = Thread.currentThread();
-    } else if (!Thread.currentThread().equals(this.currentThread)) {
-      throw new IllegalStateException("Concurrent access to TransactionalAnswer forbidded");
-    }
-  }
-
-  public void post() {
-    // TM.releaseTransaction();
-  }
 }




More information about the Mulgara-svn mailing list