[Mulgara-svn] r1457 - in trunk: . conf/core src/jar/jrdf/java/org/mulgara/jrdf src/jar/query/java/org/mulgara/query src/jar/querylang/java/org/mulgara/itql src/jar/querylang/java/org/mulgara/protocol/http src/jar/querylang/java/org/mulgara/sparql src/jar/querylang/sablecc src/jar/resolver/java/org/mulgara/resolver src/jar/resolver-lucene/java/org/mulgara/resolver/lucene src/jar/resolver-memory/java/org/mulgara/resolver/memory src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype src/jar/resolver-null/java/org/mulgara/resolver/nullres src/jar/resolver-prefix/java/org/mulgara/resolver/prefix src/jar/resolver-spi/java/org/mulgara/resolver/spi src/jar/resolver-spi/java/org/mulgara/store/statement src/jar/resolver-store/java/org/mulgara/resolver/store src/jar/resolver-store/java/org/mulgara/store/statement src/jar/resolver-store/java/org/mulgara/store/statement/xa src/jar/resolver-store/java/org/mulgara/store/statement/xa11 src/jar/store-stringpool-memory/java/org/mulgara/store/stringpool/memory src/jar/store-stringpool-xa11/java/org/mulgara/store/stringpool/xa11 src/jar/store-xa/java/org/mulgara/store/xa src/jar/tuples/java/org/mulgara/store/tuples src/jar/util-xa/java/org/mulgara/store/xa

pag at mulgara.org pag at mulgara.org
Sat Jan 24 07:03:53 UTC 2009


Author: pag
Date: 2009-01-23 23:03:51 -0800 (Fri, 23 Jan 2009)
New Revision: 1457

Added:
   trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/XA11StatementStoreResolverFactory.java
   trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/
   trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java
   trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java
   trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java
   trunk/src/jar/resolver/java/org/mulgara/resolver/TuplesBasedOperation.java
   trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedStoreAppend.java
Removed:
   trunk/src/jar/query/java/org/mulgara/query/ConstraintNegation.java
   trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolution.java
   trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolutionUnitTest.java
   trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreInverseResolution.java
   trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java
   trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java
   trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java
Modified:
   trunk/.project
   trunk/conf/core/mulgara-x-config.xml
   trunk/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphUnitTest.java
   trunk/src/jar/querylang/java/org/mulgara/itql/ConstraintExpressionBuilder.java
   trunk/src/jar/querylang/java/org/mulgara/itql/ItqlInterpreterBeanUnitTest.java
   trunk/src/jar/querylang/java/org/mulgara/protocol/http/ProtocolServlet.java
   trunk/src/jar/querylang/java/org/mulgara/protocol/http/SparqlServlet.java
   trunk/src/jar/querylang/java/org/mulgara/protocol/http/TqlServlet.java
   trunk/src/jar/querylang/java/org/mulgara/sparql/IdentityTransformer.java
   trunk/src/jar/querylang/sablecc/itql.grammar
   trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndexTuples.java
   trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneTransformer.java
   trunk/src/jar/resolver-memory/java/org/mulgara/resolver/memory/MemoryResolver.java
   trunk/src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype/TuplesWrapperResolution.java
   trunk/src/jar/resolver-null/java/org/mulgara/resolver/nullres/NullResolution.java
   trunk/src/jar/resolver-prefix/java/org/mulgara/resolver/prefix/TuplesWrapperResolution.java
   trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/ReresolvableResolution.java
   trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/SystemResolver.java
   trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStore.java
   trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreAbstractUnitTest.java
   trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreException.java
   trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolution.java
   trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java
   trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolverFactory.java
   trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/TripleAVLFile.java
   trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImpl.java
   trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImplUnitTest.java
   trunk/src/jar/resolver/java/org/mulgara/resolver/BackupOperation.java
   trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java
   trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java
   trunk/src/jar/resolver/java/org/mulgara/resolver/OutputOperation.java
   trunk/src/jar/resolver/java/org/mulgara/resolver/RestoreOperation.java
   trunk/src/jar/store-stringpool-memory/java/org/mulgara/store/stringpool/memory/MemoryStringPoolImpl.java
   trunk/src/jar/store-stringpool-xa11/java/org/mulgara/store/stringpool/xa11/XA11StringPoolImpl.java
   trunk/src/jar/store-xa/java/org/mulgara/store/xa/XAStatementStore.java
   trunk/src/jar/tuples/java/org/mulgara/store/tuples/AbstractTuples.java
   trunk/src/jar/tuples/java/org/mulgara/store/tuples/DefinablePrefixAnnotation.java
   trunk/src/jar/tuples/java/org/mulgara/store/tuples/LeftJoin.java
   trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedAppend.java
   trunk/src/jar/tuples/java/org/mulgara/store/tuples/Tuples.java
   trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperations.java
   trunk/src/jar/tuples/java/org/mulgara/store/tuples/WrappedTuples.java
   trunk/src/jar/util-xa/java/org/mulgara/store/xa/AVLNode.java
Log:
Merging XA1.1 branch into trunk. Keeping the default configuration at XA 1

Modified: trunk/.project
===================================================================
--- trunk/.project	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/.project	2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
-	<name>Mulgara-trunk</name>
+	<name>mulgara</name>
 	<comment></comment>
 	<projects>
 	</projects>

Modified: trunk/conf/core/mulgara-x-config.xml
===================================================================
--- trunk/conf/core/mulgara-x-config.xml	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/conf/core/mulgara-x-config.xml	2009-01-24 07:03:51 UTC (rev 1457)
@@ -26,7 +26,14 @@
           all interfaces
   -->
   <Jetty>
-    <Disabled>true</Disabled>
+    <Disabled>false</Disabled>
+    <Connector>
+      <!--<Host>localhost</Host>-->
+      <Port>8080</Port>
+      <Acceptors>5</Acceptors>
+      <MaxIdleTimeMs>60000</MaxIdleTimeMs>
+      <LowResourceMaxIdleTimeMs>5000</LowResourceMaxIdleTimeMs>
+    </Connector>
   </Jetty>
 
   <!-- The name of the server, used for RMI binding -->
@@ -81,11 +88,11 @@
     and resolvers.  The persistent resolver is used to manipulate the system
     model.
   -->
-  <PersistentNodePoolFactory type="org.mulgara.store.nodepool.xa.XANodePoolFactory" dir="xaNodePool"/>
+  <PersistentNodePoolFactory type="org.mulgara.store.stringpool.xa11.XA11StringPoolFactory" dir="xaStringPool"/>
   <TemporaryNodePoolFactory  type="org.mulgara.store.nodepool.memory.MemoryNodePoolFactory"/>
-  <PersistentStringPoolFactory type="org.mulgara.store.stringpool.xa.XAStringPoolFactory" dir="xaStringPool"/>
+  <PersistentStringPoolFactory type="org.mulgara.store.stringpool.xa11.XA11StringPoolFactory" dir="xaStringPool"/>
   <TemporaryStringPoolFactory type="org.mulgara.store.stringpool.memory.MemoryStringPoolFactory"/>
-  <PersistentResolverFactory type="org.mulgara.resolver.store.StatementStoreResolverFactory" dir="xaStatementStore"/>
+  <PersistentResolverFactory type="org.mulgara.resolver.store.XA11StatementStoreResolverFactory" dir="xaStatementStore"/>
   <TemporaryResolverFactory type="org.mulgara.resolver.memory.MemoryResolverFactory" dir="tempStatementStore"/>
 
   <!--
@@ -98,6 +105,8 @@
     types.
   -->
   <DefaultContentHandler type="org.mulgara.content.rdfxml.RDFXMLContentHandler"/>
+  <ContentHandler type="org.mulgara.content.mp3.MP3ContentHandler"/>
+  <ContentHandler type="org.mulgara.content.mbox.MBoxContentHandler"/>
   <ContentHandler type="org.mulgara.content.n3.N3ContentHandler"/>
 
   <!--
@@ -108,7 +117,9 @@
   <ResolverFactory type="org.mulgara.resolver.xsd.XSDResolverFactory"/>
   <ResolverFactory type="org.mulgara.resolver.http.HttpResolverFactory"/>
   <ResolverFactory type="org.mulgara.resolver.nodetype.NodeTypeResolverFactory"/>
+  <ResolverFactory type="org.mulgara.resolver.jar.JarResolverFactory"/>
   <ResolverFactory type="org.mulgara.resolver.view.ViewResolverFactory"/>
+  <ResolverFactory type="org.mulgara.resolver.filesystem.FileSystemResolverFactory"/>
   <ResolverFactory type="org.mulgara.resolver.prefix.PrefixResolverFactory"/>
   <ResolverFactory type="org.mulgara.resolver.relational.RelationalResolverFactory"/>
   <ResolverFactory type="org.mulgara.resolver.distributed.DistributedResolverFactory"/>

Modified: trunk/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphUnitTest.java
===================================================================
--- trunk/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphUnitTest.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphUnitTest.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -111,8 +111,8 @@
     }
 
     //reset model
-    this.dropModel(this.modelURI);
-    this.createModel(this.modelURI);
+    this.dropModel(modelURI);
+    this.createModel(modelURI);
 
     //create and return graph
     graph = new JRDFGraph(session, modelURI);
@@ -246,19 +246,18 @@
     try {
 
       String hostname = InetAddress.getLocalHost().getCanonicalHostName();
-      this.serverURI = new URI("rmi", hostname, "/" + SERVER_NAME, null);
-      this.modelURI = new URI("rmi", hostname, "/" + SERVER_NAME, MODEL_NAME);
+      serverURI = new URI("rmi", hostname, "/" + SERVER_NAME, null);
+      modelURI = new URI("rmi", hostname, "/" + SERVER_NAME, MODEL_NAME);
 
       SessionFactory sessionFactory = SessionFactoryFinder.newSessionFactory(serverURI, false);
       this.session = (LocalJRDFSession) sessionFactory.newJRDFSession();
 
       //initialize model
-      this.createModel(this.modelURI);
+      this.createModel(modelURI);
 
       //let superclass set up too
       super.setUp();
-    }
-    catch (Exception exception) {
+    } catch (Exception exception) {
 
       exception.printStackTrace();
 
@@ -266,11 +265,11 @@
       try {
 
         tearDown();
+      } catch (Throwable t) {
+        logger.error("Encountered exception in exception handler. Ignoring.", t);
       }
-      finally {
 
-        throw exception;
-      }
+      throw exception;
     }
   }
 
@@ -281,7 +280,7 @@
    */
   public void tearDown() throws Exception {
 
-    this.dropModel(this.modelURI);
+    this.dropModel(modelURI);
 
     //close the graph
     if (graph != null) {

Deleted: trunk/src/jar/query/java/org/mulgara/query/ConstraintNegation.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/query/ConstraintNegation.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/query/java/org/mulgara/query/ConstraintNegation.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,185 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is the Kowari Metadata Store.
- *
- * The Initial Developer of the Original Code is Plugged In Software Pty
- * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
- * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
- * Plugged In Software Pty Ltd. All Rights Reserved.
- *
- * Contributor(s):
- *   getModel() contributed by Netymon Pty Ltd on behalf of
- *   The Australian Commonwealth Government under contract 4500507038.
- *
- * [NOTE: The text of this Exhibit A may differ slightly from the text
- * of the notices in the Source Code files of the Original Code. You
- * should use the text of this Exhibit A rather than the text found in the
- * Original Code Source Code for Your Modifications.]
- *
- */
-
-package org.mulgara.query;
-
-import java.util.*;
-
-// Third party packages
-// import org.apache.log4j.Logger;
-
-/**
- * A constraint expression composed of the negation (logical NOT) of one
- * subexpressions.
- *
- * @created 2001-10-29
- *
- * @author <a href="http://staff.pisoftware.com/raboczi">Simon Raboczi</a>
- *
- * @version $Revision: 1.9 $
- *
- * @modified $Date: 2005/05/29 08:32:39 $
- *
- * @maintenanceAuthor $Author: raboczi $
- *
- * @company <A href="mailto:info at PIsoftware.com">Plugged In Software</A>
- *
- * @copyright &copy; 2001-2003 <A href="http://www.PIsoftware.com/">Plugged In
- *      Software Pty Ltd</A>
- *
- * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
- */
-public class ConstraintNegation implements Constraint {
-
-  // /** The logger */
-  // private final static Logger logger = Logger.getLogger(ConstraintNegation.class.getName());
-
-  /**
-   * Allow newer compiled version of the stub to operate when changes
-   * have not occurred with the class.
-   * NOTE : update this serialVersionUID when a method or a public member is
-   * deleted.
-   */
-  private static final long serialVersionUID = 9147228997817064907L;
-
-  /**
-   * The negated expression.
-   */
-  private Constraint constraint;
-
-  //
-  // Constructor
-  //
-
-  /**
-   * Construct a constraint negation.
-   *
-   * @param constraint  a non-<code>null</code> constraint
-   * @throws IllegalArgumentException if <var>constraint</var> is
-   *   <code>null</code>
-   */
-  public ConstraintNegation(Constraint constraint) {
-
-    // Validate "expression" parameter
-    if (constraint == null) {
-
-      throw new IllegalArgumentException("Null \"constraint\" parameter");
-    }
-
-    // Initialize fields
-    this.constraint = constraint;
-  }
-
-  public boolean isRepeating() {
-    return false;
-  }
-
-
-  /**
-   * Get a constraint element by index.
-   *
-   * @param index The constraint element to retrieve, from 0 to 3.
-   * @return The constraint element referred to by index.
-   */
-  public ConstraintElement getElement(int index) {
-    return constraint.getElement(index);
-  }
-
-  public ConstraintElement getModel() {
-    return constraint.getModel();
-  }
-
-
-  /**
-   * Get all constraints which are variables. For back-compatibility, this
-   * method currently ignores the fourth element of the triple.
-   *
-   * @return A set containing all variable constraints.
-   */
-  public Set<Variable> getVariables() {
-    return constraint.getVariables();
-  }
-
-
-  /**
-   * tests if the inner constraint is a ConstraintIs.
-   *
-   * @return <code>true</code> if the inner constraint is a ConstraintIs class.
-   */
-  public boolean isInnerConstraintIs() {
-    return constraint instanceof ConstraintIs;
-  }
-
-  /**
-   * Convert this object to a string.
-   *
-   * @return A string representation of this object.
-   */
-  public String toString() {
-    return "not " + constraint;
-  }
-
-  /**
-   * Creates a relatively unique value representing this constraint.
-   *
-   * @return A numerical combination of the elements and the anchor
-   */
-  public int hashCode() {
-    return constraint.hashCode() * -1;
-  }
-
-  /**
-   * Equality is by value.
-   *
-   * @param object PARAMETER TO DO
-   * @return RETURNED VALUE TO DO
-   */
-  public boolean equals(Object object) {
-
-    if (object == null) {
-      return false;
-    }
-
-    if (object == this) {
-      return true;
-    }
-
-    boolean returnValue = false;
-
-    // Check that the given object is the correct class if so check each
-    // element.
-    if (object.getClass().equals(ConstraintNegation.class)) {
-
-      ConstraintNegation tmpConstraint = (ConstraintNegation) object;
-      returnValue = constraint.equals(tmpConstraint.constraint);
-    }
-
-    return returnValue;
-  }
-}

Modified: trunk/src/jar/querylang/java/org/mulgara/itql/ConstraintExpressionBuilder.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/itql/ConstraintExpressionBuilder.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/querylang/java/org/mulgara/itql/ConstraintExpressionBuilder.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -169,11 +169,6 @@
         tmpConstraint = ConstraintFactory.newConstraint(subject, predicate, object);
       }
 
-      // handle negated constraints
-      if (((AConstraintConstraintFactor) rawConstraintFactor).getExclude() != null) {
-        tmpConstraint = new ConstraintNegation(tmpConstraint);
-      }
-
       // Set new value.
       if (logger.isDebugEnabled()) logger.debug("Setting constraint: " + tmpConstraint);
 
@@ -209,14 +204,7 @@
       ConstraintExpressionBuilder builder = new ConstraintExpressionBuilder(interpreter);
       embeddedConstraintExpression.apply((Switch) builder);
 
-      tmpConstraintExpression = builder.getConstraintExpression();
-
-      // handle negated expressions
-      if (((AExpressionConstraintFactor) rawConstraintFactor).getExclude() != null) {
-        tmpConstraintExpression = new ConstraintNegation((Constraint)tmpConstraintExpression);
-      }
-
-      setConstraintExpression(tmpConstraintExpression);
+      setConstraintExpression(builder.getConstraintExpression());
     } catch (URISyntaxException use) {
       uriException = use;
     } catch (QueryException qe) {

Modified: trunk/src/jar/querylang/java/org/mulgara/itql/ItqlInterpreterBeanUnitTest.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/itql/ItqlInterpreterBeanUnitTest.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/querylang/java/org/mulgara/itql/ItqlInterpreterBeanUnitTest.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -32,6 +32,7 @@
 import org.mulgara.server.SessionFactory;
 import org.mulgara.server.driver.SessionFactoryFinder;
 import org.mulgara.util.Rmi;
+import org.mulgara.util.StackTrace;
 import org.mulgara.util.TempDir;
 
 // third party packages
@@ -91,7 +92,7 @@
   private ItqlInterpreterBean bean = null;
 
   /** host name of server */
-  private static String hostName = System.getProperty("host.name");
+  private static String hostName = System.getProperty("host.name", "localhost");
 
   /** an example model */
   private static String testModel = "rmi://" + hostName + "/server1#itqlmodel";
@@ -617,15 +618,25 @@
     // log that we're executing the test
     log.debug("Starting backup API test 2");
 
-    File file = new File(tmpDirectory, "server.gz");
-    file.delete();
+    try {
+      File file = new File(tmpDirectory, "server.gz");
+      file.delete();
+  
+      URI serverURI = new URI("rmi://localhost/server1");
+  
+      bean.backup(serverURI, file);
+  
+      assertTrue("Excepting a backup file", file.exists());
+    } catch (QueryException e) {
+      System.err.println("Error processing query" + e);
+      Throwable t = e.getCause();
+      while (t != null) {
+        System.err.println("Caused by: " + t + StackTrace.throwableToString(t));
+        t = t.getCause();
+      }
+      throw e;
+    }
 
-    URI serverURI = new URI("rmi://localhost/server1");
-
-    bean.backup(serverURI, file);
-
-    assertTrue("Excepting a backup file", file.exists());
-
   }
 
   /**
@@ -639,15 +650,25 @@
     // log that we're executing the test
     log.debug("Starting backup API test 4");
 
-    File file = new File(tmpDirectory, "server2.gz");
-    file.delete();
-
-    URI serverURI = new URI("rmi://localhost/server1");
-
-    bean.backup(serverURI, new FileOutputStream(file));
-
-    assertTrue("Excepting a backup file", file.exists());
-
+    try {
+      File file = new File(tmpDirectory, "server2.gz");
+      file.delete();
+  
+      URI serverURI = new URI("rmi://localhost/server1");
+  
+      bean.backup(serverURI, new FileOutputStream(file));
+  
+      assertTrue("Excepting a backup file", file.exists());
+    } catch (QueryException e) {
+      System.err.println("Error processing query" + e);
+      Throwable t = e.getCause();
+      while (t != null) {
+        System.err.println("Caused by: " + t + StackTrace.throwableToString(t));
+        t = t.getCause();
+      }
+      throw e;
+    }
+  
   }
 
   /**
@@ -700,18 +721,27 @@
    *
    * @throws Exception if the test fails
    */
-  @SuppressWarnings("deprecation")
   public void testRestoreApi1() throws Exception {
 
     // log that we're executing the test
     log.debug("Starting restore API test 1");
 
-    File file = new File(tmpDirectory, "server2.gz");
+    try {
+      File file = new File(tmpDirectory, "server2.gz");
+  
+      URI serverURI = new URI("rmi://localhost/server1");
+  
+      bean.restore(file.toURL().openStream(), serverURI);
+    } catch (QueryException e) {
+      System.err.println("Error processing query" + e);
+      Throwable t = e.getCause();
+      while (t != null) {
+        System.err.println("Caused by: " + t + StackTrace.throwableToString(t));
+        t = t.getCause();
+      }
+      throw e;
+    }
 
-    URI serverURI = new URI("rmi://localhost/server1");
-
-    bean.restore(file.toURL().openStream(), serverURI);
-
   }
 
   /**
@@ -721,58 +751,67 @@
    *
    * @throws Exception if the test fails
    */
-  @SuppressWarnings("deprecation")
   public void testRoundTrip1() throws Exception {
 
-    // log that we're executing the test
-    log.debug("Starting round trip test 1");
+    try {
+      // log that we're executing the test
+      log.debug("Starting round trip test 1");
+  
+      URI serverURI = new URI("rmi://" + hostName + "/server1");
+  
+      // test the output
+      String select = "select $o from <" + testModel + "> " +
+          "where <rmi://" + hostName +
+          "/server1> <http://purl.org/dc/elements/1.1/creator> $o or " +
+          " <rmi://" + hostName +
+          "/foobar> <http://purl.org/dc/elements/1.1/creator> $o or " +
+          " <rmi://" + hostName +
+          "/server1/foobar> <http://purl.org/dc/elements/1.1/creator> $o ;";
+  
+      // insert statements with a subject the same as the
+      // server name
+      String insert = "insert " +
+          "<rmi://" + hostName +
+          "/server1> <http://purl.org/dc/elements/1.1/creator> 'foo' " +
+          "<rmi://" + hostName +
+          "/foobar> <http://purl.org/dc/elements/1.1/creator> 'foobar' " +
+          "<rmi://" + hostName +
+          "/server1/foobar> <http://purl.org/dc/elements/1.1/creator> 'server1/foobar' " +
+          " into <" + testModel + ">;";
+  
+      // insert the statement
+      bean.executeQuery(insert);
+  
+      // select the statement
+      Answer answer = bean.executeQuery(select);
+      assertTrue("Excepting a answer before restore", answer != null);
+      assertTrue("Excepting a single result and found :" +
+          answer.getRowCount(), (answer.getRowCount() == 3));
+  
+      //backup the server
+      File file = new File(tmpDirectory, "roundtrip.gz");
+      file.delete();
+      bean.backup(serverURI, new FileOutputStream(file));
+      assertTrue("Excepting a backup file", file.exists());
+  
+      // restore the server
+      bean.restore(file.toURL().openStream(), serverURI);
+  
+      // select the statement
+      answer = bean.executeQuery(select);
+      assertTrue("Excepting a answer after restore", answer != null);
+      assertTrue("Excepting a single result and found :" +
+          answer.getRowCount(), (answer.getRowCount() == 3));
+    } catch (QueryException e) {
+      System.err.println("Error processing query" + e);
+      Throwable t = e.getCause();
+      while (t != null) {
+        System.err.println("Caused by: " + t + StackTrace.throwableToString(t));
+        t = t.getCause();
+      }
+      throw e;
+    }
 
-    URI serverURI = new URI("rmi://" + hostName + "/server1");
-
-    // test the output
-    String select = "select $o from <" + testModel + "> " +
-        "where <rmi://" + hostName +
-        "/server1> <http://purl.org/dc/elements/1.1/creator> $o or " +
-        " <rmi://" + hostName +
-        "/foobar> <http://purl.org/dc/elements/1.1/creator> $o or " +
-        " <rmi://" + hostName +
-        "/server1/foobar> <http://purl.org/dc/elements/1.1/creator> $o ;";
-
-    // insert statements with a subject the same as the
-    // server name
-    String insert = "insert " +
-        "<rmi://" + hostName +
-        "/server1> <http://purl.org/dc/elements/1.1/creator> 'foo' " +
-        "<rmi://" + hostName +
-        "/foobar> <http://purl.org/dc/elements/1.1/creator> 'foobar' " +
-        "<rmi://" + hostName +
-        "/server1/foobar> <http://purl.org/dc/elements/1.1/creator> 'server1/foobar' " +
-        " into <" + testModel + ">;";
-
-    // insert the statement
-    bean.executeQuery(insert);
-
-    // select the statement
-    Answer answer = bean.executeQuery(select);
-    assertTrue("Excepting a answer before restore", answer != null);
-    assertTrue("Excepting a single result and found :" +
-        answer.getRowCount(), (answer.getRowCount() == 3));
-
-    //backup the server
-    File file = new File(tmpDirectory, "roundtrip.gz");
-    file.delete();
-    bean.backup(serverURI, new FileOutputStream(file));
-    assertTrue("Excepting a backup file", file.exists());
-
-    // restore the server
-    bean.restore(file.toURL().openStream(), serverURI);
-
-    // select the statement
-    answer = bean.executeQuery(select);
-    assertTrue("Excepting a answer after restore", answer != null);
-    assertTrue("Excepting a single result and found :" +
-        answer.getRowCount(), (answer.getRowCount() == 3));
-
   }
 
   /**

Modified: trunk/src/jar/querylang/java/org/mulgara/protocol/http/ProtocolServlet.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/http/ProtocolServlet.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/http/ProtocolServlet.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -21,6 +21,7 @@
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.Collections;
+import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -84,16 +85,13 @@
   private static final String QUERY_ARG = "query";
 
   /** The parameter identifying the output type. */
-  protected static final String OUTPUT_ARG = "out";
+  protected static final String OUTPUT_ARG = "format";
 
-  /** The output parameter value for indicating JSON output. */
-  protected static final String OUTPUT_JSON = "json";
+  /** The header name for accepted mime types. */
+  protected static final String ACCEPT_HEADER = "Accept";
 
-  /** The output parameter value for indicating XML output. */
-  protected static final String OUTPUT_XML = "xml";
-
   /** The default output type to use. */
-  protected static final String DEFAULT_OUTPUT_TYPE = OUTPUT_XML;
+  protected static final Output DEFAULT_OUTPUT_TYPE = Output.XML;
 
   /** The parameter identifying the graph. */
   protected static final String DEFAULT_GRAPH_ARG = "default-graph-uri";
@@ -138,10 +136,10 @@
   private SessionFactory cachedSessionFactory;
 
   /** This object maps request types to the constructors for that output. */
-  protected final Map<String,AnswerStreamConstructor> streamBuilders = new HashMap<String,AnswerStreamConstructor>();
+  protected final Map<Output,AnswerStreamConstructor> streamBuilders = new EnumMap<Output,AnswerStreamConstructor>(Output.class);
 
   /** This object maps request types to the constructors for sending objects to that output. */
-  protected final Map<String,ObjectStreamConstructor> objectStreamBuilders = new HashMap<String,ObjectStreamConstructor>();
+  protected final Map<Output,ObjectStreamConstructor> objectStreamBuilders = new EnumMap<Output,ObjectStreamConstructor>(Output.class);
 
   /**
    * Creates the servlet for communicating with the given server.
@@ -170,7 +168,7 @@
   
       Answer result = executeQuery(query, req);
 
-      String outputType = req.getParameter(OUTPUT_ARG);
+      Output outputType = getOutputType(req);
       sendAnswer(result, outputType, resp);
 
       try {
@@ -294,7 +292,7 @@
    * @throws BadRequestException Due to a bad protocol type.
    * @throws InternalErrorException Due to an error accessing the answer.
    */
-  void sendAnswer(Answer answer, String outputType, HttpServletResponse resp) throws IOException, BadRequestException, InternalErrorException {
+  void sendAnswer(Answer answer, Output outputType, HttpServletResponse resp) throws IOException, BadRequestException, InternalErrorException {
     send(streamBuilders, answer, outputType, resp);
   }
 
@@ -309,7 +307,7 @@
    * @throws BadRequestException Due to a bad protocol type.
    * @throws InternalErrorException Due to an error accessing the result.
    */
-  void sendStatus(Object result, String outputType, HttpServletResponse resp) throws IOException, BadRequestException, InternalErrorException {
+  void sendStatus(Object result, Output outputType, HttpServletResponse resp) throws IOException, BadRequestException, InternalErrorException {
     send(objectStreamBuilders, result, outputType, resp);
   }
 
@@ -326,13 +324,12 @@
    * @throws BadRequestException Due to a bad protocol type.
    * @throws InternalErrorException Due to an error accessing the answer.
    */
-  <T> void send(Map<String,? extends StreamConstructor<T>> builders, T data, String type, HttpServletResponse resp) throws IOException, BadRequestException, InternalErrorException {
+  <T> void send(Map<Output,? extends StreamConstructor<T>> builders, T data, Output type, HttpServletResponse resp) throws IOException, BadRequestException, InternalErrorException {
     resp.setContentType(CONTENT_TYPE);
     resp.setHeader("pragma", "no-cache");
 
     // establish the output type
     if (type == null) type = DEFAULT_OUTPUT_TYPE;
-    else type = type.toLowerCase();
 
     // get the constructor for the stream outputter
     StreamConstructor<T> constructor = builders.get(type);
@@ -404,7 +401,7 @@
 
     Object result = executeCommand(cmd, req);
 
-    String outputType = req.getParameter(OUTPUT_ARG);
+    Output outputType = getOutputType(req);
     if (result instanceof Answer) {
       sendAnswer((Answer)result, outputType, resp);
     } else {
@@ -544,4 +541,49 @@
     for (String p: knownParams) if (p.equalsIgnoreCase(name)) return true;
     return false;
   }
+
+
+  /**
+   * Determine the type of response we need.
+   * @param req The request object for the servlet connection.
+   * @return xml, json, rdfXml or rdfN3.
+   */
+  private Output getOutputType(HttpServletRequest req) {
+    Output type = DEFAULT_OUTPUT_TYPE;
+
+    // get the accepted types
+    String accepted = req.getHeader(ACCEPT_HEADER);
+    if (accepted != null) {
+      type = Output.forMime(accepted);
+    }
+
+    // check the URI parameters
+    String reqOutputName = req.getParameter(OUTPUT_ARG);
+    if (reqOutputName != null) {
+      Output reqOutput = Output.valueOf(reqOutputName.toUpperCase());
+      if (reqOutput != null) type = reqOutput;
+    }
+    return type;
+  }
+
+
+  /**
+   * Enumeration of the various output types, depending on mime type.
+   */
+  enum Output {
+    XML("application/sparql-results+xml"),
+    JSON("application/sparql-results+json"),
+    RDFXML("application/rdf+xml"),
+    N3("text/rdf+n3");
+
+    final String mimeText;
+    private Output(String mimeText) { this.mimeText = mimeText; }
+
+    static private Map<String,Output> outputs = new HashMap<String,Output>();
+    static {
+      for (Output o: Output.values()) outputs.put(o.mimeText, o);
+    }
+    
+    static Output forMime(String mimeText) { return outputs.get(mimeText); }
+  }
 }

Modified: trunk/src/jar/querylang/java/org/mulgara/protocol/http/SparqlServlet.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/http/SparqlServlet.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/http/SparqlServlet.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -60,9 +60,10 @@
     AnswerStreamConstructor xmlBuilder = new AnswerStreamConstructor() {
       public StreamedAnswer fn(Answer ans, OutputStream s) { return new StreamedSparqlXMLAnswer(ans, s); }
     };
-    streamBuilders.put(OUTPUT_JSON, jsonBuilder);
-    streamBuilders.put(OUTPUT_XML, xmlBuilder);
-    streamBuilders.put(null, xmlBuilder);
+    streamBuilders.put(Output.JSON, jsonBuilder);
+    streamBuilders.put(Output.XML, xmlBuilder);
+    streamBuilders.put(Output.RDFXML, xmlBuilder);  // TODO: create an RDF/XML Builder
+    streamBuilders.put(Output.N3, xmlBuilder);      // TODO: create an N3 Builder
 
     ObjectStreamConstructor jsonObjBuilder = new ObjectStreamConstructor() {
       public StreamedAnswer fn(Object o, OutputStream s) { return new StreamedSparqlJSONObject(o, s); }
@@ -70,9 +71,10 @@
     ObjectStreamConstructor xmlObjBuilder = new ObjectStreamConstructor() {
       public StreamedAnswer fn(Object o, OutputStream s) { return new StreamedSparqlXMLObject(o, s); }
     };
-    objectStreamBuilders.put(OUTPUT_JSON, jsonObjBuilder);
-    objectStreamBuilders.put(OUTPUT_XML, xmlObjBuilder);
-    objectStreamBuilders.put(null, xmlObjBuilder);
+    objectStreamBuilders.put(Output.JSON, jsonObjBuilder);
+    objectStreamBuilders.put(Output.XML, xmlObjBuilder);
+    objectStreamBuilders.put(Output.RDFXML, xmlObjBuilder);  // TODO: create an RDF/XML Object Builder
+    objectStreamBuilders.put(Output.N3, xmlObjBuilder);      // TODO: create an N3 Builder
   }
 
 

Modified: trunk/src/jar/querylang/java/org/mulgara/protocol/http/TqlServlet.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/http/TqlServlet.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/http/TqlServlet.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -62,9 +62,10 @@
     AnswerStreamConstructor xmlBuilder = new AnswerStreamConstructor() {
       public StreamedAnswer fn(Answer ans, OutputStream s) { return new StreamedTqlXMLAnswer(ans, s); }
     };
-    streamBuilders.put(OUTPUT_JSON, jsonBuilder);
-    streamBuilders.put(OUTPUT_XML, xmlBuilder);
-    streamBuilders.put(null, xmlBuilder);
+    streamBuilders.put(Output.JSON, jsonBuilder);
+    streamBuilders.put(Output.XML, xmlBuilder);
+    streamBuilders.put(Output.RDFXML, xmlBuilder);  // TODO: create an RDF/XML builder
+    streamBuilders.put(Output.N3, xmlBuilder);      // TODO: create an N3 builder
 
     ObjectStreamConstructor jsonObjBuilder = new ObjectStreamConstructor() {
       public StreamedAnswer fn(Object o, OutputStream s) { return new StreamedSparqlJSONObject(o, s); }
@@ -72,9 +73,10 @@
     ObjectStreamConstructor xmlObjBuilder = new ObjectStreamConstructor() {
       public StreamedAnswer fn(Object o, OutputStream s) { return new StreamedSparqlXMLObject(o, s); }
     };
-    objectStreamBuilders.put(OUTPUT_JSON, jsonObjBuilder);
-    objectStreamBuilders.put(OUTPUT_XML, xmlObjBuilder);
-    objectStreamBuilders.put(null, xmlObjBuilder);
+    objectStreamBuilders.put(Output.JSON, jsonObjBuilder);
+    objectStreamBuilders.put(Output.XML, xmlObjBuilder);
+    objectStreamBuilders.put(Output.RDFXML, xmlObjBuilder);  // TODO: create an RDF/XML object builder
+    objectStreamBuilders.put(Output.N3, xmlObjBuilder);      // TODO: create an N3 object builder
   }
 
 

Modified: trunk/src/jar/querylang/java/org/mulgara/sparql/IdentityTransformer.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/sparql/IdentityTransformer.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/querylang/java/org/mulgara/sparql/IdentityTransformer.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -32,7 +32,6 @@
 import org.mulgara.query.ConstraintImpl;
 import org.mulgara.query.ConstraintIn;
 import org.mulgara.query.ConstraintIs;
-import org.mulgara.query.ConstraintNegation;
 import org.mulgara.query.ConstraintNotOccurs;
 import org.mulgara.query.ConstraintOccurs;
 import org.mulgara.query.ConstraintOccursLessThan;
@@ -60,7 +59,7 @@
    * Builds a transformer, with identity constructors.
    */
   public IdentityTransformer() {
-    initialize(new ConsImpl(), new ConsIs(), new ConsNegation(),
+    initialize(new ConsImpl(), new ConsIs(),
          new ConsNotOccurs(), new ConsOccurs(), new ConsOccursLessThan(),
          new ConsOccursMoreThan(), new ConsSingleTransitive(),
          new ConsTransitive(), new ConsWalk());
@@ -267,11 +266,6 @@
     public Class<ConstraintIs> getType() { return ConstraintIs.class; }
   }
 
-  protected class ConsNegation implements ConstraintTypeCons<ConstraintNegation> {
-    public ConstraintNegation newConstraint(Constraint c) { throw new IllegalStateException("Negations are no longer supported"); }
-    public Class<ConstraintNegation> getType() { return ConstraintNegation.class; }
-  }
-
   protected class ConsSingleTransitive implements ConstraintTypeCons<SingleTransitiveConstraint> {
     public SingleTransitiveConstraint newConstraint(Constraint c) throws SymbolicTransformationException {
       SingleTransitiveConstraint s = (SingleTransitiveConstraint)c;

Modified: trunk/src/jar/querylang/sablecc/itql.grammar
===================================================================
--- trunk/src/jar/querylang/sablecc/itql.grammar	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/querylang/sablecc/itql.grammar	2009-01-24 07:03:51 UTC (rev 1457)
@@ -47,7 +47,6 @@
   {def}                drop        = 'drop';
   {def}                echo        = 'echo';
   {def}                execute     = 'execute';
-  {def}                exclude     = 'exclude';
   {def}                export      = 'export';
   {def}                from        = 'from';
   {def}                help        = 'help';
@@ -253,10 +252,10 @@
     {minus} [minuend]:constraint_dterm minus [subtrahend]:constraint_factor ;
 
   constraint_factor =
-    {constraint} exclude? constraint                  |
+    {constraint} constraint                  |
     {compound} lbrace [subject]:element exists_expression in_clause? rbrace |
     {existential} lbracket exists_expression in_clause? rbracket |
-    {expression} exclude? lpar constraint_expression rpar |
+    {expression} lpar constraint_expression rpar |
     {transitive} transitive_clause |
     {walk} walk_clause ;
 

Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/BackupOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/BackupOperation.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/BackupOperation.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -163,22 +163,19 @@
         StatementStore.VARIABLES[3]));
     assert tuples != null;
     try {
-      assert tuples.getVariables()[0] == StatementStore.VARIABLES[0];
-      assert tuples.getVariables()[1] == StatementStore.VARIABLES[1];
-      assert tuples.getVariables()[2] == StatementStore.VARIABLES[2];
-      assert tuples.getVariables()[3] == StatementStore.VARIABLES[3];
+      int[] colMap = mapColumnsToStd(tuples.getVariables());
       writer.write("TRIPLES\n");
 
       long preallocationModelNode = metadata.getPreallocationModelNode();
       for (tuples.beforeFirst(); tuples.next(); ) {
         // Suppress output of the preallocation model.
-        long modelNode = tuples.getColumnValue(3);
+        long modelNode = tuples.getColumnValue(colMap[3]);
         if (modelNode != preallocationModelNode) {
-          writer.write(Long.toString(tuples.getColumnValue(0)));
+          writer.write(Long.toString(tuples.getColumnValue(colMap[0])));
           writer.write(' ');
-          writer.write(Long.toString(tuples.getColumnValue(1)));
+          writer.write(Long.toString(tuples.getColumnValue(colMap[1])));
           writer.write(' ');
-          writer.write(Long.toString(tuples.getColumnValue(2)));
+          writer.write(Long.toString(tuples.getColumnValue(colMap[2])));
           writer.write(' ');
           writer.write(Long.toString(modelNode));
           writer.write('\n');

Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -38,18 +38,22 @@
   public void execute(OperationContext       operationContext,
                       SystemResolver         systemResolver,
                       DatabaseMetadata       metadata) throws Exception {
+    if (logger.isDebugEnabled()) logger.debug("Creating bootstrap nodes");
     // Find the local node identifying the model
-    long model = systemResolver.localizePersistent(
+    long graph = systemResolver.localizePersistent(
         new URIReferenceImpl(databaseMetadata.getSystemModelURI()));
     long rdfType = systemResolver.localizePersistent(
         new URIReferenceImpl(databaseMetadata.getRdfTypeURI()));
-    long modelType = systemResolver.localizePersistent(
+    long graphType = systemResolver.localizePersistent(
         new URIReferenceImpl(databaseMetadata.getSystemModelTypeURI()));
 
+    // set up the system resolver to understand the system graph
+    systemResolver.initializeSystemNodes(graph, rdfType, graphType);
+
+    if (logger.isDebugEnabled()) logger.debug("Creating bootstrap statements");
     // Use the session to create the model
-    systemResolver.modifyModel(model, new SingletonStatements(model, rdfType,
-        modelType), true);
-    databaseMetadata.initializeSystemNodes(model, rdfType, modelType);
+    systemResolver.modifyModel(graph, new SingletonStatements(graph, rdfType, graphType), true);
+    databaseMetadata.initializeSystemNodes(graph, rdfType, graphType);
 
     long preSubject = systemResolver.localizePersistent(
         new URIReferenceImpl(databaseMetadata.getPreallocationSubjectURI()));
@@ -60,13 +64,13 @@
 
     // Every node cached by DatabaseMetadata must be preallocated
     systemResolver.modifyModel(preModel,
-        new SingletonStatements(preSubject, prePredicate, model),
+        new SingletonStatements(preSubject, prePredicate, graph),
         true);
     systemResolver.modifyModel(preModel,
         new SingletonStatements(preSubject, prePredicate, rdfType),
         true);
     systemResolver.modifyModel(preModel,
-        new SingletonStatements(preSubject, prePredicate, modelType),
+        new SingletonStatements(preSubject, prePredicate, graphType),
         true);
     systemResolver.modifyModel(preModel,
         new SingletonStatements(preSubject, prePredicate, preSubject),
@@ -80,7 +84,7 @@
 
     databaseMetadata.initializePreallocationNodes(preSubject, prePredicate, preModel);
 
-    result = model;
+    result = graph;
   }
 
   public boolean isWriteOperation()

Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -30,6 +30,7 @@
 // Java 2 standard packages
 import gnu.trove.TIntHashSet;
 import gnu.trove.TIntIterator;
+import gnu.trove.TIntProcedure;
 
 import java.beans.Beans;
 import java.io.File;
@@ -1144,7 +1145,14 @@
     } else {
       TIntHashSet phaseSet = intersectPhaseSets(phaseSets);
       if (phaseSet.isEmpty()) {
-        throw new SimpleXAResourceException("No matching phases between Resource Handlers.");
+        final StringBuilder s = new StringBuilder("[");
+        for (TIntHashSet p: phaseSets) {
+          s.append(" { ");
+          p.forEach(new TIntProcedure() {public boolean execute(int i) { s.append(i).append(" "); return true; }});
+          s.append("}");
+        }
+        s.append(" ]");
+        throw new SimpleXAResourceException("No matching phases between Resource Handlers. Recovery sets: " + s);
       }
 
       selectCommonPhase(highestCommonPhaseNumber(phaseSet), handlers);

Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/OutputOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/OutputOperation.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/OutputOperation.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -27,7 +27,7 @@
  * @copyright &copy; 2008 <a href="http://www.revelytix.com">Revelytix, Inc.</a>
  * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
  */
-public abstract class OutputOperation implements Operation {
+public abstract class OutputOperation extends TuplesBasedOperation implements Operation {
   
   protected final OutputStream outputStream;
   protected final URI destinationURI;

Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/RestoreOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/RestoreOperation.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/RestoreOperation.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -80,8 +80,7 @@
  *   Technology, Inc</a>
  * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
  */
-class RestoreOperation implements BackupConstants, Operation
-{
+class RestoreOperation extends TuplesBasedOperation implements BackupConstants, Operation {
 
   /** Logger.  */
   private static final Logger logger =
@@ -221,23 +220,20 @@
                                      StatementStore.VARIABLES[1],
                                      StatementStore.VARIABLES[2],
                                      StatementStore.VARIABLES[3]));
-    assert tuples.getVariables()[0] == StatementStore.VARIABLES[0];
-    assert tuples.getVariables()[1] == StatementStore.VARIABLES[1];
-    assert tuples.getVariables()[2] == StatementStore.VARIABLES[2];
-    assert tuples.getVariables()[3] == StatementStore.VARIABLES[3];
+    int[] colMap = mapColumnsToStd(tuples.getVariables());
 
     try {
       tuples.beforeFirst();
 
       long preallocationModelNode = metadata.getPreallocationModelNode();
       while (tuples.next()) {
-        long modelNode = tuples.getColumnValue(3);
+        long modelNode = tuples.getColumnValue(colMap[3]);
         if (modelNode != preallocationModelNode) {
           resolver.modifyModel(
               modelNode,
-              new SingletonStatements(tuples.getColumnValue(0),
-                                      tuples.getColumnValue(1),
-                                      tuples.getColumnValue(2)),
+              new SingletonStatements(tuples.getColumnValue(colMap[0]),
+                                      tuples.getColumnValue(colMap[1]),
+                                      tuples.getColumnValue(colMap[2])),
               DatabaseSession.DENY_STATEMENTS
           );
         }
@@ -541,23 +537,20 @@
                                      StatementStore.VARIABLES[1],
                                      StatementStore.VARIABLES[2],
                                      StatementStore.VARIABLES[3]));
-    assert tuples.getVariables()[0] == StatementStore.VARIABLES[0];
-    assert tuples.getVariables()[1] == StatementStore.VARIABLES[1];
-    assert tuples.getVariables()[2] == StatementStore.VARIABLES[2];
-    assert tuples.getVariables()[3] == StatementStore.VARIABLES[3];
+    int[] colMap = mapColumnsToStd(tuples.getVariables());
 
     try {
       tuples.beforeFirst();
 
       long preallocationModelNode = metadata.getPreallocationModelNode();
       while (tuples.next()) {
-        long modelNode = tuples.getColumnValue(3);
+        long modelNode = tuples.getColumnValue(colMap[3]);
         if (modelNode != preallocationModelNode) {
           resolver.modifyModel(
               modelNode,
-              new SingletonStatements(tuples.getColumnValue(0),
-                                      tuples.getColumnValue(1),
-                                      tuples.getColumnValue(2)),
+              new SingletonStatements(tuples.getColumnValue(colMap[0]),
+                                      tuples.getColumnValue(colMap[1]),
+                                      tuples.getColumnValue(colMap[2])),
               DatabaseSession.DENY_STATEMENTS
           );
         }

Copied: trunk/src/jar/resolver/java/org/mulgara/resolver/TuplesBasedOperation.java (from rev 1456, branches/xa11/src/jar/resolver/java/org/mulgara/resolver/TuplesBasedOperation.java)
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/TuplesBasedOperation.java	                        (rev 0)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/TuplesBasedOperation.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -0,0 +1,52 @@
+/*
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+
+package org.mulgara.resolver;
+
+import java.util.Arrays;
+
+import org.mulgara.query.Variable;
+import org.mulgara.store.statement.StatementStore;
+
+/**
+ * Handles mapping of Tuples to expected columns, when necessary.
+ *
+ * @created Jan 23, 2009
+ * @author Paul Gearon
+ * @copyright &copy; 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public abstract class TuplesBasedOperation {
+
+  /**
+   * Check a variable array to see if it is in SPOG or GSPO order, and return a mapping array
+   * to allow the columns to be accessed in SPOG order. If assertions are enabled, then the
+   * entire structure is tested, otherwise the first column is all that is tested.
+   * @param vars The variables to test for order.
+   * @return A mapping array used to access variables in SPOG order.
+   */
+  protected static final int[] mapColumnsToStd(Variable[] vars) {
+    assert vars.length == 4 : "Wrong number of variables. Expected {Subject,Predicate,Object,Meta} got " + Arrays.toString(vars);
+    if (vars[0] == StatementStore.VARIABLES[0]) {
+      assert vars[1] == StatementStore.VARIABLES[1] : "Expected '" + StatementStore.VARIABLES[1] + "' got '" + vars[1];
+      assert vars[2] == StatementStore.VARIABLES[2] : "Expected '" + StatementStore.VARIABLES[2] + "' got '" + vars[2];
+      assert vars[3] == StatementStore.VARIABLES[3] : "Expected '" + StatementStore.VARIABLES[3] + "' got '" + vars[3];
+      return new int[] { 0, 1, 2, 3 };
+    } else {
+      assert vars[0] == StatementStore.VARIABLES[3] : "Expected '" + StatementStore.VARIABLES[3] + "' got '" + vars[0];
+      assert vars[1] == StatementStore.VARIABLES[0] : "Expected '" + StatementStore.VARIABLES[0] + "' got '" + vars[1];
+      assert vars[2] == StatementStore.VARIABLES[1] : "Expected '" + StatementStore.VARIABLES[1] + "' got '" + vars[2];
+      assert vars[3] == StatementStore.VARIABLES[2] : "Expected '" + StatementStore.VARIABLES[2] + "' got '" + vars[3];
+      return new int[] { 1, 2, 3, 0 };
+    }
+  }
+}

Modified: trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndexTuples.java
===================================================================
--- trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndexTuples.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndexTuples.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -378,7 +378,7 @@
     return false;
   }
 
-  public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+  public Annotation getAnnotation(Class<? extends org.mulgara.store.tuples.Annotation> annotationClass) throws TuplesException {
     // the object (lucene query string) is required when a score is requested
     if (annotationClass.equals(MandatoryBindingAnnotation.class) &&
         objectElement instanceof Variable && constraint.getScoreVar() != null) {

Modified: trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneTransformer.java
===================================================================
--- trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneTransformer.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneTransformer.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -138,6 +138,7 @@
           cumulative.add(lc);
         } else {
           cumulative.iterator().next().conjoinWith(lc);
+          if (logger.isTraceEnabled()) logger.trace("Updated LC with: " + cumulative.iterator().next() + "; result: " + lc);
           transformed = true;
         }
 

Modified: trunk/src/jar/resolver-memory/java/org/mulgara/resolver/memory/MemoryResolver.java
===================================================================
--- trunk/src/jar/resolver-memory/java/org/mulgara/resolver/memory/MemoryResolver.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-memory/java/org/mulgara/resolver/memory/MemoryResolver.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -385,4 +385,11 @@
   public LongMapper getRestoreMapper() throws Exception {
     return new MemLongMapper();
   }
+
+  /**
+   * Ignored in this implementation 
+   */
+  public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
+    // do nothing
+  }
 }

Modified: trunk/src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype/TuplesWrapperResolution.java
===================================================================
--- trunk/src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype/TuplesWrapperResolution.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype/TuplesWrapperResolution.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -368,7 +368,7 @@
   /**
    * Copied from AbstractTuples
    */
-  public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+  public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
     return null;
   }
 }

Modified: trunk/src/jar/resolver-null/java/org/mulgara/resolver/nullres/NullResolution.java
===================================================================
--- trunk/src/jar/resolver-null/java/org/mulgara/resolver/nullres/NullResolution.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-null/java/org/mulgara/resolver/nullres/NullResolution.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -75,7 +75,7 @@
    * @see org.mulgara.store.tuples.Tuples#getAnnotation(java.lang.Class)
    * @return Always <code>null</code>.
    */
-  public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+  public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
     return null;
   }
 

Modified: trunk/src/jar/resolver-prefix/java/org/mulgara/resolver/prefix/TuplesWrapperResolution.java
===================================================================
--- trunk/src/jar/resolver-prefix/java/org/mulgara/resolver/prefix/TuplesWrapperResolution.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-prefix/java/org/mulgara/resolver/prefix/TuplesWrapperResolution.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -352,7 +352,7 @@
   /**
    * Copied from AbstractTuples
    */
-  public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+  public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
     return null;
   }
 }

Modified: trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/ReresolvableResolution.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/ReresolvableResolution.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/ReresolvableResolution.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -29,6 +29,7 @@
 
 import java.util.Map;
 
+import org.mulgara.query.ConstraintElement;
 import org.mulgara.query.TuplesException;
 
 /**
@@ -60,5 +61,5 @@
    * @return null if resolution was not able to be simplified using bindings otherwise a new 
    *         ReresolvableResolution with any variables bound in the reresolution removed.
    */
-  public ReresolvableResolution reresolve(Map bindings) throws TuplesException;
+  public ReresolvableResolution reresolve(Map<? extends ConstraintElement,Long> bindings) throws TuplesException;
 }

Modified: trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/SystemResolver.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/SystemResolver.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/SystemResolver.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -27,7 +27,6 @@
 
 package org.mulgara.resolver.spi;
 
-import java.net.URI;
 
 /**
  * A {@link Resolver} that is currently hosting the System Graph.
@@ -50,4 +49,12 @@
   public void createSystemModel(long model, long modelTypeURI) throws ResolverException, LocalizeException;
 
   public boolean modelExists(long model) throws ResolverException, LocalizeException;
+
+  /**
+   * Informs the system resolver of the metadata it uses for managing data.
+   * @param systemGraphNode The node for the system graph.
+   * @param rdfTypeNode The node representing <rdf:type>.
+   * @param systemGraphTypeNode The node used for the SystemResolver graph type.
+   */
+  public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode);
 }

Modified: trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStore.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStore.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStore.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -27,9 +27,6 @@
 
 package org.mulgara.store.statement;
 
-// Java 2 standard packages
-import java.util.*;
-
 // Locally written packages
 import org.mulgara.query.Variable;
 import org.mulgara.store.tuples.StoreTuples;

Modified: trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreAbstractUnitTest.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreAbstractUnitTest.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreAbstractUnitTest.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -27,10 +27,9 @@
 
 package org.mulgara.store.statement;
 
-// Java 2 standard packages
-import java.util.*;
-
 // third party packages
+import java.util.Arrays;
+
 import junit.framework.*;
 import org.apache.log4j.Logger;
 
@@ -39,6 +38,7 @@
 import org.mulgara.store.nodepool.NodePool;
 import org.mulgara.store.tuples.TestTuples;
 import org.mulgara.store.tuples.Tuples;
+import org.mulgara.store.tuples.TuplesOperations;
 import org.mulgara.store.xa.XAStatementStore;
 
 /**
@@ -69,6 +69,10 @@
   private static Logger log =
       Logger.getLogger(StatementStoreAbstractUnitTest.class.getName());
 
+  static final protected long SYSTEM_GRAPH = 100;
+  static final protected long RDF_TYPE = 101;
+  static final protected long GRAPH_TYPE = 102;
+
   /**
    * Subclasses must initialize this field.
    */
@@ -100,8 +104,6 @@
 
   /**
    * Test {@link StatementStore#isEmpty}.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   public void testIsEmpty() throws Exception {
 
@@ -113,23 +115,22 @@
       store.removeTriples(1, 2, 3, 1);
       store.removeTriples(1, 2, 4, 2);
       store.removeTriples(2, 5, 6, 2);
+      store.removeTriples(SYSTEM_GRAPH, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH);
+      store.removeTriples(1, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH);
+      store.removeTriples(2, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH);
 
       assertTrue(!store.isEmpty());
 
       store.removeTriples(1, 2, 3, 9);
 
       assertTrue(store.isEmpty());
-    }
-    catch (UnsupportedOperationException e) {
-
+    } catch (UnsupportedOperationException e) {
       log.warn("IsEmpty method unsupported", e);
     }
   }
 
   /**
    * Test {@link StatementStore#existsTriples}.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   public void testExists() throws Exception {
 
@@ -137,63 +138,57 @@
 
       long n = NodePool.NONE;
 
-      assertTrue(store.existsTriples(1, 2, 3, n));
-      assertTrue(store.existsTriples(1, 2, 4, n));
-      assertTrue(store.existsTriples(2, 5, 6, n));
-      assertTrue(!store.existsTriples(1, 3, 2, n));
-      assertTrue(!store.existsTriples(9, 9, 9, n));
+      assertTrue(store.existsTriples(n, 2, 3, 1));
+      assertTrue(store.existsTriples(n, 2, 4, 2));
+      assertTrue(store.existsTriples(n, 5, 6, 2));
+      assertTrue(!store.existsTriples(n, 3, 2, 1));
+      assertTrue(!store.existsTriples(n, 9, 9, 9));
 
-      assertTrue(store.existsTriples(1, 2, n, n));
-      assertTrue(store.existsTriples(2, 5, n, n));
-      assertTrue(!store.existsTriples(1, 3, n, n));
-      assertTrue(!store.existsTriples(2, 9, n, n));
+      assertTrue(store.existsTriples(1, n, 3, 1));
+      assertTrue(store.existsTriples(2, n, 6, 2));
+      assertTrue(!store.existsTriples(2, n, 4, 2));
+      assertTrue(!store.existsTriples(9, n, 3, 1));
 
-      assertTrue(store.existsTriples(n, 2, 3, n));
-      assertTrue(store.existsTriples(n, 2, 4, n));
-      assertTrue(!store.existsTriples(n, 1, 3, n));
-      assertTrue(!store.existsTriples(n, 2, 9, n));
+      assertTrue(store.existsTriples(n, n, 3, 1));
+      assertTrue(store.existsTriples(n, n, 4, 2));
+      assertTrue(!store.existsTriples(n, n, 3, 2));
+      assertTrue(!store.existsTriples(n, n, 9, 2));
 
-      assertTrue(store.existsTriples(1, n, 3, n));
-      assertTrue(store.existsTriples(2, n, 6, n));
-      assertTrue(!store.existsTriples(2, n, 4, n));
-      assertTrue(!store.existsTriples(9, n, 3, n));
+      assertTrue(store.existsTriples(1, 2, n, 1));
+      assertTrue(store.existsTriples(2, 5, n, 2));
+      assertTrue(!store.existsTriples(1, 3, n, 1));
+      assertTrue(!store.existsTriples(2, 9, n, 2));
 
-      assertTrue(store.existsTriples(1, n, n, n));
-      assertTrue(store.existsTriples(2, n, n, n));
-      assertTrue(!store.existsTriples(3, n, n, n));
+      assertTrue(store.existsTriples(n, 2, n, 1));
+      assertTrue(store.existsTriples(n, 5, n, 2));
+      assertTrue(!store.existsTriples(n, 3, n, 1));
+      assertTrue(!store.existsTriples(n, 9, n, 2));
 
-      assertTrue(store.existsTriples(n, 2, n, n));
-      assertTrue(store.existsTriples(n, 5, n, n));
-      assertTrue(!store.existsTriples(n, 1, n, n));
+      assertTrue(store.existsTriples(1, n, n, 1));
+      assertTrue(store.existsTriples(1, n, n, 2));
+      assertTrue(store.existsTriples(2, n, n, 2));
+      assertTrue(!store.existsTriples(3, n, n, 2));
 
-      assertTrue(store.existsTriples(n, n, 3, n));
-      assertTrue(store.existsTriples(n, n, 6, n));
-      assertTrue(!store.existsTriples(n, n, 5, n));
-    }
-    catch (UnsupportedOperationException e) {
-
+      assertTrue(store.existsTriples(n, n, n, 1));
+      assertTrue(store.existsTriples(n, n, n, 2));
+      assertTrue(!store.existsTriples(n, n, n, 3));
+    } catch (UnsupportedOperationException e) {
       log.warn("Exists method unsupported", e);
     }
   }
 
   /**
    * Test {@link StatementStore#findTuples}.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   public void testDump() throws Exception {
 
-    TestTuples expected = new TestTuples();
-    add(expected, store.VARIABLES, new long[] {
-        1, 2, 3, 1});
-    add(expected, store.VARIABLES, new long[] {
-        1, 2, 4, 2});
-    add(expected, store.VARIABLES, new long[] {
-        2, 5, 6, 2});
+    TestTuples expected = getDump();
 
     Tuples t = store.findTuples(NodePool.NONE, NodePool.NONE, NodePool.NONE, NodePool.NONE);
-    assertEquals(expected, t);
+    Tuples r = TuplesOperations.project(t, Arrays.asList(StatementStore.VARIABLES));
+    assertEquals(expected, r);
     t.close();
+    r.close();
     expected.close();
   }
 
@@ -217,37 +212,39 @@
     store.removeTriples(2, 5, 6, 2);
     store.removeTriples(1, 2, 4, 2);
 
-    assertTrue(!store.existsTriples(1, 2, 3, NodePool.NONE));
-    assertTrue(!store.existsTriples(1, 2, 4, NodePool.NONE));
-    assertTrue(!store.existsTriples(2, 5, 6, NodePool.NONE));
+    assertTrue(!store.existsTriples(NodePool.NONE, 2, 3, 1));
+    assertTrue(!store.existsTriples(NodePool.NONE, 2, 4, 2));
+    assertTrue(!store.existsTriples(NodePool.NONE, 5, 6, 2));
   }
 
   /**
    * Test {@link StatementStore#findTuples}.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   public void testFindTriplesByNode0() throws Exception {
 
     TestTuples expected = new TestTuples();
     Variable[] vars =
-        new Variable[] {
-        store.VARIABLES[1], store.VARIABLES[2], store.VARIABLES[3]};
-    add(expected, vars, new long[] {
-        2, 3, 1});
-    add(expected, vars, new long[] {
-        2, 4, 2});
+        new Variable[] {StatementStore.VARIABLES[1], StatementStore.VARIABLES[2], StatementStore.VARIABLES[3]};
+    add(expected, vars, new long[] {2, 3, 1});
+    add(expected, vars, new long[] {2, 4, 2});
+    add(expected, vars, new long[] {RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
 
-    Tuples t = store.findTuples(1, NodePool.NONE, NodePool.NONE, NodePool.NONE);
-    assertEquals(expected, t);
-    t.close();
-    expected.close();
+    try {
+      Tuples t = store.findTuples(1, NodePool.NONE, NodePool.NONE, NodePool.NONE);
+      assertEquals(expected, t);
+      t.close();
+    } catch (IllegalArgumentException e) {
+      // not supported
+      return;
+    } finally {
+      expected.close();
+    }
 
     expected = new TestTuples();
-    add(expected, vars, new long[] {
-        5, 6, 2});
+    add(expected, vars, new long[] {5, 6, 2});
 
-    t = store.findTuples(2, NodePool.NONE, NodePool.NONE, NodePool.NONE);
+    Tuples t = store.findTuples(2, NodePool.NONE, NodePool.NONE, NodePool.NONE);
+    add(expected, vars, new long[] {RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
     assertEquals(expected, t);
     t.close();
     expected.close();
@@ -261,17 +258,17 @@
   public void testFindTriplesByNode1() throws Exception {
 
     TestTuples expected = new TestTuples();
-    Variable[] vars =
-        new Variable[] {
-        store.VARIABLES[2], store.VARIABLES[0], store.VARIABLES[3]};
-    add(expected, vars, new long[] {
-        3, 1, 1});
-    add(expected, vars, new long[] {
-        4, 1, 2});
+    Variable[] vars = new Variable[] {StatementStore.VARIABLES[2], StatementStore.VARIABLES[0], StatementStore.VARIABLES[3]};
+    add(expected, vars, new long[] {3, 1, 1});
+    add(expected, vars, new long[] {4, 1, 2});
 
-    Tuples t = store.findTuples(NodePool.NONE, 2, NodePool.NONE, NodePool.NONE);
-    assertEquals(expected, t);
-    t.close();
+    try {
+      Tuples t = store.findTuples(NodePool.NONE, 2, NodePool.NONE, NodePool.NONE);
+      assertEquals(expected, t);
+      t.close();
+    } catch (IllegalArgumentException e) {
+      // not supported
+    }
     expected.close();
   }
 
@@ -283,15 +280,16 @@
   public void testFindTriplesByNode2() throws Exception {
 
     TestTuples expected = new TestTuples();
-    Variable[] vars =
-        new Variable[] {
-        store.VARIABLES[0], store.VARIABLES[1], store.VARIABLES[3]};
-    add(expected, vars, new long[] {
-        1, 2, 1});
+    Variable[] vars = new Variable[] {StatementStore.VARIABLES[0], StatementStore.VARIABLES[1], StatementStore.VARIABLES[3]};
+    add(expected, vars, new long[] {1, 2, 1});
 
-    Tuples t = store.findTuples(NodePool.NONE, NodePool.NONE, 3, NodePool.NONE);
-    assertEquals(expected, t);
-    t.close();
+    try {
+      Tuples t = store.findTuples(NodePool.NONE, NodePool.NONE, 3, NodePool.NONE);
+      assertEquals(expected, t);
+      t.close();
+    } catch (IllegalArgumentException e) {
+      // not supported
+    }
     expected.close();
   }
 
@@ -303,13 +301,9 @@
   public void testFindTriplesByNode3() throws Exception {
 
     TestTuples expected = new TestTuples();
-    Variable[] vars =
-        new Variable[] {
-        store.VARIABLES[0], store.VARIABLES[1], store.VARIABLES[2]};
-    add(expected, vars, new long[] {
-        1, 2, 4});
-    add(expected, vars, new long[] {
-        2, 5, 6});
+    Variable[] vars = new Variable[] {StatementStore.VARIABLES[0], StatementStore.VARIABLES[1], StatementStore.VARIABLES[2]};
+    add(expected, vars, new long[] {1, 2, 4});
+    add(expected, vars, new long[] {2, 5, 6});
 
     Tuples t = store.findTuples(NodePool.NONE, NodePool.NONE, NodePool.NONE, 2);
     assertEquals(expected, t);
@@ -319,64 +313,59 @@
 
   /**
    * Test {@link StatementStore#findTuples}.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   public void testFindTriplesByNode01() throws Exception {
 
     TestTuples expected = new TestTuples();
-    Variable[] vars = new Variable[] {
-        store.VARIABLES[2], store.VARIABLES[3]};
-    add(expected, vars, new long[] {
-        3, 1});
-    add(expected, vars, new long[] {
-        4, 2});
+    Variable[] vars = new Variable[] {StatementStore.VARIABLES[2], StatementStore.VARIABLES[3]};
+    add(expected, vars, new long[] {3, 1});
+    add(expected, vars, new long[] {4, 2});
 
-    Tuples t = store.findTuples(1, 2, NodePool.NONE, NodePool.NONE);
-    assertEquals(expected, t);
-    t.close();
-
-    t = store.findTuples(1, 3, NodePool.NONE, NodePool.NONE);
-    assertTrue(!expected.equals(t));
-    t.close();
+    try {
+      Tuples t = store.findTuples(1, 2, NodePool.NONE, NodePool.NONE);
+      assertEquals(expected, t);
+      t.close();
+  
+      t = store.findTuples(1, 3, NodePool.NONE, NodePool.NONE);
+      assertTrue(!expected.equals(t));
+      t.close();
+    } catch (IllegalArgumentException e) {
+      // not supported
+    }
     expected.close();
   }
 
   /**
    * Test {@link StatementStore#findTuples}.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   public void testFindTriplesByNode02() throws Exception {
 
     TestTuples expected = new TestTuples();
-    Variable[] vars = new Variable[] {
-        store.VARIABLES[1], store.VARIABLES[3]};
-    add(expected, vars, new long[] {
-        2, 1});
+    Variable[] vars = new Variable[] {StatementStore.VARIABLES[1], StatementStore.VARIABLES[3]};
+    add(expected, vars, new long[] {2, 1});
 
-    Tuples t = store.findTuples(1, NodePool.NONE, 3, NodePool.NONE);
-    assertEquals(expected, t);
-    t.close();
-
-    t = store.findTuples(1, NodePool.NONE, 4, NodePool.NONE);
-    assertTrue(!expected.equals(t));
-    t.close();
+    try {
+      Tuples t = store.findTuples(1, NodePool.NONE, 3, NodePool.NONE);
+      assertEquals(expected, t);
+      t.close();
+  
+      t = store.findTuples(1, NodePool.NONE, 4, NodePool.NONE);
+      assertTrue(!expected.equals(t));
+      t.close();
+    } catch (IllegalArgumentException e) {
+      // not supported
+    }
     expected.close();
   }
 
   /**
    * Test {@link StatementStore#findTuples}.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   public void testFindTriplesByNode03() throws Exception {
 
     TestTuples expected = new TestTuples();
-    Variable[] vars = new Variable[] {
-        store.VARIABLES[1], store.VARIABLES[2]};
-    add(expected, vars, new long[] {
-        2, 4});
+    Variable[] vars = new Variable[] {StatementStore.VARIABLES[1], StatementStore.VARIABLES[2]};
+    add(expected, vars, new long[] {2, 4});
 
     Tuples t = store.findTuples(1, NodePool.NONE, NodePool.NONE, 2);
     assertEquals(expected, t);
@@ -386,39 +375,35 @@
 
   /**
    * Test {@link StatementStore#findTuples}.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   public void testFindTriplesByNode12() throws Exception {
 
     TestTuples expected = new TestTuples();
-    Variable[] vars = new Variable[] {
-        store.VARIABLES[0], store.VARIABLES[3]};
-    add(expected, vars, new long[] {
-        1, 1});
+    Variable[] vars = new Variable[] {StatementStore.VARIABLES[0], StatementStore.VARIABLES[3]};
+    add(expected, vars, new long[] {1, 1});
 
-    Tuples t = store.findTuples(NodePool.NONE, 2, 3, NodePool.NONE);
-    assertEquals(expected, t);
-    t.close();
-
-    t = store.findTuples(NodePool.NONE, 2, 4, NodePool.NONE);
-    assertTrue(!expected.equals(t));
-    t.close();
+    try {
+      Tuples t = store.findTuples(NodePool.NONE, 2, 3, NodePool.NONE);
+      assertEquals(expected, t);
+      t.close();
+  
+      t = store.findTuples(NodePool.NONE, 2, 4, NodePool.NONE);
+      assertTrue(!expected.equals(t));
+      t.close();
+    } catch (IllegalArgumentException e) {
+      // not supported
+    }
     expected.close();
   }
 
   /**
    * Test {@link StatementStore#findTuples}.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   public void testFindTriplesByNode13() throws Exception {
 
     TestTuples expected = new TestTuples();
-    Variable[] vars = new Variable[] {
-        store.VARIABLES[2], store.VARIABLES[0]};
-    add(expected, vars, new long[] {
-        4, 1});
+    Variable[] vars = new Variable[] {StatementStore.VARIABLES[2], StatementStore.VARIABLES[0]};
+    add(expected, vars, new long[] {4, 1});
 
     Tuples t = store.findTuples(NodePool.NONE, 2, NodePool.NONE, 2);
     assertEquals(expected, t);
@@ -428,16 +413,12 @@
 
   /**
    * Test {@link StatementStore#findTuples}.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   public void testFindTriplesByNode23() throws Exception {
 
     TestTuples expected = new TestTuples();
-    Variable[] vars = new Variable[] {
-        store.VARIABLES[0], store.VARIABLES[1]};
-    add(expected, vars, new long[] {
-        2, 5});
+    Variable[] vars = new Variable[] {StatementStore.VARIABLES[0], StatementStore.VARIABLES[1]};
+    add(expected, vars, new long[] {2, 5});
 
     Tuples t = store.findTuples(NodePool.NONE, NodePool.NONE, 6, 2);
     assertEquals(expected, t);
@@ -447,14 +428,11 @@
 
   /**
    * Test {@link StatementStore#findTuples}.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   public void testFindTriplesByNode013() throws Exception {
 
-    TestTuples expected = new TestTuples(store.VARIABLES[2]);
-    Variable[] vars = new Variable[] {
-        store.VARIABLES[2]};
+    TestTuples expected = new TestTuples(StatementStore.VARIABLES[2]);
+    Variable[] vars = new Variable[] {StatementStore.VARIABLES[2]};
     Tuples t = store.findTuples(2, 6, NodePool.NONE, 1);
     assertEquals(expected, t);
     t.close();
@@ -463,8 +441,7 @@
     assertEquals(expected, t);
     t.close();
 
-    add(expected, vars, new long[] {
-        4});
+    add(expected, vars, new long[] {4});
     t = store.findTuples(1, 2, NodePool.NONE, 2);
     assertEquals(expected, t);
     t.close();
@@ -473,20 +450,16 @@
 
   /**
    * Test {@link StatementStore#findTuples}.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   public void testFindTriplesByNode023() throws Exception {
 
-    TestTuples expected = new TestTuples(store.VARIABLES[1]);
-    Variable[] vars = new Variable[] {
-        store.VARIABLES[1]};
+    TestTuples expected = new TestTuples(StatementStore.VARIABLES[1]);
+    Variable[] vars = new Variable[] {StatementStore.VARIABLES[1]};
     Tuples t = store.findTuples(1, NodePool.NONE, 3, 4);
     assertEquals(expected, t);
     t.close();
 
-    add(expected, vars, new long[] {
-        5});
+    add(expected, vars, new long[] {5});
     t = store.findTuples(2, NodePool.NONE, 6, 2);
     assertEquals(expected, t);
     t.close();
@@ -495,20 +468,16 @@
 
   /**
    * Test {@link StatementStore#findTuples}.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   public void testFindTriplesByNode123() throws Exception {
 
-    TestTuples expected = new TestTuples(store.VARIABLES[0]);
-    Variable[] vars = new Variable[] {
-        store.VARIABLES[0]};
+    TestTuples expected = new TestTuples(StatementStore.VARIABLES[0]);
+    Variable[] vars = new Variable[] {StatementStore.VARIABLES[0]};
     Tuples t = store.findTuples(NodePool.NONE, 2, 3, 4);
     assertEquals(expected, t);
     t.close();
 
-    add(expected, vars, new long[] {
-        1});
+    add(expected, vars, new long[] {1});
     t = store.findTuples(NodePool.NONE, 2, 3, 1);
     assertEquals(expected, t);
     t.close();
@@ -517,58 +486,53 @@
 
   /**
    * Populate the test store.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   protected void setUp() throws Exception {
+    store.initializeSystemNodes(SYSTEM_GRAPH, RDF_TYPE, GRAPH_TYPE);
 
+    // set up the graph instances
+    store.addTriple(SYSTEM_GRAPH, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH);
+    store.addTriple(1, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH);
+    store.addTriple(2, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH);
+
     store.addTriple(1, 2, 3, 1);
     store.addTriple(1, 2, 4, 2);
     store.addTriple(2, 5, 6, 2);
   }
 
   /**
+   * Return a dump of all tuples, sorted by the primary index.
+   * @return a new TestTuples containing all the {@link #setUp()} triples, according to the natural ordering of the store.
+   */
+  protected abstract TestTuples getDump();
+
+  /**
    * Close the test store.
-   *
-   * @throws Exception EXCEPTION TO DO
    */
   protected void tearDown() throws Exception {
-
     if (store != null) {
-
       try {
-
         store.close();
-      }
-      finally {
-
+      } finally {
         store = null;
       }
     }
   }
 
   /**
-   * METHOD TO DO
-   *
-   * @param tt PARAMETER TO DO
-   * @param vars PARAMETER TO DO
-   * @param nodes PARAMETER TO DO
+   * Add a row to a tuples
+   * @param tt The tuples to add to
+   * @param vars The column names in the tuples
+   * @param nodes The values to bind to
    */
   protected void add(TestTuples tt, Variable[] vars, long[] nodes) {
 
-    if (vars.length != nodes.length) {
+    if (vars.length != nodes.length) throw new AssertionError();
 
-      throw new AssertionError();
-    }
-
     for (int i = 0; i < vars.length; ++i) {
-
       if (i == 0) {
-
         tt.or(vars[i], nodes[i]);
-      }
-      else {
-
+      } else {
         tt.and(vars[i], nodes[i]);
       }
     }

Modified: trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreException.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreException.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreException.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -43,6 +43,9 @@
  */
 public class StatementStoreException extends StoreException {
 
+  /** Version ID for serialization. */
+  private static final long serialVersionUID = -2415826145039347120L;
+
   /**
    * Get line separator.
    */

Deleted: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolution.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolution.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolution.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,615 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is the Kowari Metadata Store.
- *
- * The Initial Developer of the Original Code is Plugged In Software Pty
- * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
- * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
- * Plugged In Software Pty Ltd. All Rights Reserved.
- *
- * Contributor(s):
- *   getModel() contributed by Netymon Pty Ltd on behalf of
- *   The Australian Commonwealth Government under contract 4500507038.
- *
- * [NOTE: The text of this Exhibit A may differ slightly from the text
- * of the notices in the Source Code files of the Original Code. You
- * should use the text of this Exhibit A rather than the text found in the
- * Original Code Source Code for Your Modifications.]
- *
- */
-
-package org.mulgara.resolver.store;
-
-// Third party packages
-import org.apache.log4j.Logger;
-
-// Standard Java packages
-import java.util.*;
-
-// Locally written packages
-import org.mulgara.query.*;
-import org.mulgara.resolver.spi.Resolution;
-import org.mulgara.resolver.spi.Resolver;
-import org.mulgara.store.nodepool.NodePool;
-import org.mulgara.store.statement.StatementStore;
-import org.mulgara.store.statement.StatementStoreException;
-import org.mulgara.store.tuples.AbstractTuples;
-import org.mulgara.store.tuples.StoreTuples;
-import org.mulgara.store.tuples.Tuples;
-import org.mulgara.store.tuples.TuplesOperations;
-
-/**
- * Tuples backed by the graph, corresponding to a particular constraint.
- *
- * It differs from {@link StatementStoreResolution} in that it handles
- * constraints with duplicate variable bindings.  That is,
- * <code>$x $x $x</code> which will return all the statements that have the
- * same value in all three places.  The class retains the original constraint
- * so that the graph index it's resolved against can be resolved anew as its
- * variables are bound.
- *
- * TO DO: Support <code>mulgara:is</code> re-binding.
- *
- * @created 2004-08-26
- *
- * @author Andrew Newman
- *
- * @version $Revision: 1.10 $
- *
- * @modified $Date: 2005/05/02 20:07:58 $ by $Author: raboczi $
- *
- * @maintenanceAuthor $Author: raboczi $
- *
- * @company <a href="mailto:info at PIsoftware.com">Plugged In Software</a>
- *
- * @copyright &copy; 2003 <A href="http://www.PIsoftware.com/">Plugged In
- *      Software Pty Ltd</A>
- *
- * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
- */
-class StatementStoreDuplicateResolution extends AbstractTuples implements Resolution {
-
-  protected static Logger logger = Logger.getLogger(StatementStoreDuplicateResolution.class);
-
-  /** Indicates ordering by subject */
-  private final static int MASK0 = 1;
-
-  /** Indicates ordering by predicate */
-  private final static int MASK1 = 2;
-
-  /** Indicates ordering by object */
-  private final static int MASK2 = 4;
-
-  /** Indicates ordering by graph */
-  private final static int MASK3 = 8;
-
-  /**
-   * The constraint these tuples were generated to satisfy.
-   */
-  protected Constraint constraint;
-
-  /**
-   * The graph from which these tuples were generated.
-   */
-  protected StatementStore store;
-
-  /**
-   * The tuples.
-   */
-  private Tuples baseTuples, uniqueTuples;
-
-  /**
-   * Which columns s, p, o are the same.
-   */
-  private boolean[] sameColumns;
-
-  /**
-   * Whether we've calculated the rows.
-   */
-  private boolean calculatedRowCount;
-
-  /**
-   * An array that contains the position in the tuples.  Elements 0, 1, 2, 3
-   * map to subject, predicate, object and meta and the value in the array is
-   * the column position.
-   */
-  private int[] columnOrder;
-
-  /** A mapping between the virtual column numbers and the internal column numbers. */
-  private int[] columnMap;
-
-  private boolean hasNext = false;
-
-  private List variableList;
-
-  private TuplesEvaluator tuplesEvaluator;
-
-  /**
-   * Construct a tuples with node numbers and local tuples objects.
-   *
-   * @param newTuples a local tuples representing a graph.
-   */
-  StatementStoreDuplicateResolution(boolean[] newSameColumns, Tuples newTuples,
-      int[] newColumnOrder) {
-
-    baseTuples = newTuples;
-    sameColumns = newSameColumns;
-    columnOrder = newColumnOrder;
-
-    // Get variable list.
-    variableList = new LinkedList();
-    Variable[] baseVars = baseTuples.getVariables();
-    for (int index = 0; index < sameColumns.length; index++) {
-      if (sameColumns[index]) variableList.add(baseVars[index]);
-    }
-    // do 1:1 mapping as this is expected in the tests - variable names are not duplicated
-    columnMap = new int[baseVars.length];
-    for (int i = 0; i < columnMap.length; i++) columnMap[i] = i;
-
-    // Project for unique variables.
-    try {
-      uniqueTuples = TuplesOperations.project(baseTuples, variableList);
-    }
-    catch (TuplesException te) {
-      logger.error("Failed to get unique tuples", te);
-    }
-
-    columnOrder = newColumnOrder;
-    setVariables(newTuples.getVariables());
-    setTuplesEvaluator();
-  }
-
-  /**
-   * Find a graph index that satisfies a constraint.
-   *
-   * @param newConstraint the constraint to satisfy
-   * @param newStore the store to resolve against
-   * @throws IllegalArgumentException if <var>constraint</var> or <var>graph
-   *      </var> is <code>null</code>
-   * @throws TuplesException EXCEPTION TO DO
-   */
-  StatementStoreDuplicateResolution(Constraint newConstraint, StatementStore newStore)
-      throws TuplesException {
-
-    try {
-      constraint = newConstraint;
-      store = newStore;
-
-      // Setup which columns are duplicates.
-      boolean equalSubject = constraint.getElement(0).equals(constraint.getElement(1)) ||
-          constraint.getElement(0).equals(constraint.getElement(2));
-      boolean equalPredicate = constraint.getElement(1).equals(constraint.getElement(0)) ||
-          constraint.getElement(1).equals(constraint.getElement(2));
-      boolean equalObject = constraint.getElement(2).equals(constraint.getElement(0)) ||
-          constraint.getElement(2).equals(constraint.getElement(1));
-      sameColumns = new boolean[] { equalSubject, equalPredicate,
-          equalObject };
-
-      // Setup which are the constants and which are the variables.
-      long subject = toGraphTuplesIndex(constraint.getElement(0));
-      long predicate = toGraphTuplesIndex(constraint.getElement(1));
-      long object = toGraphTuplesIndex(constraint.getElement(2));
-      long meta = toGraphTuplesIndex(constraint.getModel());
-
-      final long VAR = NodePool.NONE;
-      if (meta != VAR && subject == VAR && predicate == VAR && object == VAR) {
-        // all variables except the graph. Select explicit ordering.
-        int mask = MASK3;
-        if (equalSubject) mask |= MASK0;
-        if (equalPredicate) mask |= MASK1;
-        if (equalObject) mask |= MASK2;
-        baseTuples = store.findTuples(mask, subject, predicate, object, meta);
-      } else {
-        // Return the tuples using the s, p, o hints.
-        baseTuples = store.findTuples(subject, predicate, object, meta);
-      }
-
-      // Get the unique values for the multiply constrained column.
-      variableList = new LinkedList();
-      for (int index = 0; index < sameColumns.length; index++) {
-        if (sameColumns[index]) {
-          variableList.add(StatementStore.VARIABLES[index]);
-        }
-      }
-      uniqueTuples = TuplesOperations.project(baseTuples, variableList);
-
-      // Create column map.
-      columnOrder = new int[4];
-      int[] inverseColumnOrder = ((StoreTuples)baseTuples).getColumnOrder();
-      for (int index = 0; index < inverseColumnOrder.length; index++) {
-        columnOrder[inverseColumnOrder[index]] = index;
-      }
-
-      // Set the variables. Using an ordered set.
-      Set uniqueVariables = new LinkedHashSet();
-      columnMap = new int[2];
-      for (int index = 0; index < baseTuples.getVariables().length; index++) {
-        Object obj = constraint.getElement(index);
-        if (obj instanceof Variable) {
-          if (!((Variable) obj).equals(Variable.FROM)) {
-            if (!uniqueVariables.contains(obj)) columnMap[uniqueVariables.size()] = columnOrder[index];
-            uniqueVariables.add(obj);
-          }
-        }
-      }
-      setVariables((Variable[]) uniqueVariables.toArray(new Variable[uniqueVariables.size()]));
-
-      // Set up the tuples evaluator.
-      setTuplesEvaluator();
-    }
-    catch (StatementStoreException se) {
-      throw new TuplesException("Failed to set-up tuples", se);
-    }
-  }
-
-  /**
-   * Create a new tuples evaluator depending on how many columns to bind.
-   */
-  public void setTuplesEvaluator() {
-    if (variableList.size() == 2) {
-      tuplesEvaluator = new TwoConstrainedTuplesEvaluator();
-    }
-    else {
-      tuplesEvaluator = new ThreeConstrainedTuplesEvaluator();
-    }
-  }
-
-  public long getRowCount() throws TuplesException {
-    return tuplesEvaluator.getRowCount();
-  }
-
-  public boolean hasNoDuplicates() throws TuplesException {
-    return baseTuples.hasNoDuplicates();
-  }
-
-  public List getOperands() {
-    return new ArrayList();
-  }
-
-  public void beforeFirst(long[] prefix, int suffixTruncation) throws TuplesException {
-    if (prefix.length > 4) {
-      throw new TuplesException("Prefix too long");
-    }
-    tuplesEvaluator.beforeFirst(prefix, suffixTruncation);
-  }
-
-  public void close() throws TuplesException {
-    try {
-      if (baseTuples != null) {
-        baseTuples.close();
-      }
-    }
-    finally {
-      if (uniqueTuples != null) {
-        uniqueTuples.close();
-      }
-    }
-  }
-
-  /**
-   * METHOD TO DO
-   *
-   * @return RETURNED VALUE TO DO
-   */
-  public Object clone() {
-    StatementStoreDuplicateResolution cloned = (StatementStoreDuplicateResolution) super.clone();
-    cloned.baseTuples = (Tuples) baseTuples.clone();
-    cloned.uniqueTuples = (Tuples) uniqueTuples.clone();
-    cloned.setVariables(getVariables());
-    cloned.setTuplesEvaluator();
-//    cloned.constraint = constraint;
-    return cloned;
-  }
-
-
-  public long getRowUpperBound() throws TuplesException {
-    return getRowCount();
-  }
-
-  public int getRowCardinality() throws TuplesException {
-    long count = getRowCount();
-    if (count > 1) {
-      return Cursor.MANY;
-    }
-    switch ((int) count) {
-      case 0:
-        return Cursor.ZERO;
-      case 1:
-        return Cursor.ONE;
-      default:
-        throw new TuplesException("Illegal row count: " + count);
-    }
-  }
-
-  public Constraint getConstraint() {
-    return constraint;
-  }
-
-  public long getColumnValue(int column) throws TuplesException {
-    return baseTuples.getColumnValue(columnMap[column]);
-  }
-
-  public boolean isColumnEverUnbound(int column) throws TuplesException {
-    return baseTuples.isColumnEverUnbound(columnMap[column]);
-  }
-
-  public boolean isUnconstrained() throws TuplesException {
-    return baseTuples.isUnconstrained();
-  }
-
-  public boolean isMaterialized() {
-    return baseTuples.isMaterialized();
-  }
-
-  public boolean next() throws TuplesException {
-    return tuplesEvaluator.next();
-  }
-
-  public boolean isComplete() {
-    return true;
-  }
-
-
-  /**
-   * A decorator around the getRowCount(), next() and beforeFirst() methods on
-   * a tuples correctly sets the searching tuples and performs the correct next
-   * operation.
-   */
-  private interface TuplesEvaluator {
-
-    /**
-     * Returns the row count.
-     *
-     * @return the row count.
-     * @throws TuplesException if there was an error accessing the tuples.
-     */
-    public long getRowCount() throws TuplesException;
-
-    /**
-     * Calls before first using a given prefix.
-     *
-     * @param prefix long[] the prefix to jump to.
-     * @param suffixTruncation the suffixes to truncate.
-     * @throws TuplesException if there was a problem accessing the tuples.
-     */
-    public void beforeFirst(long[] prefix, int suffixTruncation)
-        throws TuplesException;
-
-    /**
-     * Returns true if there is another tuples.
-     *
-     * @throws TuplesException if there was a problem accessing the tuples.
-     * @return true if there is another tuples.
-     */
-    public boolean next() throws TuplesException;
-  }
-
-  /**
-   * Operates on a tuples where two of the constraints are equal.
-   */
-  private class TwoConstrainedTuplesEvaluator implements TuplesEvaluator {
-
-    public long getRowCount() throws TuplesException {
-
-      // Only calculate rows once.
-      if (!calculatedRowCount) {
-
-        // Start with total number of tuples.
-        Tuples tmpUniqueTuples = (Tuples) uniqueTuples.clone();
-        Tuples tmpTuples = (Tuples) baseTuples.clone();
-        tmpUniqueTuples.beforeFirst();
-        tmpTuples.beforeFirst();
-
-        rowCount = 0;
-
-        while (tmpUniqueTuples.next()) {
-          if (tmpUniqueTuples.getColumnValue(0) == tmpUniqueTuples.getColumnValue(1)) {
-            tmpTuples.beforeFirst(new long[] {
-                tmpUniqueTuples.getColumnValue(0),
-                tmpUniqueTuples.getColumnValue(1) }, 0);
-            while (tmpTuples.next()) {
-              rowCount++;
-            }
-          }
-        }
-
-        // Ensure we don't calculate the rows again.
-        calculatedRowCount = true;
-      }
-      return rowCount;
-    }
-
-    public void beforeFirst(long[] prefix, int suffixTruncation)
-        throws TuplesException {
-
-      // create a new prefix for uniqueTuples
-      // this only includes columns from the initial prefix that represented duplicate variables
-      // takes advantage of the fact that variables came out in the same order as the initial constraint
-      // also, sameColumns offsets are same as baseTuples offsets
-      long[] duplicatesPrefix = new long[] {};
-      for (int i = 0; i < prefix.length; i++) {
-        // i is an index into the virtual tuples. Map it to the original columns
-        if (sameColumns[columnMap[i]]) {
-          // only the first of the duplicated columns was mapped
-          duplicatesPrefix = new long[] { prefix[i], prefix[i] };
-          break;
-        }
-      }
-
-      // Get the subject/predicate before first.
-      uniqueTuples.beforeFirst(duplicatesPrefix, suffixTruncation);
-
-      hasNext = uniqueTuples.next();
-      while (hasNext && (uniqueTuples.getColumnValue(0) != uniqueTuples.getColumnValue(1))) {
-        hasNext = uniqueTuples.next();
-      }
-
-      // Go to the first tuples. Ignoring suffix truncation.
-      if (hasNext) {
-        if (prefix.length <= 1) {
-          baseTuples.beforeFirst(new long[] { uniqueTuples.getColumnValue(0), uniqueTuples.getColumnValue(1) }, 0);
-        } else {
-          assert prefix.length == 2;
-          baseTuples.beforeFirst(new long[] { uniqueTuples.getColumnValue(0), uniqueTuples.getColumnValue(1), prefix[1] }, 0);
-        }
-      }
-   }
-
-    public boolean next() throws TuplesException {
-
-      // Check that there are more tuples - assume tuples are in order.
-      if (hasNext) {
-
-        boolean hasNextBase = baseTuples.next();
-
-        // Check if we still have a match, if not get the next match.
-        if (!hasNextBase ||
-            !((uniqueTuples.getColumnValue(0) == baseTuples.getColumnValue(0)) &&
-            (uniqueTuples.getColumnValue(1) == baseTuples.getColumnValue(1)))) {
-
-          // Get the next item to search.
-          while (uniqueTuples.next()) {
-
-            // Check to see that there is a next value.  There will be at least
-            // one value as the items to search are based on the original tuples.
-            if (uniqueTuples.getColumnValue(0) == uniqueTuples.getColumnValue(1)) {
-              baseTuples.beforeFirst(new long[] { uniqueTuples.getColumnValue(0),
-                  uniqueTuples.getColumnValue(1) }, 0);
-              hasNextBase = baseTuples.next();
-              if (hasNextBase) {
-                break;
-              }
-            }
-          }
-        }
-        hasNext = hasNextBase;
-      }
-      return hasNext;
-    }
-  }
-
-  /**
-   * Operates on a tuples where all three of the constraints are equal.
-   */
-  private class ThreeConstrainedTuplesEvaluator implements TuplesEvaluator {
-
-    public long getRowCount() throws TuplesException {
-
-      // Only calculate rows once.
-      if (!calculatedRowCount) {
-
-        // Start with total number of tuples.
-        Tuples tmpSubjPredTuples = (Tuples) uniqueTuples.clone();
-        Tuples tmpTuples = (Tuples) baseTuples.clone();
-        tmpSubjPredTuples.beforeFirst();
-        tmpTuples.beforeFirst();
-
-        rowCount = 0;
-
-        while (tmpSubjPredTuples.next()) {
-          if ((tmpSubjPredTuples.getColumnValue(0) == tmpSubjPredTuples.getColumnValue(1)) &&
-             (tmpSubjPredTuples.getColumnValue(1) == tmpSubjPredTuples.getColumnValue(2))) {
-            tmpTuples.beforeFirst(new long[] {
-                tmpSubjPredTuples.getColumnValue(0),
-                tmpSubjPredTuples.getColumnValue(1),
-                tmpSubjPredTuples.getColumnValue(2) }, 0);
-            while (tmpTuples.next()) {
-              rowCount++;
-            }
-          }
-        }
-
-        // Ensure we don't calculate the rows again.
-        calculatedRowCount = true;
-      }
-      return rowCount;
-    }
-
-    public void beforeFirst(long[] prefix, int suffixTruncation)
-        throws TuplesException {
-
-      // Get the subject/predicate before first.
-     uniqueTuples.beforeFirst(prefix, suffixTruncation);
-     baseTuples.beforeFirst(prefix, suffixTruncation);
-     hasNext = uniqueTuples.next();
-
-     while (hasNext &&
-         ((uniqueTuples.getColumnValue(0) != uniqueTuples.getColumnValue(1)) ||
-          (uniqueTuples.getColumnValue(1) != uniqueTuples.getColumnValue(2)))) {
-       hasNext = uniqueTuples.next();
-     }
-
-     // Go to the first tuples.
-     if (hasNext) {
-       baseTuples.beforeFirst(new long[] { uniqueTuples.getColumnValue(0),
-           uniqueTuples.getColumnValue(1), uniqueTuples.getColumnValue(2) },
-           0);
-     }
-   }
-
-    public boolean next() throws TuplesException {
-
-      // Check that there are more tuples - assume tuples are in order.
-      if (hasNext) {
-
-        boolean hasNextBase = baseTuples.next();
-
-        // Check if we still have a match, if not get the next match.
-        if (!hasNextBase ||
-            !((uniqueTuples.getColumnValue(0) == baseTuples.getColumnValue(0)) &&
-            (uniqueTuples.getColumnValue(1) == baseTuples.getColumnValue(1)) &&
-            (uniqueTuples.getColumnValue(2) == baseTuples.getColumnValue(2)))) {
-
-          // Get the next item to search.
-          while (uniqueTuples.next()) {
-
-            // Check to see that there is a next value.  There will be at least
-            // one value as the items to search are based on the original tuples.
-            if ((uniqueTuples.getColumnValue(0) == uniqueTuples.getColumnValue(1)) &&
-                (uniqueTuples.getColumnValue(1) == uniqueTuples.getColumnValue(2))) {
-              baseTuples.beforeFirst(new long[] { uniqueTuples.getColumnValue(0),
-                  uniqueTuples.getColumnValue(1),
-                  uniqueTuples.getColumnValue(2) }, 0);
-              hasNextBase = baseTuples.next();
-              if (hasNextBase) {
-                break;
-              }
-            }
-          }
-        }
-        hasNext = hasNextBase;
-      }
-      return hasNext;
-    }
-  }
-
-  /**
-   * Returns the long representation of the constraint element or
-   * NodePool.NONE if a variable.
-   *
-   * @param constraintElement the constraint element to resolve.
-   * @throws TuplesException if the constraint element is not supported.
-   * @return long the long representation of the constraint element.
-   */
-  protected static long toGraphTuplesIndex(ConstraintElement constraintElement)
-      throws TuplesException {
-    if (constraintElement instanceof Variable) {
-      return NodePool.NONE;
-    }
-    if (constraintElement instanceof LocalNode) {
-      return ((LocalNode) constraintElement).getValue();
-    }
-
-    throw new TuplesException("Unsupported constraint element: " +
-        constraintElement + " (" + constraintElement.getClass() + ")");
-  }
-}

Deleted: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolutionUnitTest.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolutionUnitTest.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolutionUnitTest.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,405 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is the Kowari Metadata Store.
- *
- * The Initial Developer of the Original Code is Plugged In Software Pty
- * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
- * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
- * Plugged In Software Pty Ltd. All Rights Reserved.
- *
- * Contributor(s): N/A.
- *
- * [NOTE: The text of this Exhibit A may differ slightly from the text
- * of the notices in the Source Code files of the Original Code. You
- * should use the text of this Exhibit A rather than the text found in the
- * Original Code Source Code for Your Modifications.]
- *
- */
-
-package org.mulgara.resolver.store;
-
-import java.util.*;
-
-// JUnit
-import junit.framework.*;
-
-// Log4J
-import org.apache.log4j.Logger;
-
-// Local packages
-import org.mulgara.store.statement.*;
-import org.mulgara.store.tuples.LiteralTuples;
-import org.mulgara.store.tuples.Tuples;
-
-/**
- * Test case for {@link StatementStoreDuplicateResolution}.
- *
- * @created 2004-06-15
- *
- * @author Andrew Newman
- *
- * @version $Revision: 1.3 $
- *
- * @modified $Date: 2005/01/05 04:58:55 $
- *
- * @maintenanceAuthor $Author: newmana $
- *
- * @company <A href="mailto:info at PIsoftware.com">Plugged In Software</A>
- *
- * @copyright &copy; 2003 <A href="http://www.PIsoftware.com/">Plugged In
- *      Software Pty Ltd</A>
- *
- * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
- */
-public class StatementStoreDuplicateResolutionUnitTest extends TestCase {
-
-  /**
-   * Logger.
-   */
-  private Logger logger =
-      Logger.getLogger(StatementStoreDuplicateResolutionUnitTest.class.getName());
-
-  /**
-   * Tuples for testing with.
-   */
-  private LiteralTuples t1, t2, t3, t4;
-
-  /**
-   * Constrained negation test tuples.
-   */
-  private StatementStoreDuplicateResolution tuples;
-
-  /**
-   * Constructs a new test with the given name.
-   *
-   * @param name the name of the test
-   */
-  public StatementStoreDuplicateResolutionUnitTest(String name) {
-    super(name);
-  }
-
-  /**
-   * Hook for test runner to obtain a test suite from.
-   *
-   * @return The test suite
-   */
-  public static Test suite() {
-
-    TestSuite suite = new TestSuite();
-
-    suite.addTest(new StatementStoreDuplicateResolutionUnitTest("testSubjectPredicate"));
-    suite.addTest(new StatementStoreDuplicateResolutionUnitTest("testSubjectObject"));
-    suite.addTest(new StatementStoreDuplicateResolutionUnitTest("testPredicateObject"));
-    suite.addTest(new StatementStoreDuplicateResolutionUnitTest("testSubjectPredicateObject"));
-
-    return suite;
-  }
-
-  /**
-   * Create test instance.
-   *
-   * @throws Exception EXCEPTION TO DO
-   */
-  public void setUp() throws Exception {
-
-    String[] var1 = new String[] { "x", "y", "z" };
-    t1 = new LiteralTuples(var1);
-    long[][] subjectTuples = new long[][] {
-        new long[] { 1, 1, 1 },
-        new long[] { 1, 3, 1 },
-        new long[] { 1, 3, 4 },
-        new long[] { 1, 4, 1 },
-        new long[] { 2, 1, 4 },
-        new long[] { 2, 2, 2 },
-        new long[] { 2, 2, 3 },
-        new long[] { 2, 2, 4 },
-        new long[] { 2, 2, 5 },
-        new long[] { 2, 3, 1 },
-        new long[] { 3, 1, 1 },
-        new long[] { 3, 1, 3 },
-        new long[] { 3, 3, 3 },
-        new long[] { 3, 2, 4 },
-        new long[] { 4, 1, 1 },
-        new long[] { 4, 4, 1 },
-        new long[] { 4, 5, 4 },
-        new long[] { 4, 5, 6 },
-        new long[] { 4, 5, 7 },
-        new long[] { 5, 5, 5 },
-        new long[] { 6, 6, 6 },
-        new long[] { 7, 7, 7 },
-        new long[] { 7, 8, 1 },
-    };
-
-    for (int i = 0; i < subjectTuples.length; i++) {
-      ((LiteralTuples) t1).appendTuple(subjectTuples[i]);
-    }
-
-    String[] var2 = new String[] { "y", "z", "x" };
-    t2 = new LiteralTuples(var2);
-    long[][] predicateTuples = new long[][] {
-        new long[] { 1, 1, 1 },
-        new long[] { 1, 1, 3 },
-        new long[] { 1, 1, 4 },
-        new long[] { 1, 3, 3 },
-        new long[] { 1, 4, 2 },
-        new long[] { 2, 2, 2 },
-        new long[] { 2, 3, 2 },
-        new long[] { 2, 4, 2 },
-        new long[] { 2, 4, 3 },
-        new long[] { 2, 5, 2 },
-        new long[] { 3, 1, 1 },
-        new long[] { 3, 1, 2 },
-        new long[] { 3, 3, 3 },
-        new long[] { 3, 4, 1 },
-        new long[] { 4, 1, 1 },
-        new long[] { 4, 1, 4 },
-        new long[] { 5, 4, 4 },
-        new long[] { 5, 6, 4 },
-        new long[] { 5, 7, 4 },
-        new long[] { 5, 5, 5 },
-        new long[] { 6, 6, 6 },
-        new long[] { 7, 7, 7 },
-        new long[] { 8, 1, 7 },
-    };
-
-    for (int i = 0; i < predicateTuples.length; i++) {
-      ((LiteralTuples) t2).appendTuple(predicateTuples[i]);
-    }
-
-    String[] var4 = new String[] { "x", "z", "y" };
-    t4 = new LiteralTuples(var4);
-    long[][] subjectObjectTuples = new long[][] {
-        new long[] { 1, 1, 1 },
-        new long[] { 1, 1, 3 },
-        new long[] { 1, 1, 4 },
-        new long[] { 1, 4, 3 },
-        new long[] { 2, 1, 3 },
-        new long[] { 2, 2, 2 },
-        new long[] { 2, 3, 2 },
-        new long[] { 2, 4, 1 },
-        new long[] { 2, 4, 2 },
-        new long[] { 2, 5, 2 },
-        new long[] { 3, 1, 1 },
-        new long[] { 3, 3, 1 },
-        new long[] { 3, 3, 3 },
-        new long[] { 3, 4, 2 },
-        new long[] { 4, 1, 1 },
-        new long[] { 4, 1, 4 },
-        new long[] { 4, 4, 5 },
-        new long[] { 4, 6, 5 },
-        new long[] { 4, 7, 5 },
-        new long[] { 5, 5, 5 },
-        new long[] { 6, 6, 6 },
-        new long[] { 7, 1, 8 },
-        new long[] { 7, 7, 7 },
-    };
-
-    for (int i = 0; i < subjectObjectTuples.length; i++) {
-      ((LiteralTuples) t4).appendTuple(subjectObjectTuples[i]);
-    }
-  }
-
-  /**
-   * Default text runner.
-   *
-   * @param args The command line arguments
-   */
-  public static void main(String[] args) {
-
-    junit.textui.TestRunner.run(suite());
-  }
-
-  //
-  // Test cases
-  //
-
-  /**
-   * Test a constraint where the subject and predicate are the same.
-   *
-   * @throws Exception if query fails when it should have succeeded
-   */
-  public void testSubjectPredicate() throws Exception {
-
-    // Not subject = 1.
-    tuples = new StatementStoreDuplicateResolution(
-        new boolean[] { true, true, false }, t1, new int[] { 0, 1, 2, 3});
-
-    // Expected results
-    long[][] expectedTuples = new long[][] {
-        new long[] { 1, 1, 1 },
-        new long[] { 2, 2, 2 },
-        new long[] { 2, 2, 3 },
-        new long[] { 2, 2, 4 },
-        new long[] { 2, 2, 5 },
-        new long[] { 3, 3, 3 },
-        new long[] { 4, 4, 1 },
-        new long[] { 5, 5, 5 },
-        new long[] { 6, 6, 6 },
-        new long[] { 7, 7, 7 },
-    };
-
-    testTuples(expectedTuples, tuples);
-  }
-
-  /**
-   * Test a constraint where the predicate and object are the same.
-   *
-   * @throws Exception if query fails when it should have succeeded
-   */
-  public void testPredicateObject() throws Exception {
-
-    // Not subject = 1.
-    tuples = new StatementStoreDuplicateResolution(
-        new boolean[] { false, true, true }, t2, new int[] { 1, 2, 0, 3});
-
-    // Expected results
-    long[][] expectedTuples = new long[][] {
-        new long[] { 1, 1, 1 },
-        new long[] { 1, 1, 3 },
-        new long[] { 1, 1, 4 },
-        new long[] { 2, 2, 2 },
-        new long[] { 3, 3, 3 },
-        new long[] { 5, 5, 5 },
-        new long[] { 6, 6, 6 },
-        new long[] { 7, 7, 7 },
-    };
-
-    testTuples(expectedTuples, tuples);
-  }
-
-  /**
-   * Test a constraint where the subject and object are the same.
-   *
-   * @throws Exception if query fails when it should have succeeded
-   */
-  public void testSubjectObject() throws Exception {
-
-    // Not subject = 1.
-    tuples = new StatementStoreDuplicateResolution(
-        new boolean[] { true, false, true }, t4, new int[] { 0, 2, 1, 3});
-
-    // Expected results
-    long[][] expectedTuples = new long[][] {
-        new long[] { 1, 1, 1 },
-        new long[] { 1, 1, 3 },
-        new long[] { 1, 1, 4 },
-        new long[] { 2, 2, 2 },
-        new long[] { 3, 3, 1 },
-        new long[] { 3, 3, 3 },
-        new long[] { 4, 4, 5 },
-        new long[] { 5, 5, 5 },
-        new long[] { 6, 6, 6 },
-        new long[] { 7, 7, 7 },
-    };
-
-    testTuples(expectedTuples, tuples);
-  }
-
-  /**
-   * Test a constraint where the subject, predicate and object are the same.
-   *
-   * @throws Exception if query fails when it should have succeeded
-   */
-  public void testSubjectPredicateObject() throws Exception {
-
-    // Not subject = 1.
-    tuples = new StatementStoreDuplicateResolution(
-        new boolean[] { true, true, true }, t1, new int[] { 0, 1, 2, 3});
-
-    // Expected results
-    long[][] expectedTuples = new long[][] {
-        new long[] { 1, 1, 1 },
-        new long[] { 2, 2, 2 },
-        new long[] { 3, 3, 3 },
-        new long[] { 5, 5, 5 },
-        new long[] { 6, 6, 6 },
-        new long[] { 7, 7, 7 },
-    };
-
-    testTuples(expectedTuples, tuples);
-
-    String[] vars1a = new String[] { "x", "y", "z" };
-    Tuples t1a = new LiteralTuples(vars1a);
-    long[][] t1aTuples = new long[][] {
-        new long[] { 3897, 3906, 3906 },
-        new long[] { 3897, 3908, 3908 },
-        new long[] { 3899, 3892, 3900 },
-        new long[] { 3900, 3892, 3894 },
-        new long[] { 3906, 3892, 3894 },
-        new long[] { 3906, 3892, 3907 },
-        new long[] { 3906, 3906, 3906 },
-        new long[] { 3908, 3892, 3896 },
-        new long[] { 3908, 3892, 3908 },
-        new long[] { 3908, 3908, 3894 },
-        new long[] { 3908, 3908, 3908 },
-        new long[] { 3910, 3892, 3902 },
-        new long[] { 3910, 3910, 3910 },
-        new long[] { 3911, 3892, 3904 },
-        new long[] { 3911, 3892, 3911 },
-    };
-
-    for (int i = 0; i < t1aTuples.length; i++) {
-      ((LiteralTuples) t1a).appendTuple(t1aTuples[i]);
-    }
-
-    tuples = new StatementStoreDuplicateResolution(new boolean[] { true, true, true},
-        t1a, new int[] { 0, 1, 2, 3});
-
-    expectedTuples = new long[][] {
-        new long[] { 3906, 3906, 3906 },
-        new long[] { 3908, 3908, 3908 },
-        new long[] { 3910, 3910, 3910 },
-    };
-
-    testTuples(expectedTuples, tuples);
-  }
-
-  /**
-   * Test that we have the expected number and values of Tuples.
-   *
-   * @throws Exception if query fails when it should have succeeded
-   */
-  public void testTuples(long[][] expectedTuples, Tuples result)
-      throws Exception {
-
-    assertTrue("Expected: " + expectedTuples.length + ", " +
-        result.getRowCount(), expectedTuples.length == result.getRowCount());
-
-    if (result.getRowCount() > 0) {
-      result.beforeFirst();
-      result.next();
-
-      int index = 0;
-      do {
-
-        long tuple[] = new long[] {
-            result.getColumnValue(0),
-            result.getColumnValue(1),
-            result.getColumnValue(2)
-        };
-
-        assertTrue("Expected tuple result: " + expectedTuples[index][0] + "," +
-            expectedTuples[index][1] + "," +
-            expectedTuples[index][2] + " but was: " + tuple[0] + "," + tuple[1] +
-            "," + tuple[2],
-            expectedTuples[index][0] == tuple[0] &&
-            expectedTuples[index][1] == tuple[1] &&
-            expectedTuples[index][2] == tuple[2]);
-        index++;
-        tuples.next();
-      }
-      while (index < expectedTuples.length);
-
-      assertFalse("Should be no more result tuples", tuples.next());
-    }
-  }
-}

Deleted: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreInverseResolution.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreInverseResolution.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreInverseResolution.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,670 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is the Kowari Metadata Store.
- *
- * The Initial Developer of the Original Code is Plugged In Software Pty
- * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
- * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
- * Plugged In Software Pty Ltd. All Rights Reserved.
- *
- * Contributor(s):
- *   getModel() contributed by Netymon Pty Ltd on behalf of
- *   The Australian Commonwealth Government under contract 4500507038.
- *
- * [NOTE: The text of this Exhibit A may differ slightly from the text
- * of the notices in the Source Code files of the Original Code. You
- * should use the text of this Exhibit A rather than the text found in the
- * Original Code Source Code for Your Modifications.]
- *
- */
-
-package org.mulgara.resolver.store;
-
-// Third party packages
-import org.apache.log4j.Logger;
-
-// Standard Java packages
-import java.util.*;
-
-// Locally written packages
-import org.mulgara.query.*;
-import org.mulgara.resolver.spi.Resolution;
-import org.mulgara.resolver.spi.Resolver;
-import org.mulgara.store.nodepool.NodePool;
-import org.mulgara.store.statement.StatementStore;
-import org.mulgara.store.statement.StatementStoreException;
-import org.mulgara.store.tuples.AbstractTuples;
-import org.mulgara.store.tuples.StoreTuples;
-import org.mulgara.store.tuples.Tuples;
-
-/**
- * Tuples backed by the graph, corresponding the tuples that don't match
- * a particular constraint. This class retains the original constraint so that
- * the graph index it's resolved against can be resolved anew as its variables
- * are bound.
- *
- * @created 2004-08-04
- *
- * @author Andrew Newman
- *
- * @version $Revision: 1.10 $
- *
- * @modified $Date: 2005/05/02 20:07:58 $ by $Author: raboczi $
- *
- * @maintenanceAuthor $Author: raboczi $
- *
- * @company <a href="mailto:info at PIsoftware.com">Plugged In Software</a>
- *
- * @copyright &copy; 2003 <A href="http://www.PIsoftware.com/">Plugged In
- *      Software Pty Ltd</A>
- *
- * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
- */
-class StatementStoreInverseResolution extends AbstractTuples implements Resolution {
-
-  protected static final Logger logger = Logger.getLogger(StatementStoreInverseResolution.class);
-
-  /**
-   * The constraint these tuples were generated to satisfy.
-   */
-  protected Constraint constraint;
-
-  /**
-   * The graph from which these tuples were generated.
-   */
-  protected StatementStore store;
-
-  /**
-   * The tuples.
-   */
-  private Tuples tuples;
-
-  /**
-   * The long representation of the subject node or NodePool.NONE
-   */
-  private long subject;
-
-  /**
-   * The long representation of the predicate node or NodePool.NONE
-   */
-  private long predicate;
-
-  /**
-   * The long representation of the object node or NodePool.NONE
-   */
-  private long object;
-
-  /**
-   * The long representation of the meta node or NodePool.NONE
-   */
-  private long metanode;
-
-  /**
-   * Prefix.  The prefix into the tuples to the section to exclude.
-   */
-  private long[] excludePrefix;
-
-  /**
-   * The not evaluator for a given tuples.
-   */
-  private TuplesEvaluator tuplesEvaluator;
-
-  /**
-   * Whether we've calculated the rows.
-   */
-  private boolean calculatedRowCount;
-
-  /**
-   * An array that contains the position in the tuples.  Elements 0, 1, 2, 3
-   * map to subject, predicate, object and meta and the value in the array is
-   * the column position.
-   */
-  private int[] columnOrder;
-
-  /**
-   * True when we have skipped over the block in the store.
-   */
-  private boolean skipped = false;
-
-  /**
-   * True if all constraints are fixed.
-   */
-  private boolean allFixedConstraints;
-
-  /**
-   * True if a single statement given by the constraints exists.
-   */
-  private boolean singleStatementExists;
-
-  /**
-   * Used to force the tuples to act empty, used if beforeFirst is used with a bad prefix.
-   */
-  private boolean forceEmpty;
-
-  /**
-   * Find a graph index that satisfies a constraint.
-   *
-   * @param newConstraint the constraint to satisfy
-   * @param newStore the store to resolve against
-   * @throws IllegalArgumentException if <var>constraint</var> or <var>graph
-   *      </var> is <code>null</code>
-   * @throws TuplesException EXCEPTION TO DO
-   */
-  StatementStoreInverseResolution(Constraint newConstraint, StatementStore newStore)
-      throws TuplesException {
-
-    if (newStore == null) {
-      throw new IllegalArgumentException("Cannot give null statementstore");
-    }
-
-    constraint = newConstraint;
-    store = newStore;
-
-    subject = toGraphTuplesIndex(constraint.getElement(0));
-    predicate = toGraphTuplesIndex(constraint.getElement(1));
-    object = toGraphTuplesIndex(constraint.getElement(2));
-    metanode = toGraphTuplesIndex(constraint.getModel());
-
-    allFixedConstraints = (subject != NodePool.NONE) &&
-        (predicate != NodePool.NONE) && (object != NodePool.NONE);
-
-    forceEmpty = false;
-
-    try {
-
-      if (allFixedConstraints) {
-        singleStatementExists = store.existsTriples(subject, predicate, object, metanode);
-
-        // Return the tuples for a single model
-        tuples = store.findTuples(false, false, false, true);
-        tuples.beforeFirst(new long[] {metanode}, 0);
-
-      } else {
-
-        // Return the tuples using the s, p, o hints.
-        tuples = store.findTuples(subject != NodePool.NONE,
-            predicate != NodePool.NONE,
-            object != NodePool.NONE,
-            metanode != NodePool.NONE);
-
-        if (metanode != NodePool.NONE) {
-          // go to the beginning of the fixed model
-          tuples.beforeFirst(new long[] {metanode}, 0);
-        } else {
-          // go to the beginning of all models
-          tuples.beforeFirst();
-        }
-      }
-
-      // Get the column order - this is column index -> tuples index we want
-      // tuple index -> column index
-      int[] inverseColumnOrder = ((StoreTuples) tuples).getColumnOrder();
-
-      columnOrder = new int[4];
-
-      // Create column map.
-      for (int index = 0; index < inverseColumnOrder.length; index++) {
-        columnOrder[inverseColumnOrder[index]] = index;
-      }
-
-      // Prepopulate variable list.
-      List variableList = new ArrayList(Arrays.asList(StatementStore.VARIABLES));
-      boolean changedList = false;
-
-      // Create correct variable bindings in order.
-      for (int index = 0; index < 4; index++) {
-        if (constraint.getElement(index) instanceof Variable) {
-          Variable var = (Variable) constraint.getElement(index);
-          if (!var.equals(Variable.FROM)) {
-
-            // Remove it from it's position in the list and re-add it with the
-            // correct value.
-            changedList = true;
-            variableList.remove(columnOrder[index]);
-            variableList.add(columnOrder[index], var);
-          }
-        }
-      }
-
-      setTuplesEvaluator();
-      setVariables(variableList);
-    }
-    catch (StatementStoreException se) {
-      throw new TuplesException("Failed to set-up tuples", se);
-    }
-
-  }
-
-  /**
-   * Create the appropriate tuples evaluator.
-   */
-  private void setTuplesEvaluator() {
-
-    if (((subject != NodePool.NONE) && (predicate == NodePool.NONE) && (object == NodePool.NONE)) ||
-      ((subject != NodePool.NONE) && (predicate != NodePool.NONE) && (object == NodePool.NONE)) ||
-      ((subject != NodePool.NONE) && (predicate != NodePool.NONE) && (object != NodePool.NONE))) {
-      tuplesEvaluator = new SPOTuplesEvaluator();
-
-      if ((subject != NodePool.NONE) && (predicate == NodePool.NONE) && (object == NodePool.NONE)) {
-        excludePrefix = new long[] { subject };
-      }
-      else if ((subject != NodePool.NONE) && (predicate != NodePool.NONE) && (object == NodePool.NONE)) {
-        excludePrefix = new long[] { subject, predicate };
-      }
-      else if ((subject != NodePool.NONE) && (predicate != NodePool.NONE) && (object != NodePool.NONE)) {
-        excludePrefix = new long[] { subject, predicate, object };
-      }
-    }
-    else if (((subject == NodePool.NONE) && (predicate != NodePool.NONE) && (object == NodePool.NONE)) ||
-      ((subject == NodePool.NONE) && (predicate != NodePool.NONE) && (object != NodePool.NONE))) {
-      tuplesEvaluator = new POSTuplesEvaluator();
-      if ((subject == NodePool.NONE) && (predicate != NodePool.NONE) && (object == NodePool.NONE)) {
-        excludePrefix = new long[] { predicate };
-      }
-      else if ((subject == NodePool.NONE) && (predicate != NodePool.NONE) && (object != NodePool.NONE)) {
-        excludePrefix = new long[] { predicate, object };
-      }
-    }
-    else if ((subject == NodePool.NONE) && (predicate == NodePool.NONE) && (object != NodePool.NONE)) {
-      tuplesEvaluator = new OSPTuplesEvaluator();
-      excludePrefix = new long[] { object };
-    }
-    else if ((subject != NodePool.NONE) && (predicate == NodePool.NONE) && (object != NodePool.NONE)) {
-      tuplesEvaluator = new SOPTuplesEvaluator();
-      excludePrefix = new long[] { subject, object };
-    }
-    else if ((subject == NodePool.NONE) && (predicate == NodePool.NONE) && (object == NodePool.NONE)) {
-      tuplesEvaluator = new UnconstrainedTuplesEvaluator();
-      excludePrefix = new long[] {};
-    }
-
-    // prepend the metanode if it is set
-    if (metanode != NodePool.NONE) {
-      long[] newPrefix = new long[excludePrefix.length + 1];
-      newPrefix[0] = metanode;
-      for (int i = 0; i < excludePrefix.length; i++) {
-        newPrefix[i + 1] = excludePrefix[i];
-      }
-      excludePrefix = newPrefix;
-    }
-  }
-
-  public long getRowCount() throws TuplesException {
-
-    // Only calculate rows once.
-    if (!calculatedRowCount) {
-
-      // If the exclude prefix is more than just the model then calculate otherwise we've asked
-      // for a NOT ($s $p $o) which is 0.
-      if (excludePrefix.length > 1) {
-
-        Tuples modelTuples = null;
-        Tuples excludedTuples = null;
-
-        try {
-          // get all tuples in the model
-          modelTuples = store.findTuples(NodePool.NONE, NodePool.NONE, NodePool.NONE, metanode);
-
-          // get excluded tuples in the model
-          excludedTuples = store.findTuples(subject, predicate, object, metanode);
-
-          // Calculated the excluded set from the model.
-          rowCount = modelTuples.getRowCount() - excludedTuples.getRowCount();
-
-        } catch (StatementStoreException e) {
-          throw new TuplesException("Unable to count data", e);
-        } finally {
-          try {
-            if (modelTuples != null) {
-              modelTuples.close();
-            }
-          } finally {
-            if (excludedTuples != null) {
-              excludedTuples.close();
-            }
-          }
-        }
-
-      } else {
-        rowCount = 0;
-      }
-
-      // Ensure we don't calculate the rows again.
-      calculatedRowCount = true;
-    }
-    return rowCount;
-  }
-
-  public boolean hasNoDuplicates() throws TuplesException {
-    return tuples.hasNoDuplicates();
-  }
-
-  public List getOperands() {
-    return new ArrayList();
-  }
-
-  public void beforeFirst(long[] prefix, int suffixTruncation) throws TuplesException {
-    if (prefix.length > 4) {
-      throw new TuplesException("Prefix too long");
-    }
-
-    // Reset skipped.
-    skipped = false;
-    // Reset the forceEmpty flag
-    forceEmpty = false;
-
-    if (metanode != NodePool.NONE) {
-      if (prefix.length > 0) {
-        if (prefix[0] != metanode) {
-          // no matching tuples
-          forceEmpty = true;
-        }
-      } else {
-        prefix = new long[] {metanode};
-      }
-    }
-
-    // Move to the
-    tuples.beforeFirst(prefix, suffixTruncation);
-  }
-
-  public void close() throws TuplesException {
-    if (tuples != null) {
-      tuples.close();
-    }
-  }
-
-  /**
-   * METHOD TO DO
-   *
-   * @return RETURNED VALUE TO DO
-   */
-  public Object clone() {
-    StatementStoreInverseResolution cloned = (StatementStoreInverseResolution) super.clone();
-    cloned.tuples = (Tuples) tuples.clone();
-    cloned.setVariables(getVariables());
-
-    // Create a new tuples evaluator.
-    cloned.setTuplesEvaluator();
-    return cloned;
-  }
-
-
-  public long getRowUpperBound() throws TuplesException {
-    return getRowCount();
-  }
-
-  public int getRowCardinality() throws TuplesException {
-    long count = getRowCount();
-    if (count > 1) {
-      return Cursor.MANY;
-    }
-    switch ((int) count) {
-      case 0:
-        return Cursor.ZERO;
-      case 1:
-        return Cursor.ONE;
-      default:
-        throw new TuplesException("Illegal row count: " + count);
-    }
-  }
-
-  public long getColumnValue(int column) throws TuplesException {
-    return tuples.getColumnValue(column);
-  }
-
-  public boolean isColumnEverUnbound(int column) throws TuplesException {
-    return tuples.isColumnEverUnbound(column);
-  }
-
-  public boolean isUnconstrained() throws TuplesException {
-
-    // If we have a least one variable return the tuples isUnconstrainedValue.
-    if (!allFixedConstraints) {
-      return tuples.isUnconstrained();
-    }
-    else {
-
-      // If the statement exists we are constrained.
-      if (singleStatementExists) {
-        return false;
-      }
-      else {
-        return true;
-      }
-    }
-  }
-
-  public boolean isMaterialized() {
-    return tuples.isMaterialized();
-  }
-
-  public boolean next() throws TuplesException {
-    boolean hasNext = false;
-    if (!forceEmpty) {
-      hasNext = tuplesEvaluator.next();
-    }
-    return hasNext;
-  }
-
-  /**
-   * @return the original {@link Constraint} passed to the
-   *   {@link Resolver#resolve} method to generate this {@link Resolution}
-   */
-  public Constraint getConstraint() {
-    return constraint;
-  }
-
-
-  /**
-   * If a {@link Resolver} represents a closed world, it may assert that the
-   * {@link Resolution} contains every possible solution.
-   *
-   * @return whether this {@link Resolution} includes every solution to the constraint
-   */
-  public boolean isComplete() {
-    return true;
-  }
-
-
-  public String toString() {
-    return "not " + tuples.toString() + " from constraint " + constraint;
-  }
-
-  /**
-   * Returns the long representation of the constraint element or
-   * NodePool.NONE if a variable.
-   *
-   * @param constraintElement the constraint element to resolve.
-   * @throws TuplesException if the constraint element is not supported.
-   * @return long the long representation of the constraint element.
-   */
-  protected static long toGraphTuplesIndex(ConstraintElement constraintElement)
-      throws TuplesException {
-    if (constraintElement instanceof Variable) {
-      return NodePool.NONE;
-    }
-    if (constraintElement instanceof LocalNode) {
-      return ((LocalNode) constraintElement).getValue();
-    }
-
-    throw new TuplesException("Unsupported constraint element: " +
-        constraintElement + " (" + constraintElement.getClass() + ")");
-  }
-
-  /**
-   * A decorator around the next() method on a tuples that skips a set of
-   * statements if they are given in the constraint.
-   */
-  private interface TuplesEvaluator {
-
-    /**
-     * Returns true if there is another tuples.  Calling next may skip a set
-     * of tuples based on the constraint.
-     *
-     * @throws TuplesException if there was a problem accessing the tuples.
-     * @return true if there is another tuples.
-     */
-    public boolean next() throws TuplesException;
-  }
-
-  /**
-   * The evaluator for the S, P, O constrained tuples.
-   */
-  private class SPOTuplesEvaluator implements TuplesEvaluator {
-
-    public boolean next() throws TuplesException {
-
-      // Iterate forward one.
-      boolean moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-
-      // If we've skipped over the tuples then just call the normal tuples.next.
-      if (!skipped) {
-
-        // Assume that the subject is always bound - otherwise wouldn't be used.
-        // If the predicate is also constrained iterate through these.
-        if (predicate != NodePool.NONE) {
-
-          // If the predicate is also constrained iterate through these.
-          if (object != NodePool.NONE) {
-
-            // If we match then skip over the totally constrained tuple.
-            if ((moreTuples) &&
-                (tuples.getColumnValue(columnOrder[0]) == subject) &&
-                (tuples.getColumnValue(columnOrder[1]) == predicate) &&
-                (tuples.getColumnValue(columnOrder[2]) == object)) {
-              moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-              skipped = true;
-            }
-          }
-          else {
-
-            // Skip over all the objects for the given subject, predicate.
-            while ((moreTuples) &&
-                (tuples.getColumnValue(columnOrder[0]) == subject) &&
-                (tuples.getColumnValue(columnOrder[1]) == predicate)) {
-              moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-              skipped = true;
-            }
-          }
-        }
-        else {
-
-          // Skip over all the predicate, objects for the given subject.
-          while ((moreTuples) &&
-              (tuples.getColumnValue(columnOrder[0]) == subject)) {
-            moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-            skipped = true;
-          }
-        }
-      }
-      return moreTuples;
-    }
-  }
-
-  /**
-   * The evaluator for the P, O, S constrained tuples.
-   */
-  private class POSTuplesEvaluator implements TuplesEvaluator {
-
-    public boolean next() throws TuplesException {
-
-      // Iterate forward one.
-      boolean moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-
-      // If we've skipped over the tuples then just call the normal tuples.next.
-      if (!skipped) {
-
-        // If the object is also constrained iterate through these.
-        if (object != NodePool.NONE) {
-
-          // Skip over all the subjects for the given predicate, objects.
-          while ((moreTuples) &&
-              (tuples.getColumnValue(columnOrder[1]) == predicate) &&
-              (tuples.getColumnValue(columnOrder[2]) == object)) {
-            moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-            skipped = true;
-          }
-        }
-        else {
-
-          // Skip over all the object, subjects for the given predicate.
-          while ((moreTuples) &&
-              (tuples.getColumnValue(columnOrder[1]) == predicate)) {
-            moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-            skipped = true;
-          }
-        }
-      }
-      return moreTuples;
-    }
-  }
-
-  /**
-   * The evaluator for the O, S, P constrained tuples.
-   */
-  private class OSPTuplesEvaluator implements TuplesEvaluator {
-
-    public boolean next() throws TuplesException {
-
-      // Iterate forward one.
-      boolean moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-
-      // If we've skipped over the tuples then just call the normal tuples.next.
-      if (!skipped) {
-
-        // Skip over all the subject, predicates for the given object.
-        while ((moreTuples) &&
-            (tuples.getColumnValue(columnOrder[2]) == object)) {
-          moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-          skipped = true;
-        }
-      }
-      return moreTuples;
-    }
-  }
-
-  /**
-   * The evaluator for the S, O, P constrained tuples.
-   */
-  private class SOPTuplesEvaluator implements TuplesEvaluator {
-
-    public boolean next() throws TuplesException {
-
-      // Iterate forward one.
-      boolean moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-
-      // If we've skipped over the tuples then just call the normal tuples.next.
-      if (!skipped) {
-
-        // Skip over all the subject, predicates for the given object.
-        while ((moreTuples) &&
-            (tuples.getColumnValue(columnOrder[0]) == subject) &&
-            (tuples.getColumnValue(columnOrder[2]) == object)) {
-          moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-          skipped = true;
-        }
-      }
-      return moreTuples;
-    }
-  }
-
-  /**
-   * The evaluator when none of the tuples are constrained.
-   */
-  private class UnconstrainedTuplesEvaluator implements TuplesEvaluator {
-
-    public boolean next() throws TuplesException {
-      return false;
-    }
-  }
-}

Modified: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolution.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolution.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolution.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -40,8 +40,6 @@
 // Locally written packages
 import org.mulgara.query.*;
 import org.mulgara.resolver.spi.ReresolvableResolution;
-import org.mulgara.resolver.spi.Resolution;
-import org.mulgara.resolver.spi.Resolver;
 import org.mulgara.store.nodepool.NodePool;
 import org.mulgara.store.statement.StatementStore;
 import org.mulgara.store.statement.StatementStoreException;
@@ -241,6 +239,7 @@
   /**
    * @param bound constraints to be bound post-beforeFirst.  In constraint-order.
    */
+  @SuppressWarnings("unchecked")
   protected void defineIndex(boolean[] bound) throws TuplesException {
     assert bound.length == 4;
 
@@ -254,8 +253,7 @@
 
     if (indexedTuples != null) {
       if (logger.isDebugEnabled()) {
-        logger.debug("Orig indexedTuples.variables = " +
-                    toString(indexedTuples.getVariables()));
+        logger.debug("Orig indexedTuples.variables = " + toString(indexedTuples.getVariables()));
       }
       indexedTuples.close();
     }
@@ -352,14 +350,14 @@
   }
 
 
-  public ReresolvableResolution reresolve(final Map bindings) throws TuplesException {
+  public ReresolvableResolution reresolve(final Map<? extends ConstraintElement, Long> bindings) throws TuplesException {
     boolean reconstrain = false;
     ConstraintElement[] e = new ConstraintElement[4];
     for (int i = 0; i < 4; i++) {
       e[i] = constraint.getElement(i);
 
       if (e[i] instanceof Variable) {
-        Long value = (Long)bindings.get(e[i]);
+        Long value = bindings.get(e[i]);
         if (value != null) {
           e[i] = new LocalNode(value.longValue());
           reconstrain = true;
@@ -445,8 +443,8 @@
   }
 
 
-  public List getOperands() {
-    return Collections.EMPTY_LIST;
+  public List<Tuples> getOperands() {
+    return Collections.emptyList();
   }
 
 
@@ -557,17 +555,17 @@
     return this;
   }
 
-  public Annotation getAnnotation(Class annotation) {
+  public Annotation getAnnotation(Class<? extends Annotation> annotation) {
     if (annotation.equals(DefinablePrefixAnnotation.class)) {
       return new DefinablePrefixAnnotation() {
-        public void definePrefix(Set boundVars) throws TuplesException {
+        public void definePrefix(Set<Variable> boundVars) throws TuplesException {
           boolean[] bound = new boolean[4];
           Constraint constraint = getConstraint();
           for (int i = 0; i < 4; i++) {
             ConstraintElement elem = constraint.getElement(i);
             if (elem instanceof LocalNode) {
               bound[i] = true;
-            } else if (boundVars.contains((Variable)elem)) {
+            } else if (boundVars.contains(elem)) {
               bound[i] = true;
             } else {
               bound[i] = false;

Modified: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -355,7 +355,7 @@
         
         if (occurs) {
           // statement is asserted to be true
-          logger.debug("Inserting statement: [" + subject + " "
+          if (logger.isDebugEnabled()) logger.debug("Inserting statement: [" + subject + " "
                                                 + predicate + " "
                                                 + object + "] in " + model);
 
@@ -391,8 +391,6 @@
         if (!constraint.isRepeating()) {
           if (constraint instanceof ConstraintImpl) {
             return new StatementStoreResolution(constraint, statementStore);
-          } else if (constraint instanceof ConstraintNegation) {
-            return new StatementStoreInverseResolution(constraint, statementStore);
           } else {
             throw new QueryException("Unable to resolve constraint " + constraint + " unknown type");
           }
@@ -526,4 +524,11 @@
     }
   }
 
+  /**
+   * @see org.mulgara.resolver.spi.SystemResolver#initializeSystemNodes(long, long, long)
+   */
+  public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
+    statementStore.initializeSystemNodes(systemGraphNode, rdfTypeNode, systemGraphTypeNode);
+  }
+
 }

Modified: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolverFactory.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolverFactory.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolverFactory.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -71,9 +71,9 @@
   private long rdfType;
 
   /** The underlying transactional graph that backs the generated resolvers.  */
-  private final XAStatementStore statementStore;
+  protected final XAStatementStore statementStore;
 
-  private XAResolverSessionFactory resolverSessionFactory;
+  protected XAResolverSessionFactory resolverSessionFactory;
 
   //
   // Constructors
@@ -86,7 +86,7 @@
    * @throws IllegalArgumentException {@inheritDoc}
    * @throws ResolverException {@inheritDoc}
    */
-  private StatementStoreResolverFactory(FactoryInitializer initializer,
+  protected StatementStoreResolverFactory(FactoryInitializer initializer,
       XAResolverSessionFactory resolverSessionFactory) throws
       InitializerException {
     // Validate parameters
@@ -96,7 +96,7 @@
 
     try {
       File filePrefix = new File(initializer.getDirectory(), "xa");
-      statementStore = new XAStatementStoreImpl(filePrefix.toString());
+      statementStore = createStore(filePrefix.toString());
       resolverSessionFactory.registerStatementStore(statementStore);
     } catch (Exception e) {
       throw new InitializerException("Couldn't initialize XA store", e);
@@ -238,4 +238,15 @@
           "Failed to obtain a new ResolverSession", er);
     }
   }
+
+
+  /**
+   * Creates the required type of store
+   * @param filePrefix The base for the files being used for storage.
+   * @return a new instance of an XAStatementStore
+   * @throws IOException Error accessing the filesystem
+   */
+  protected XAStatementStore createStore(String filePrefix) throws IOException {
+    return new XAStatementStoreImpl(filePrefix.toString());
+  }
 }

Copied: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/XA11StatementStoreResolverFactory.java (from rev 1456, branches/xa11/src/jar/resolver-store/java/org/mulgara/resolver/store/XA11StatementStoreResolverFactory.java)
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/XA11StatementStoreResolverFactory.java	                        (rev 0)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/XA11StatementStoreResolverFactory.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -0,0 +1,64 @@
+/*
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+
+package org.mulgara.resolver.store;
+
+import java.io.IOException;
+
+import org.mulgara.resolver.spi.FactoryInitializer;
+import org.mulgara.resolver.spi.InitializerException;
+import org.mulgara.resolver.spi.ResolverFactory;
+import org.mulgara.store.statement.xa11.XA11StatementStoreImpl;
+import org.mulgara.store.xa.XAResolverSessionFactory;
+import org.mulgara.store.xa.XAStatementStore;
+
+/**
+ * An extension of StatementStoreResolverFactory which instantiates an XA 1.1 statement store.
+ *
+ * @created Oct 1, 2008
+ * @author Paul Gearon
+ * @copyright &copy; 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class XA11StatementStoreResolverFactory extends StatementStoreResolverFactory {
+
+  /**
+   * Internal construction of a resolver factory.
+   * @throws InitializerException Unable to initialize.
+   */
+  protected XA11StatementStoreResolverFactory(FactoryInitializer initializer,
+      XAResolverSessionFactory resolverSessionFactory) throws InitializerException {
+    super(initializer, resolverSessionFactory);
+  }
+
+  /**
+   * Factory method for instances of this factory
+   * @param initializer Configuration object for this factory.
+   * @param resolverSessionFactory A factory that this factory can proxy for getting sessions. 
+   * @return A new factory for resolver sessions.
+   * @throws InitializerException The factory could not be initialized.
+   */
+  public static ResolverFactory newInstance(FactoryInitializer initializer,
+        XAResolverSessionFactory resolverSessionFactory) throws InitializerException {
+    return new XA11StatementStoreResolverFactory(initializer, resolverSessionFactory);
+  }
+
+  /**
+   * Creates the required type of store
+   * @param filePrefix The base for the files being used for storage.
+   * @return a new instance of an XAStatementStore
+   * @throws IOException Error accessing the filesystem
+   */
+  protected XAStatementStore createStore(String filePrefix) throws IOException {
+    return new XA11StatementStoreImpl(filePrefix.toString());
+  }
+}

Modified: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/TripleAVLFile.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/TripleAVLFile.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/TripleAVLFile.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -413,7 +413,7 @@
    * Inner class to compare two triples in an int buffer, using a given ordering
    * for each of the node columns.
    */
-  private final static class TripleComparator implements Comparator {
+  private final static class TripleComparator implements Comparator<Object> {
 
     private int offset;
 
@@ -539,6 +539,7 @@
         HEADER_SIZE + AVLFile.Phase.RECORD_SIZE +
         ManagedBlockFile.Phase.RECORD_SIZE;
 
+    @SuppressWarnings("unused")
     private final static int IDX_NR_FILE_TRIPLES = 0;
 
     private long nrFileTriples;
@@ -977,7 +978,7 @@
                 node, node.getNextNode()
             };
           }
-          int li = avlFile.leafIndex(findResult);
+          int li = AVLFile.leafIndex(findResult);
           findResult[li].insert(newNode, 1 - li);
 
           if (index == MAX_TRIPLES || index > splitPoint) {
@@ -1189,6 +1190,39 @@
     }
 
 
+    public StoreTuples findTuplesForMeta(long graph) throws IOException {
+      long[] startTriple = new long[SIZEOF_TRIPLE];
+      long[] endTriple = new long[SIZEOF_TRIPLE];
+      startTriple[order0] = graph;
+      endTriple[order0] = graph + 1;
+      return new MetaTuplesImpl(startTriple, endTriple, 1);
+    }
+
+
+    public StoreTuples findTuplesForMeta(long graph, long node1) throws IOException {
+      long[] startTriple = new long[SIZEOF_TRIPLE];
+      long[] endTriple = new long[SIZEOF_TRIPLE];
+      startTriple[order0] = graph;
+      startTriple[order1] = node1;
+      endTriple[order0] = graph;
+      endTriple[order1] = node1 + 1;
+      return new MetaTuplesImpl(startTriple, endTriple, 2);
+    }
+
+
+    public StoreTuples findTuplesForMeta(long graph, long node1, long node2) throws IOException {
+      long[] startTriple = new long[SIZEOF_TRIPLE];
+      long[] endTriple = new long[SIZEOF_TRIPLE];
+      startTriple[order0] = graph;
+      startTriple[order1] = node1;
+      startTriple[order2] = node2;
+      endTriple[order0] = graph;
+      endTriple[order1] = node1;
+      endTriple[order2] = node2 + 1;
+      return new MetaTuplesImpl(startTriple, endTriple, 3);
+    }
+
+
     public StoreTuples allTuples() {
       return new TuplesImpl();
     }
@@ -1386,7 +1420,7 @@
     }
 
 
-    long checkIntegrity() {
+    public long checkIntegrity() {
       if (this == currentPhase && tripleWriteThread != null)
         tripleWriteThread.drain();
 
@@ -1661,12 +1695,11 @@
     }
 
 
-    private final class TuplesImpl implements StoreTuples {
+    private abstract class AbstractStoreTuples implements StoreTuples {
 
       // keep a stack trace of the instantiation of this object
-      @SuppressWarnings("unused")
-      private StackTrace stack = logger.isDebugEnabled() ? new StackTrace() : null;
-      private List<Integer> objectIds = new ArrayList<Integer>();
+      protected StackTrace stack = logger.isDebugEnabled() ? new StackTrace() : null;
+      protected List<Integer> objectIds = new ArrayList<Integer>();
 
       private long[] startTriple;
 
@@ -1676,7 +1709,7 @@
 
       private TripleLocation end;
 
-      private Token token;
+      protected Token token;
 
       private long nrTriples;
 
@@ -1685,21 +1718,21 @@
       @SuppressWarnings("unused")
       private int prefixLength;
 
-      private int[] columnMap;
+      protected int[] columnMap;
 
-      private Variable[] variables;
+      protected Variable[] variables;
 
       private long[] tmpTriple = new long[SIZEOF_TRIPLE];
 
-      private AVLNode node;
+      protected AVLNode node;
 
-      private boolean beforeStart;
+      protected boolean beforeStart;
 
       private int nrBlockTriples = 0;
 
-      private Block tripleBlock = null;
+      protected Block tripleBlock = null;
 
-      private int offset;
+      protected int offset;
 
       private long endBlockId = Block.INVALID_BLOCK_ID;
 
@@ -1717,7 +1750,7 @@
        * @param prefixLength PARAMETER TO DO
        * @throws IOException EXCEPTION TO DO
        */
-      TuplesImpl(
+      AbstractStoreTuples(
           long[] startTriple, long[] endTriple,
           int prefixLength
       ) throws IOException {
@@ -1729,19 +1762,6 @@
         this.endTriple = endTriple;
         this.prefixLength = prefixLength;
 
-        int nrColumns = SIZEOF_TRIPLE - prefixLength;
-
-        // Set up a column order which moves the prefix columns to the end.
-        columnMap = new int[nrColumns];
-        for (int i = 0; i < nrColumns; ++i) {
-          columnMap[i] = sortOrder[(i + prefixLength) % SIZEOF_TRIPLE];
-        }
-
-        variables = new Variable[nrColumns];
-        for (int i = 0; i < nrColumns; ++i) {
-          variables[i] = StatementStore.VARIABLES[columnMap[i]];
-        }
-
         start = findTriple(startTriple);
         end = findTriple(endTriple);
 
@@ -1761,7 +1781,7 @@
       /**
        * CONSTRUCTOR TuplesImpl TO DO
        */
-      TuplesImpl() {
+      AbstractStoreTuples() {
         if (Phase.this == currentPhase && tripleWriteThread != null) tripleWriteThread.drain();
 
         this.nrTriples = Phase.this.nrFileTriples;
@@ -1898,8 +1918,8 @@
       }
 
 
-      public List getOperands() {
-        return new ArrayList(0);
+      public List<Tuples> getOperands() {
+        return Collections.emptyList();
       }
 
 
@@ -2057,7 +2077,7 @@
 
       public Object clone() {
         try {
-          TuplesImpl copy = (TuplesImpl) super.clone();
+          AbstractStoreTuples copy = (AbstractStoreTuples) super.clone();
           tmpTriple = new long[SIZEOF_TRIPLE];
           if (start != null) {
             start.node.incRefCount();
@@ -2220,11 +2240,100 @@
       /**
        * Copied from AbstractTuples
        */
-      public Annotation getAnnotation(Class annotationClass) throws TuplesException {
+      public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
         return null;
       }
     }
 
+    /**
+     * The standard implementation of the StoreTuples for this phase.
+     */
+    private final class TuplesImpl extends AbstractStoreTuples {
+      TuplesImpl(long[] startTriple, long[] endTriple, int prefixLength) throws IOException {
+        super(startTriple, endTriple, prefixLength);
+        int nrColumns = SIZEOF_TRIPLE - prefixLength;
+
+        variables = new Variable[nrColumns];
+        // Set up a column order which moves the prefix columns to the end.
+        columnMap = new int[nrColumns];
+
+        for (int i = 0; i < nrColumns; ++i) {
+          columnMap[i] = sortOrder[(i + prefixLength) % SIZEOF_TRIPLE];
+          variables[i] = StatementStore.VARIABLES[columnMap[i]];
+        }
+
+      }
+
+      TuplesImpl() {
+        super();
+      }
+    }
+
+    /**
+     * A version of StoreTuples which is designed to set the Meta variable to a requested value.
+     *
+     * @created Dec 22, 2008
+     * @author Paul Gearon
+     * @copyright &copy; 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+     * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+     */
+    private final class MetaTuplesImpl extends AbstractStoreTuples {
+
+      /** The meta node this tuples comes from. */
+      private final long metaNode;
+
+      /**
+       * Constructs the Tuples to come from the store.
+       * @param startTriple The first triple for this tuples.
+       * @param endTriple The first triple pattern that is NOT part of this tuples.
+       *                  This may not appear in the store, but if anything is <= this triple
+       *                  then it is NOT in the tuples.
+       * @param prefixLength The number of elements used to identify the requires triples.
+       * @throws IOException If there was an I/O error accessing the triples data in the store.
+       */
+      MetaTuplesImpl(long[] startTriple, long[] endTriple, int prefixLength) throws IOException {
+        super(startTriple, endTriple, prefixLength);
+        int nrColumns = SIZEOF_TRIPLE - prefixLength;
+        variables = new Variable[nrColumns + 1];
+
+        // Set up a column order which moves the prefix columns to the end.
+        columnMap = new int[nrColumns + 1];
+
+        for (int i = 0; i < nrColumns; ++i) {
+          columnMap[i] = sortOrder[(i + prefixLength) % SIZEOF_TRIPLE];
+          variables[i] = StatementStore.VARIABLES[columnMap[i]];
+        }
+        // make the last variable "Meta"
+        columnMap[nrColumns] = nrColumns;
+        variables[nrColumns] = StatementStore.VARIABLES[StatementStore.VARIABLES.length - 1];
+        metaNode = startTriple[order0];
+      }
+
+      /**
+       * Get the value from the given column on the current row.
+       * @param column The column to get the value of the binding from.
+       * @return The binding for the given column on the current row.
+       * @throws TuplesException If the current state is wrong, or if the column requested is invalid.
+       */
+      public long getColumnValue(int column) throws TuplesException {
+        if (column == variables.length - 1) return metaNode;
+        // inlining rather than calling to super
+        try {
+          return tripleBlock.getLong(offset * SIZEOF_TRIPLE + columnMap[column]);
+        } catch (ArrayIndexOutOfBoundsException ex) {
+          if (column < 0 || column >= variables.length) {
+            throw new TuplesException("Column index out of range: " + column);
+          }
+          throw ex;
+        } catch (NullPointerException ex) {
+          if (beforeStart || node == null) {
+            throw new TuplesException("No current row.  Before start: " + beforeStart + " node: " + node);
+          }
+          throw ex;
+        }
+      }
+
+    }
   }
 
 }

Modified: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImpl.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImpl.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImpl.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -37,7 +37,6 @@
 
 // Locally written packages
 import org.mulgara.query.*;
-import org.mulgara.store.*;
 import org.mulgara.store.nodepool.*;
 import org.mulgara.store.statement.*;
 import org.mulgara.store.tuples.StoreTuples;
@@ -293,7 +292,7 @@
   /**
    * Description of the Field
    */
-  private List releaseNodeListeners = new ArrayList();
+  private List<ReleaseNodeListener> releaseNodeListeners = new ArrayList<ReleaseNodeListener>();
 
   //private XANodePoolImpl nodePool = null;
 
@@ -1148,11 +1147,7 @@
    * @throws Exception EXCEPTION TO DO
    */
   private void notifyReleaseNodeListeners(long node) throws Exception {
-    Iterator it = releaseNodeListeners.iterator();
-    while (it.hasNext()) {
-      ReleaseNodeListener l = (ReleaseNodeListener) it.next();
-      l.releaseNode(node);
-    }
+    for (ReleaseNodeListener l: releaseNodeListeners) l.releaseNode(node);
   }
 
 
@@ -1463,6 +1458,14 @@
     public int getPhaseNumber() {
       return phaseNumber;
     }
+
+
+    /**
+     * Ignored for this implementation.
+     */
+    public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
+      // do nothing
+    }
   }
 
 
@@ -1967,4 +1970,12 @@
 
   }
 
+
+  /**
+   * Ignored for this implementation.
+   */
+  public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
+    // do nothing
+  }
+
 }

Modified: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImplUnitTest.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImplUnitTest.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImplUnitTest.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -39,6 +39,7 @@
 // locally written packages
 import org.mulgara.store.nodepool.*;
 import org.mulgara.store.statement.*;
+import org.mulgara.store.tuples.TestTuples;
 import org.mulgara.util.*;
 
 
@@ -195,4 +196,21 @@
     }
     super.tearDown();
   }
+
+  
+  /**
+   * Return a dump of all tuples, sorted by the primary index: 0123.
+   * @see org.mulgara.store.statement.StatementStoreAbstractUnitTest#getDump()
+   */
+  protected TestTuples getDump() {
+    TestTuples expected = new TestTuples();
+    add(expected, StatementStore.VARIABLES, new long[] {1, 2, 3, 1});
+    add(expected, StatementStore.VARIABLES, new long[] {1, 2, 4, 2});
+    add(expected, StatementStore.VARIABLES, new long[] {1, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
+    add(expected, StatementStore.VARIABLES, new long[] {2, 5, 6, 2});
+    add(expected, StatementStore.VARIABLES, new long[] {2, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
+    add(expected, StatementStore.VARIABLES, new long[] {SYSTEM_GRAPH, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
+    return expected;
+  }
+
 }

Copied: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11 (from rev 1456, branches/xa11/src/jar/resolver-store/java/org/mulgara/store/statement/xa11)

Deleted: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java
===================================================================
--- branches/xa11/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,61 +0,0 @@
-/*
- * The contents of this file are subject to the Open Software License
- * Version 3.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.opensource.org/licenses/osl-3.0.txt
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- */
-
-package org.mulgara.store.statement.xa11;
-
-import org.mulgara.query.TuplesException;
-import org.mulgara.store.statement.StatementStore;
-import org.mulgara.store.tuples.LiteralTuples;
-import org.mulgara.store.tuples.StoreTuples;
-
-/**
- * A Tuples for representing a specified Graph.
- *
- * @created Jan 14, 2009
- * @author Paul Gearon
- * @copyright &copy; 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
- * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
- */
-public class LiteralGraphTuples extends LiteralTuples implements StoreTuples {
-
-  static final String[] META_NAMES = new String[] { StatementStore.VARIABLES[StatementStore.VARIABLES.length - 1].getName() };
-
-  /**
-   * Creates a new literal tuples containing graphs.
-   * @param sorted
-   */
-  public LiteralGraphTuples(boolean sorted) {
-    super(META_NAMES, sorted);
-  }
-
-  /**
-   * Creates a new literal tuples containing graphs.
-   * @param sorted
-   */
-  public LiteralGraphTuples(long graph) {
-    super(META_NAMES, true);
-    try {
-      appendTuple(new long[] { graph });
-    } catch (TuplesException te) {
-      // should not happen
-      throw new AssertionError("Unable to add an element to an array");
-    }
-  }
-
-  /**
-   * @see org.mulgara.store.tuples.StoreTuples#getColumnOrder()
-   */
-  public int[] getColumnOrder() {
-    return new int[] { 0 };
-  }
-
-}

Copied: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java (from rev 1456, branches/xa11/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java)
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java	                        (rev 0)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -0,0 +1,61 @@
+/*
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+
+package org.mulgara.store.statement.xa11;
+
+import org.mulgara.query.TuplesException;
+import org.mulgara.store.statement.StatementStore;
+import org.mulgara.store.tuples.LiteralTuples;
+import org.mulgara.store.tuples.StoreTuples;
+
+/**
+ * A Tuples for representing a specified Graph.
+ *
+ * @created Jan 14, 2009
+ * @author Paul Gearon
+ * @copyright &copy; 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class LiteralGraphTuples extends LiteralTuples implements StoreTuples {
+
+  static final String[] META_NAMES = new String[] { StatementStore.VARIABLES[StatementStore.VARIABLES.length - 1].getName() };
+
+  /**
+   * Creates a new literal tuples containing graphs.
+   * @param sorted
+   */
+  public LiteralGraphTuples(boolean sorted) {
+    super(META_NAMES, sorted);
+  }
+
+  /**
+   * Creates a new literal tuples containing graphs.
+   * @param sorted
+   */
+  public LiteralGraphTuples(long graph) {
+    super(META_NAMES, true);
+    try {
+      appendTuple(new long[] { graph });
+    } catch (TuplesException te) {
+      // should not happen
+      throw new AssertionError("Unable to add an element to an array");
+    }
+  }
+
+  /**
+   * @see org.mulgara.store.tuples.StoreTuples#getColumnOrder()
+   */
+  public int[] getColumnOrder() {
+    return new int[] { 0 };
+  }
+
+}

Deleted: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java
===================================================================
--- branches/xa11/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,1796 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is the Kowari Metadata Store.
- *
- * The Initial Developer of the Original Code is Plugged In Software Pty
- * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
- * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
- * Plugged In Software Pty Ltd. All Rights Reserved.
- *
- * Contributor(s): N/A.
- *
- * [NOTE: The text of this Exhibit A may differ slightly from the text
- * of the notices in the Source Code files of the Original Code. You
- * should use the text of this Exhibit A rather than the text found in the
- * Original Code Source Code for Your Modifications.]
- *
- */
-package org.mulgara.store.statement.xa11;
-
-import java.io.*;
-import java.nio.*;
-
-// Java 2 standard packages
-import java.util.*;
-
-// Third party packages
-import org.apache.log4j.Logger;
-
-// Locally written packages
-import org.mulgara.query.*;
-import org.mulgara.store.nodepool.*;
-import org.mulgara.store.statement.*;
-import org.mulgara.store.statement.xa.TripleAVLFile;
-import org.mulgara.store.tuples.StoreTuples;
-import org.mulgara.store.tuples.TuplesOperations;
-import org.mulgara.store.xa.AbstractBlockFile;
-import org.mulgara.store.xa.Block;
-import org.mulgara.store.xa.BlockFile;
-import org.mulgara.store.xa.LockFile;
-import org.mulgara.store.xa.PersistableMetaRoot;
-import org.mulgara.store.xa.SimpleXAResourceException;
-import org.mulgara.store.xa.XAStatementStore;
-import org.mulgara.store.xa.XAUtils;
-import org.mulgara.util.Constants;
-
-/**
- * An implementation of {@link StatementStore}.
- *
- * @created 2008-09-30
- * @author Paul Gearon
- * @company <A href="mailto:info at PIsoftware.com">Plugged In Software</A>
- * @copyright &copy;2001-2004 <a href="http://www.pisoftware.com/">Plugged In Software Pty Ltd</a>
- * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
- */
-public final class XA11StatementStoreImpl implements XAStatementStore {
-
-  /** Logger. */
-  private final static Logger logger = Logger.getLogger(XA11StatementStoreImpl.class);
-
-  /** The value of the invalid gNode */
-  final static long NONE = NodePool.NONE;
-
-  /** The subject/predicate/object index */
-  final static int TI_3012 = 0;
-
-  /** The predicate/object/subject index */
-  final static int TI_3120 = 1;
-
-  /** The object/subject/predicate index */
-  final static int TI_3201 = 2;
-
-  /** The number of indexes */
-  final static int NR_INDEXES = 3;
-
-  /** The ordering of indexes, as indexed by the TI_ values */
-  private final static int[][] orders = {
-      {3, 0, 1, 2},  // TI_3012
-      {3, 1, 2, 0},  // TI_3120
-      {3, 2, 0, 1}   // TI_3201
-  };
-
-  private final static int[] selectIndex = {
-    /* 3XXX */ TI_3012,
-    /* 3XX0 */ TI_3012,
-    /* 3X1X */ TI_3120,
-    /* 3X10 */ TI_3012,
-    /* 32XX */ TI_3201,
-    /* 32X0 */ TI_3201,
-    /* 321X */ TI_3120,
-    /* 3210 */ TI_3012
-  };
-
-  /** A number to identify the correct file type */
-  private final static int FILE_MAGIC = 0xa5e7f21e;
-
-  /** The version of file format */
-  private final static int FILE_VERSION = 9;
-
-  /** Index of the file magic number within each of the two on-disk metaroots. */
-  private final static int IDX_MAGIC = 0;
-
-  /** Index of the file version number within each of the two on-disk metaroots. */
-  private final static int IDX_VERSION = 1;
-
-  /** Index of the valid flag (in ints) within each of the two on-disk metaroots. */
-  private final static int IDX_VALID = 2;
-
-  /** The index of the phase number in the on-disk phase. */
-  private final static int IDX_PHASE_NUMBER = 3;
-
-  /** The size of the header of a metaroot in ints. */
-  private final static int HEADER_SIZE_INTS = 4;
-
-  /** The size of the header of a metaroot in longs. */
-  private final static int HEADER_SIZE_LONGS = (HEADER_SIZE_INTS + 1) / 2;
-
-  /** The size of a metaroot in longs. */
-  private final static int METAROOT_SIZE = HEADER_SIZE_LONGS + Phase.RECORD_SIZE;
-
-  /** The number of metaroots in the metaroot file. */
-  private final static int NR_METAROOTS = 2;
-
-  /** The mask for a bound Subject */
-  private final static int MASK0 = 1;
-
-  /** The mask for a bound Predicate */
-  private final static int MASK1 = 2;
-
-  /** The mask for a bound Object */
-  private final static int MASK2 = 4;
-
-  /** The mask for a bound Graph. This must always be set. */
-  private final static int MASK3 = 8;
-
-  /** The node number for the system graph. Globalized to <#>. */
-  private long systemGraphNode = NONE;
-
-  /** The node number for <rdf:type>. */
-  private long rdfTypeNode = NONE;
-
-  /** The node number for the graph class <mulgara:ModelType>. */
-  private long graphTypeNode = NONE;
-
-  /** The name of the triple store which forms the base name for the graph files. */
-  private String fileName;
-
-  /** The LockFile that protects the graph from being opened twice. */
-  private LockFile lockFile;
-
-  /** The BlockFile for the node pool metaroot file. */
-  private BlockFile metarootFile = null;
-
-  /** The metaroot blocks of the metaroot file. */
-  private Block[] metarootBlocks = new Block[NR_METAROOTS];
-
-  /** An error flag that is set during file initialization if the file version is incorrect */
-  private boolean wrongFileVersion = false;
-
-  /** The files containing indexed triples */
-  private TripleAVLFile[] tripleAVLFiles = new TripleAVLFile[NR_INDEXES];
-
-  /** The current read/write phase. Only the latest phase can write. */
-  private Phase currentPhase = null;
-
-  /**
-   * Determines if modifications can be performed without creating a new
-   * (in-memory) phase. If dirty is false and the current phase is in use (by
-   * unclosed Tupleses) then a new phase must be created to protect the existing
-   * Tupleses before any further modifications are made.
-   */
-  private boolean dirty = true;
-
-  /**
-   * The index of the phase in the metaroot. May be 0 or 1 as the commited phase swaps
-   * between the two metaroots.
-   */
-  private int phaseIndex = 0;
-
-  /** The number of the current phase */
-  private int phaseNumber = 0;
-
-  /** A reference token for keeping the commited phase available until we no longer need it */
-  private Phase.Token committedPhaseToken = null;
-
-  /** A synchronization object for locking access to the committed phase */
-  private Object committedPhaseLock = new Object();
-
-  /** A reference token for keeping the recording phase available until we no longer need it */
-  private Phase.Token recordingPhaseToken = null;
-
-  /** The list of graphs known to this statement store. */
-  private List<Long> committedGraphNodes;
-
-  /**
-   * This flag indicates that the current object has been fully written, and may be considered
-   * as committed when the rest of the system is ready.
-   */
-  private boolean prepared = false;
-
-  /** A set of objects to be informed when nodes are released. */
-  private List<ReleaseNodeListener> releaseNodeListeners = new ArrayList<ReleaseNodeListener>();
-
-
-  /**
-   * Creates a statement store using a base filename.
-   *
-   * @param fileName The base filename to operate from.
-   * @throws IOException The mass storage could not be accessed.
-   */
-  public XA11StatementStoreImpl(String fileName) throws IOException {
-    this.fileName = fileName;
-
-    lockFile = LockFile.createLockFile(fileName + ".g.lock");
-
-    try {
-      // Check that the metaroot file was created with a compatible version of the triplestore.
-      RandomAccessFile metarootRAF = null;
-      try {
-        metarootRAF = new RandomAccessFile(fileName + ".g", "r");
-        if (metarootRAF.length() >= 2 * Constants.SIZEOF_INT) {
-          int fileMagic = metarootRAF.readInt();
-          int fileVersion = metarootRAF.readInt();
-          if (AbstractBlockFile.byteOrder != ByteOrder.BIG_ENDIAN) {
-            fileMagic = XAUtils.bswap(fileMagic);
-            fileVersion = XAUtils.bswap(fileVersion);
-          }
-          wrongFileVersion = fileMagic != FILE_MAGIC || fileVersion != FILE_VERSION;
-        } else {
-          wrongFileVersion = false;
-        }
-      } catch (FileNotFoundException ex) {
-        wrongFileVersion = false;
-      } finally {
-        if (metarootRAF != null) metarootRAF.close();
-      }
-
-      for (int i = 0; i < NR_INDEXES; ++i) {
-        String suffix = ".g_" + orders[i][0] + orders[i][1] + orders[i][2] + orders[i][3];
-        tripleAVLFiles[i] = new TripleAVLFile(fileName + suffix, orders[i]);
-      }
-    } catch (IOException ex) {
-      try {
-        close();
-      } catch (StatementStoreException ex2) { /* no-op */ }
-      throw ex;
-    }
-  }
-
-
-  /**
-   * Returns <code>true</code> if there are no triples in the graph
-   * @return <code>true</code> if there are no triples in the graph
-   */
-  public synchronized boolean isEmpty() {
-    checkInitialized();
-    return currentPhase.isEmpty();
-  }
-
-
-  /**
-   * Returns a count of the number of triples in the graph
-   * @return a count of the number of triples in the graph
-   */
-  public synchronized long getNrTriples() {
-    checkInitialized();
-    return currentPhase.getNrTriples();
-  }
-
-
-  /**
-   * Gets the PhaseNumber attribute of the XAGraphImpl object
-   * @return The PhaseNumber value
-   */
-  public synchronized int getPhaseNumber() {
-    checkInitialized();
-    return phaseNumber;
-  }
-
-
-  /**
-   * Adds a feature to the ReleaseNodeListener attribute of the XAGraphImpl object
-   * @param l The feature to be added to the ReleaseNodeListener attribute
-   */
-  public synchronized void addReleaseNodeListener(ReleaseNodeListener l) {
-    if (!releaseNodeListeners.contains(l)) releaseNodeListeners.add(l);
-  }
-
-
-  /**
-   * Removes a release node listener.
-   * @param l The listener to remove.
-   */
-  public synchronized void removeReleaseNodeListener(ReleaseNodeListener l) {
-    releaseNodeListeners.remove(l);
-  }
-
-
-  /**
-   * Adds a new triple to the graph if it doesn't already exist.
-   * @param node0 the first element of the new triple
-   * @param node1 the second element of the new triple
-   * @param node2 the third element of the new triple
-   * @param node3 the fourth element of the new triple
-   * @throws StatementStoreException Due to structural or IO errors.
-   */
-  public synchronized void addTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
-    checkInitialized();
-    if (
-        node0 < NodePool.MIN_NODE ||
-        node1 < NodePool.MIN_NODE ||
-        node2 < NodePool.MIN_NODE ||
-        node3 < NodePool.MIN_NODE
-    ) {
-      throw new StatementStoreException(
-          "Attempt to add a triple with node number out of range: " + node0 + " " + node1 + " " + node2 + " " + node3
-      );
-    }
-
-    if (!dirty && currentPhase.isInUse()) {
-      try {
-        new Phase();
-      } catch (IOException ex) {
-        throw new StatementStoreException("I/O error", ex);
-      }
-    }
-
-    currentPhase.addTriple(node0, node1, node2, node3);
-  }
-
-
-  /**
-   * Removes all triples matching the given specification.
-   * @param node0 the value for the first element of the triples
-   * @param node1 the value for the second element of the triples
-   * @param node2 the value for the third element of the triples
-   * @param node3 the value for the fourth element of the triples
-   * @throws StatementStoreException if something exceptional happens
-   */
-  public synchronized void removeTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
-    checkInitialized();
-    if (node0 != NONE && node1 != NONE && node2 != NONE && node3 != NONE) {
-      if (!dirty && currentPhase.isInUse()) {
-        try {
-          new Phase();
-        } catch (IOException ex) {
-          throw new StatementStoreException("I/O error", ex);
-        }
-      }
-
-      // Remove the triple.
-      currentPhase.removeTriple(node0, node1, node2, node3);
-    } else {
-      // Find all the tuples matching the specification and remove them.
-      StoreTuples tuples = currentPhase.findTuples(node0, node1, node2, node3);
-      try {
-        try {
-          if (!tuples.isEmpty()) {
-            // There is at least one triple to remove so protect the
-            // Tuples as we make changes to the triplestore.
-            try {
-              new Phase();
-            } catch (IOException ex) {
-              throw new StatementStoreException("I/O error", ex);
-            }
-
-            long[] triple = new long[] { node0, node1, node2, node3 };
-            int[] columnMap = tuples.getColumnOrder();
-            int nrColumns = columnMap.length;
-            tuples.beforeFirst();
-            while (tuples.next()) {
-              // Copy the row data over to the triple.
-              for (int col = 0; col < nrColumns; ++col) {
-                triple[columnMap[col]] = tuples.getColumnValue(col);
-              }
-
-              currentPhase.removeTriple(triple[0], triple[1], triple[2], triple[3]);
-            }
-          }
-        } finally {
-          tuples.close();
-        }
-      } catch (TuplesException ex) {
-        throw new StatementStoreException("Exception while iterating over temporary Tuples.", ex);
-      }
-    }
-  }
-
-
-  /**
-   * Finds triples matching the given specification.
-   * @param node0 The 0 node of the triple to find.
-   * @param node1 The 1 node of the triple to find.
-   * @param node2 The 2 node of the triple to find.
-   * @param node3 The 3 node of the triple to find.
-   * @return A set of all the triples which match the search.
-   * @throws StatementStoreException Due to a structural or IO error.
-   */
-  public synchronized StoreTuples findTuples(long node0, long node1, long node2, long node3) throws StatementStoreException {
-    checkInitialized();
-    dirty = false;
-    return currentPhase.findTuples(node0, node1, node2, node3);
-  }
-
-  
-  /**
-   * Finds triples matching the given specification and index mask.
-   * @param mask The mask of the index to use. This is only allowable for 3 variables
-   *             and a given graph.
-   * @param node0 The 0 node of the triple to find.
-   * @param node1 The 1 node of the triple to find.
-   * @param node2 The 2 node of the triple to find.
-   * @param node3 The 3 node of the triple to find.
-   * @return A set of all the triples which match the search.
-   * @throws StatementStoreException Due to a structural or IO error.
-   */
-  public synchronized StoreTuples findTuples(
-      int mask, long node0, long node1, long node2, long node3
-  ) throws StatementStoreException {
-    checkInitialized();
-    dirty = false;
-    if (!checkMask(mask, node0, node1, node2, node3)) throw new StatementStoreException("Bad explicit index selection for given node pattern.");
-    return currentPhase.findTuples(mask, node0, node1, node2, node3);
-  }
-
-
-  /**
-   * Tests a mask for consistency against the nodes it will be used to find.
-   * @param mask The mask to test.
-   * @param node0 The 0 node of the triple to find.
-   * @param node1 The 1 node of the triple to find.
-   * @param node2 The 2 node of the triple to find.
-   * @param node3 The 3 node of the triple to find. Must not be NONE.
-   * @return <code>true</code> if the mask is consistent with the given nodes.
-   */
-  private static boolean checkMask(int mask, long node0, long node1, long node2, long node3) {
-    // The graph must be bound
-    if (node3 != NONE) return false;
-    if (node0 != NONE && 0 == (mask & MASK0)) return false;
-    if (node1 != NONE && 0 == (mask & MASK1)) return false;
-    if (node2 != NONE && 0 == (mask & MASK2)) return false;
-    return true;
-  }
-
-
-  /**
-   * Returns a StoreTuples which contains all triples in the store.  The
-   * parameters provide a hint about how the StoreTuples will be used.  This
-   * information is used to select the index from which the StoreTuples will be
-   * obtained.
-   * @param node0Bound specifies that node0 will be bound
-   * @param node1Bound specifies that node1 will be bound
-   * @param node2Bound specifies that node2 will be bound
-   * @return the {@link StoreTuples}
-   * @throws StatementStoreException if something exceptional happens
-   */
-  public synchronized StoreTuples findTuples(boolean node0Bound, boolean node1Bound, boolean node2Bound, boolean node3Bound) throws StatementStoreException {
-    checkInitialized();
-    dirty = false;
-    return currentPhase.findTuples(node0Bound, node1Bound, node2Bound, node3Bound);
-  }
-
-
-  /**
-   * Returns <code>true</code> if any triples match the given specification.
-   * Allows wild cards StatementStore.NONE for any of the node numbers except node3.
-   * @param node0 The 0 node of the triple to find.
-   * @param node1 The 1 node of the triple to find.
-   * @param node2 The 2 node of the triple to find.
-   * @param node3 The 3 node of the triple to find.
-   * @return <code>true</code> if any matching triples exist in the graph.
-   * @throws StatementStoreException Due to a structural or IO error.
-   */
-  public synchronized boolean existsTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
-    checkInitialized();
-    return currentPhase.existsTriples(node0, node1, node2, node3);
-  }
-
-
-  public XAStatementStore newReadOnlyStatementStore() {
-    return new ReadOnlyGraph();
-  }
-
-
-  public XAStatementStore newWritableStatementStore() {
-    return this;
-  }
-
-
-  /**
-   * Close all files, removing empty space from the ends as required.
-   * @throws StatementStoreException if an error occurs while truncating,
-   * flushing or closing one of the three files.
-   */
-  public synchronized void close() throws StatementStoreException {
-    try {
-      unmap();
-    } finally {
-      try {
-        IOException savedEx = null;
-
-        for (int i = 0; i < NR_INDEXES; ++i) {
-          try {
-            if (tripleAVLFiles[i] != null) tripleAVLFiles[i].close();
-          } catch (IOException ex) {
-            savedEx = ex;
-          }
-        }
-
-        if (metarootFile != null) {
-          try {
-            metarootFile.close();
-          } catch (IOException ex) {
-            savedEx = ex;
-          }
-        }
-
-        if (savedEx != null) throw new StatementStoreException("I/O error closing graph.", savedEx);
-      } finally {
-        if (lockFile != null) {
-          lockFile.release();
-          lockFile = null;
-        }
-      }
-    }
-  }
-
-
-  /**
-   * Close this graph, if it is currently open, and remove all files associated with it.
-   * @throws StatementStoreException Due to an IO error.
-   */
-  public synchronized void delete() throws StatementStoreException {
-    currentPhase = null;
-    try {
-      unmap();
-    } finally {
-      try {
-        IOException savedEx = null;
-
-        for (int i = 0; i < NR_INDEXES; ++i) {
-          try {
-            if (tripleAVLFiles[i] != null) tripleAVLFiles[i].delete();
-          } catch (IOException ex) {
-            savedEx = ex;
-          }
-        }
-
-        if (metarootFile != null) {
-          try {
-            metarootFile.delete();
-          } catch (IOException ex) {
-            savedEx = ex;
-          }
-        }
-
-        if (savedEx != null) throw new StatementStoreException("I/O error deleting graph.", savedEx);
-      } finally {
-        for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFiles[i] = null;
-        metarootFile = null;
-        if (lockFile != null) {
-          lockFile.release();
-          lockFile = null;
-        }
-      }
-    }
-  }
-
-
-  /**
-   * Try to safely close the store if this was not done explicitly.
-   */
-  protected void finalize() {
-    try {
-      close();
-    } catch (Throwable t) {
-      logger.warn("Exception in finalize while trying to close the statement store.", t);
-    }
-  }
-
-
-  /**
-   * A manually tracked reference to this object was released. Does nothing.
-   */
-  public void release() {
-    if (logger.isDebugEnabled()) logger.debug("Release " + this.getClass() + ":" + System.identityHashCode(this));
-  }
-
-
-  /**
-   * This in called in response to the resource being manually refreshed.
-   * This implementation does nothing here.
-   */
-  public void refresh() {
-    if (logger.isDebugEnabled()) {
-      logger.debug("Refresh " + this.getClass() + ":" + System.identityHashCode(this));
-    }
-  }
-
-
-  //
-  // Methods from SimpleXAResource.
-  //
-
-  /**
-   * Clears this store to a fresh state.
-   * @param phaseNumber The phase number to set to.
-   * @throws IOException Error with file access
-   * @throws SimpleXAResourceException Error with the data structures.
-   */
-  public synchronized void clear(int phaseNumber) throws IOException, SimpleXAResourceException {
-    if (logger.isDebugEnabled()) {
-      logger.debug("Clear(" + phaseNumber + ") " + this.getClass() + ":" + System.identityHashCode(this));
-    }
-    if (currentPhase != null) throw new IllegalStateException("Graph already has a current phase.");
-
-    openMetarootFile(true);
-
-    synchronized (committedPhaseLock) {
-      committedPhaseToken = new Phase().use();
-    }
-    this.phaseNumber = phaseNumber;
-    phaseIndex = 1;
-    for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFiles[i].clear();
-
-    new Phase();
-  }
-
-
-  /**
-   * Clear the state of the database.
-   * @throws IOException Filesystem error
-   * @throws SimpleXAResourceException Error in the data structures.
-   */
-  public synchronized void clear() throws IOException, SimpleXAResourceException {
-    if (logger.isDebugEnabled()) logger.debug("Clear " + this.getClass() + ":" + System.identityHashCode(this));
-    if (currentPhase == null) clear(0);
-
-    // could throw an exception if clear() is called after any other
-    // operations are performed.  Calling clear() multiple times should be
-    // permitted.
-  }
-
-
-  /**
-   * Perform all the operations for a commit and return when all the data structures are in place.
-   * @throws SimpleXAResourceException Due to a bad transaction state, or an IO error while preparing.
-   */
-  public synchronized void prepare() throws SimpleXAResourceException {
-    if (logger.isDebugEnabled()) logger.debug("Prepare " + this.getClass() + ":" + System.identityHashCode(this));
-    checkInitialized();
-
-    // check that prepare() was not caleld twice
-    if (prepared) throw new SimpleXAResourceException("prepare() called twice.");
-
-    try {
-      // Perform a prepare.
-      recordingPhaseToken = currentPhase.use();
-      Phase recordingPhase = currentPhase;
-      new Phase();
-
-      // Ensure that all data associated with the phase is on disk.
-      for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFiles[i].force();
-
-      // Write the metaroot.
-      int newPhaseIndex = 1 - phaseIndex;
-      int newPhaseNumber = phaseNumber + 1;
-
-      Block block = metarootBlocks[newPhaseIndex];
-      block.putInt(IDX_VALID, 0); // should already be invalid.
-      block.putInt(IDX_PHASE_NUMBER, newPhaseNumber);
-      logger.debug("Writing graph metaroot for phase: " + newPhaseNumber);
-      recordingPhase.writeToBlock(block, HEADER_SIZE_LONGS);
-      block.write();
-      metarootFile.force();
-      block.putInt(IDX_VALID, 1);
-      block.write();
-      metarootFile.force();
-
-      phaseIndex = newPhaseIndex;
-      phaseNumber = newPhaseNumber;
-      prepared = true;
-    } catch (IOException ex) {
-      logger.error("I/O error while performing prepare.", ex);
-      throw new SimpleXAResourceException("I/O error while performing prepare.", ex);
-    } finally {
-      if (!prepared) {
-        // Something went wrong. An exception is on its way out
-        logger.error("Prepare failed.");
-        if (recordingPhaseToken != null) {
-          recordingPhaseToken.release();
-          recordingPhaseToken = null;
-        }
-      }
-    }
-  }
-
-
-  /**
-   * Update the metadata to point to the prepared data structures.
-   * @throws SimpleXAResourceException Due to a bad transaction state, or an IO error.
-   */
-  public synchronized void commit() throws SimpleXAResourceException {
-    if (logger.isDebugEnabled()) logger.debug("Commit " + this.getClass() + ":" + System.identityHashCode(this));
-
-    // check that prepare has been called
-    if (!prepared) throw new SimpleXAResourceException("commit() called without previous prepare().");
-
-    // Perform a commit.
-    try {
-      // Invalidate the metaroot of the old phase.
-      Block block = metarootBlocks[1 - phaseIndex];
-      block.putInt(IDX_VALID, 0);
-      block.write();
-      metarootFile.force();
-
-      // Release the token for the previously committed phase.
-      synchronized (committedPhaseLock) {
-        if (committedPhaseToken != null) committedPhaseToken.release();
-        committedPhaseToken = recordingPhaseToken;
-        committedGraphNodes = currentPhase.graphNodes;
-      }
-      recordingPhaseToken = null;
-    } catch (IOException ex) {
-      logger.fatal("I/O error while performing commit.", ex);
-      throw new SimpleXAResourceException("I/O error while performing commit.", ex);
-    } finally {
-      prepared = false;
-      if (recordingPhaseToken != null) {
-        // Something went wrong! An exception is on its way out
-        recordingPhaseToken.release();
-        recordingPhaseToken = null;
-
-        logger.error("Commit failed.  Calling close().");
-        try {
-          close();
-        } catch (Throwable t) {
-          logger.error("Exception on forced close()", t);
-        }
-      }
-    }
-  }
-
-
-  /**
-   * Read the state from the metaroot file and use it to set up this object
-   * @return An array of 0, 1, or 2 valid phases that can be selected as the last committed phase.
-   * @throws SimpleXAResourceException Due to an IO error, or a data error in the metaroot file.
-   */
-  public synchronized int[] recover() throws SimpleXAResourceException {
-    if (logger.isDebugEnabled()) logger.debug("Recover " + this.getClass() + ":" + System.identityHashCode(this));
-    if (currentPhase != null) return new int[0];
-    if (wrongFileVersion) throw new SimpleXAResourceException("Wrong metaroot file version.");
-
-    try {
-      openMetarootFile(false);
-    } catch (IOException ex) {
-      throw new SimpleXAResourceException("I/O error", ex);
-    }
-
-    // Count the number of valid phases.
-    int phaseCount = 0;
-    if (metarootBlocks[0].getInt(IDX_VALID) != 0) ++phaseCount;
-    if (metarootBlocks[1].getInt(IDX_VALID) != 0) ++phaseCount;
-
-    // Read the phase numbers.
-    int[] phaseNumbers = new int[phaseCount];
-    int index = 0;
-    if (metarootBlocks[0].getInt(IDX_VALID) != 0) phaseNumbers[index++] = metarootBlocks[0].getInt(IDX_PHASE_NUMBER);
-    if (metarootBlocks[1].getInt(IDX_VALID) != 0) phaseNumbers[index++] = metarootBlocks[1].getInt(IDX_PHASE_NUMBER);
-    return phaseNumbers;
-  }
-
-
-  /**
-   * Choose a phase from the metaroot file to use
-   * @param phaseNumber The number of the phase to select. This must be one of the valid
-   *        phases present in the metaroot file.
-   * @throws IOException Due to an error on the filesystem
-   * @throws SimpleXAResourceException If the file structures are incorrect.
-   */
-  public synchronized void selectPhase(int phaseNumber) throws IOException, SimpleXAResourceException {
-    if (logger.isDebugEnabled()) {
-      logger.debug("SelectPhase(" + phaseNumber + ") " + this.getClass() + ":" + System.identityHashCode(this));
-    }
-    if (currentPhase != null) throw new SimpleXAResourceException("selectPhase() called on initialized Graph.");
-    if (metarootFile == null) throw new SimpleXAResourceException("Graph metaroot file is not open.");
-
-    // Locate the metaroot corresponding to the given phase number.
-    if (
-        metarootBlocks[0].getInt(IDX_VALID) != 0 &&
-        metarootBlocks[0].getInt(IDX_PHASE_NUMBER) == phaseNumber
-    ) {
-      phaseIndex = 0;
-      // A new phase will be saved in the other metaroot.
-    } else if (
-        metarootBlocks[1].getInt(IDX_VALID) != 0 &&
-        metarootBlocks[1].getInt(IDX_PHASE_NUMBER) == phaseNumber
-    ) {
-      phaseIndex = 1;
-      // A new phase will be saved in the other metaroot.
-    } else {
-      throw new SimpleXAResourceException("Invalid phase number: " + phaseNumber);
-    }
-
-    // Load a duplicate of the selected phase.  The duplicate will have a
-    // phase number which is one higher than the original phase.
-    try {
-      synchronized (committedPhaseLock) {
-        committedPhaseToken = new Phase(metarootBlocks[phaseIndex], HEADER_SIZE_LONGS).use();
-      }
-      this.phaseNumber = phaseNumber;
-    } catch (IllegalStateException ex) {
-      throw new SimpleXAResourceException("Cannot construct initial phase.", ex);
-    }
-    new Phase();
-
-    // Invalidate the on-disk metaroot that the new phase will be saved to.
-    Block block = metarootBlocks[1 - phaseIndex];
-    block.putInt(IDX_VALID, 0);
-    block.write();
-    metarootFile.force();
-  }
-
-
-  /**
-   * Return to the data structure state from the beginning of the transaction.
-   * @throws SimpleXAResourceException Due to an IO error.
-   */
-  public synchronized void rollback() throws SimpleXAResourceException {
-    if (logger.isDebugEnabled()) logger.debug("Rollback " + this.getClass() + ":" + System.identityHashCode(this));
-    checkInitialized();
-    try {
-      if (prepared) {
-        // Restore phaseIndex and phaseNumber to their previous values.
-        phaseIndex = 1 - phaseIndex;
-        --phaseNumber;
-        recordingPhaseToken = null;
-        prepared = false;
-
-        // Invalidate the metaroot of the other phase.
-        Block block = metarootBlocks[1 - phaseIndex];
-        block.putInt(IDX_VALID, 0);
-        block.write();
-        metarootFile.force();
-      }
-    } catch (IOException ex) {
-      throw new SimpleXAResourceException("I/O error while performing rollback (invalidating metaroot)", ex);
-    } finally {
-      try {
-        new Phase(committedPhaseToken.getPhase());
-      } catch (IOException ex) {
-        throw new SimpleXAResourceException("I/O error while performing rollback (new committed phase)", ex);
-      }
-    }
-  }
-
-
-  /**
-   * Get a string representation of the current state of the graph.
-   * @return A string representing the current state
-   */
-  public synchronized String toString() {
-    if (currentPhase == null) return "Uninitialized Graph.";
-    return currentPhase.toString();
-  }
-
-
-  /**
-   * Attempt to cleanly close all mapped files.
-   */
-  public synchronized void unmap() {
-    if (committedPhaseToken != null) {
-      recordingPhaseToken = null;
-      prepared = false;
-
-      try {
-        new Phase(committedPhaseToken.getPhase());
-      } catch (Throwable t) {
-        logger.warn("Exception while rolling back in unmap()", t);
-      }
-      currentPhase = null;
-
-      synchronized (committedPhaseLock) {
-        committedPhaseToken.release();
-        committedPhaseToken = null;
-      }
-    }
-
-    if (tripleAVLFiles != null) {
-      for (int i = 0; i < NR_INDEXES; ++i) {
-        if (tripleAVLFiles[i] != null) tripleAVLFiles[i].unmap();
-      }
-    }
-
-    if (metarootFile != null) {
-      if (metarootBlocks[0] != null) metarootBlocks[0] = null;
-      if (metarootBlocks[1] != null) metarootBlocks[1] = null;
-      metarootFile.unmap();
-    }
-  }
-
-
-  /**
-   * Check that the data structures are valid
-   * @return The number of triples in the database
-   */
-  synchronized long checkIntegrity() {
-    checkInitialized();
-    return currentPhase.checkIntegrity();
-  }
-
-
-  /**
-   * Open the metaroot file and read in the contents
-   * @param clear If <code>true</code> then the file will be reset to empty.
-   * @throws IOException Due to a filesystem error.
-   * @throws SimpleXAResourceException If the data structures are inconsistent.
-   */
-  private void openMetarootFile(boolean clear) throws IOException, SimpleXAResourceException {
-    if (metarootFile == null) {
-      metarootFile = AbstractBlockFile.openBlockFile(fileName + ".g", METAROOT_SIZE * Constants.SIZEOF_LONG, BlockFile.IOType.EXPLICIT);
-
-      long nrBlocks = metarootFile.getNrBlocks();
-      if (nrBlocks != NR_METAROOTS) {
-        if (nrBlocks > 0) {
-          logger.info("Graph metaroot file for triple store \"" + fileName + "\" has invalid number of blocks: " + nrBlocks);
-          if (nrBlocks < NR_METAROOTS) {
-            clear = true;
-            metarootFile.clear();
-          }
-        } else {
-          // Perform initialization on empty file.
-          clear = true;
-        }
-        metarootFile.setNrBlocks(NR_METAROOTS);
-      }
-
-      metarootBlocks[0] = metarootFile.readBlock(0);
-      metarootBlocks[1] = metarootFile.readBlock(1);
-    }
-
-    if (clear) {
-      // Invalidate the metaroots on disk.
-      metarootBlocks[0].putInt(IDX_MAGIC, FILE_MAGIC);
-      metarootBlocks[0].putInt(IDX_VERSION, FILE_VERSION);
-      metarootBlocks[0].putInt(IDX_VALID, 0);
-      metarootBlocks[0].write();
-      metarootBlocks[1].putInt(IDX_MAGIC, 0);
-      metarootBlocks[1].putInt(IDX_VERSION, 0);
-      metarootBlocks[1].putInt(IDX_VALID, 0);
-      metarootBlocks[1].write();
-      metarootFile.force();
-    }
-  }
-
-
-  /**
-   * Tests that the current object has been initialized.
-   * @throws IllegalStateException Throws this unchecked exception if the object is not initialized.
-   */
-  private void checkInitialized() {
-    if (currentPhase == null) throw new IllegalStateException("No current phase.  Graph has not been initialized or has been closed.");
-  }
-
-
-  final class ReadOnlyGraph implements XAStatementStore {
-
-    private Phase phase = null;
-
-    private Phase.Token token = null;
-
-
-    /**
-     * Create a read-only graph attached to the current outer database
-     */
-    ReadOnlyGraph() {
-      synchronized (committedPhaseLock) {
-        if (committedPhaseToken == null) {
-          throw new IllegalStateException("Cannot create read only view of uninitialized Graph.");
-        }
-      }
-    }
-
-
-    public synchronized boolean isEmpty() {
-      return phase.isEmpty();
-    }
-
-
-    /**
-     * Returns a count of the number of triples in the graph
-     * @return a count of the number of triples in the graph
-     */
-    public synchronized long getNrTriples() {
-      return phase.getNrTriples();
-    }
-
-
-    /**
-     * Adds a triple to the graph.
-     * @param node0 The 0 node of the triple.
-     * @param node1 The 1 node of the triple.
-     * @param node2 The 2 node of the triple.
-     * @param node3 The 3 node of the triple.
-     */
-    public void addTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
-      throw new UnsupportedOperationException("Trying to modify a read-only graph.");
-    }
-
-
-    /**
-     * Removes all triples matching the given specification.
-     * @param node0 the value for the first element of the triples
-     * @param node1 the value for the second element of the triples
-     * @param node2 the value for the third element of the triples
-     * @param node3 the value for the fourth element of the triples
-     */
-    public void removeTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
-      throw new UnsupportedOperationException("Trying to modify a read-only graph.");
-    }
-
-
-    /**
-     * Finds triples matching the given specification.
-     * @param node0 The 0 node of the triple to find.
-     * @param node1 The 1 node of the triple to find.
-     * @param node2 The 2 node of the triple to find.
-     * @param node3 The 3 node of the triple to find.
-     * @return A StoreTuples which contains the triples which match the search.
-     */
-    public synchronized StoreTuples findTuples(long node0, long node1, long node2, long node3) throws StatementStoreException {
-      return phase.findTuples(node0, node1, node2, node3);
-    }
-
-    /**
-     * Finds triples matching the given specification.
-     * @param mask The mask of the index to use. This is only allowable for 3 variables
-     *             and a given graph.
-     * @param node0 The 0 node of the triple to find.
-     * @param node1 The 1 node of the triple to find.
-     * @param node2 The 2 node of the triple to find.
-     * @param node3 The 3 node of the triple to find.
-     * @return A StoreTuples which contains the triples which match the search.
-     * @throws StatementStoreException A structural or IO error
-     */
-    public synchronized StoreTuples findTuples(int mask, long node0, long node1, long node2, long node3) throws StatementStoreException {
-      if (!checkMask(mask, node0, node1, node2, node3)) throw new StatementStoreException("Bad explicit index selection for given node pattern.");
-      return phase.findTuples(mask, node0, node1, node2, node3);
-    }
-
-
-    /**
-     * Returns a StoreTuples which contains all triples in the store.  The
-     * parameters provide a hint about how the StoreTuples will be used.  This
-     * information is used to select the index from which the StoreTuples will
-     * be obtained.
-     * @param node0Bound specifies that node0 will be bound
-     * @param node1Bound specifies that node1 will be bound
-     * @param node2Bound specifies that node2 will be bound
-     * @return the {@link StoreTuples}
-     * @throws StatementStoreException if something exceptional happens
-     */
-    public synchronized StoreTuples findTuples(boolean node0Bound, boolean node1Bound, boolean node2Bound, boolean node3Bound) throws StatementStoreException {
-      return phase.findTuples(node0Bound, node1Bound, node2Bound, node3Bound);
-    }
-
-
-    public synchronized boolean existsTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
-      return phase.existsTriples(node0, node1, node2, node3);
-    }
-
-
-    public XAStatementStore newReadOnlyStatementStore() {
-      throw new UnsupportedOperationException();
-    }
-
-
-    public XAStatementStore newWritableStatementStore() {
-      throw new UnsupportedOperationException();
-    }
-
-
-    public void close() {
-      throw new UnsupportedOperationException("Trying to close a read-only graph.");
-    }
-
-
-    public void delete() {
-      throw new UnsupportedOperationException("Trying to delete a read-only graph.");
-    }
-
-
-    /**
-     * Release the phase.
-     */
-    public synchronized void release() {
-      if (logger.isDebugEnabled()) logger.debug("Releasing " + this.getClass() + ":" + System.identityHashCode(this));
-      try {
-        if (token != null) token.release();
-      } finally {
-        phase = null;
-        token = null;
-      }
-    }
-
-
-    public synchronized void refresh() {
-      if (logger.isDebugEnabled()) logger.debug("Refreshing " + this.getClass() + ":" + System.identityHashCode(this));
-
-      synchronized (committedPhaseLock) {
-        Phase committedPhase = committedPhaseToken.getPhase();
-        if (phase != committedPhase) {
-          if (token != null) token.release();
-          phase = committedPhase;
-          token = phase.use();
-        }
-      }
-    }
-
-    public void addReleaseNodeListener(ReleaseNodeListener l) {
-      throw new UnsupportedOperationException();
-    }
-
-    public void removeReleaseNodeListener(ReleaseNodeListener l) {
-      throw new UnsupportedOperationException();
-    }
-
-    public void prepare() {
-      if (logger.isDebugEnabled()) logger.debug("Preparing " + this.getClass() + ":" + System.identityHashCode(this));
-    }
-
-    public void commit() {
-      if (logger.isDebugEnabled()) logger.debug("Commit " + this.getClass() + ":" + System.identityHashCode(this));
-    }
-
-    public void rollback() {
-      if (logger.isDebugEnabled()) logger.debug("Rollback " + this.getClass() + ":" + System.identityHashCode(this));
-    }
-
-    public void clear() {
-      if (logger.isDebugEnabled()) logger.debug("Clearing " + this.getClass() + ":" + System.identityHashCode(this));
-    }
-
-    public void clear(int phaseNumber) {
-      if (logger.isDebugEnabled()) logger.debug("Clearing (" + phaseNumber + ") " + this.getClass() + ":" + System.identityHashCode(this));
-    }
-
-    public int[] recover() {
-      if (logger.isDebugEnabled()) logger.debug("Recovering " + this.getClass() + ":" + System.identityHashCode(this));
-      throw new UnsupportedOperationException("Attempting to recover ReadOnlyGraph");
-    }
-
-    public void selectPhase(int phaseNumber) {
-      if (logger.isDebugEnabled()) logger.debug("Selecting Phase " + this.getClass() + ":" + System.identityHashCode(this));
-      throw new UnsupportedOperationException("Attempting to selectPhase of ReadOnlyGraph");
-    }
-
-    public int getPhaseNumber() {
-      return phaseNumber;
-    }
-
-
-    /**
-     * Not used on a read-only graph
-     */
-    public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
-      // do nothing
-    }
-  }
-
-
-  /**
-   * This class represents the state of the the database at a particular time. Only the most
-   * recent phase can be written to.
-   */
-  final class Phase implements PersistableMetaRoot {
-
-    /** The size of the data this object stores in the metaroot */
-    final static int RECORD_SIZE = TripleAVLFile.Phase.RECORD_SIZE * NR_INDEXES;
-
-    /** Maintaines parallel structural phases between all of the parallel tree data structures */
-    private TripleAVLFile.Phase[] tripleAVLFilePhases = new TripleAVLFile.Phase[NR_INDEXES];
-
-    /** The list of graphs valid in this phase. */
-    private List<Long> graphNodes = null;
-
-
-    /**
-     * Creates a new phase based on the current state of the database.
-     * This sets the latest phase on the outer statement store.
-     * @throws IOException Error on the filesystem.
-     */
-    Phase() throws IOException {
-      for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i] = tripleAVLFiles[i].new Phase();
-      currentPhase = this;
-      dirty = true;
-      try {
-        graphNodes = committedGraphNodes == null ? scanForGraphs() : new ArrayList<Long>(committedGraphNodes);
-      } catch (StatementStoreException e) {
-        throw new IOException("Unable to get metadata for phase: " + e.getMessage());
-      }
-    }
-
-
-    /**
-     * A copy constructor for duplicating a phase structure. This sets the latest phase
-     * on the outer statement store.
-     * @throws IOException Error on the filesystem.
-     */
-    Phase(Phase p) throws IOException {
-      assert p != null;
-
-      for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i] = tripleAVLFiles[i].new Phase(p.tripleAVLFilePhases[i]);
-      currentPhase = this;
-      dirty = true;
-      graphNodes = new ArrayList<Long>(p.graphNodes);
-    }
-
-
-    /**
-     * Create a phase based on information found in a buffer that came from a metaroot
-     * @param b The buffer containing the phase information.
-     * @param offset The start of the phase information in the buffer
-     * @throws IOException A filesystem error occurred while accessing the buffer.
-     */
-    Phase(Block b, int offset) throws IOException {
-      for (int i = 0; i < NR_INDEXES; ++i) {
-        tripleAVLFilePhases[i] = tripleAVLFiles[i].new Phase(b, offset);
-        offset += TripleAVLFile.Phase.RECORD_SIZE;
-      }
-      currentPhase = this;
-      dirty = false;
-      try {
-        graphNodes = scanForGraphs();
-      } catch (StatementStoreException sse) {
-        throw new IOException("Error accessing graph data during initialization");
-      }
-    }
-
-
-    /**
-     * Writes this PersistableMetaRoot to the specified Block. The ints are
-     * written at the specified offset.
-     * @param b The metaroot Block to write this object to.
-     * @param offset The start within the buffer of where the phase information should be written to.
-     */
-    public void writeToBlock(Block b, int offset) {
-      for (int i = 0; i < NR_INDEXES; ++i) {
-        tripleAVLFilePhases[i].writeToBlock(b, offset);
-        offset += TripleAVLFile.Phase.RECORD_SIZE;
-      }
-    }
-
-
-    /**
-     * Create a string representation of the current phase.
-     * @return A string representing this phase
-     */
-    public String toString() {
-      StringBuffer sb = new StringBuffer();
-      for (int i = 0; i < NR_INDEXES; ++i) {
-        StoreTuples ts = tripleAVLFilePhases[i].allTuples();
-        try {
-          sb.append(ts).append('\n');
-        } finally {
-          try {
-            ts.close();
-          } catch (TuplesException ex) {
-            logger.warn("TuplesException while closing Tuples", ex);
-            return ex.toString();
-          }
-        }
-      }
-      return sb.toString();
-    }
-
-
-    /**
-     * Tests if any part of this phase has a reference being kept to it
-     * @return <code>true</code> if any part of this phase is being used.
-     */
-    boolean isInUse() {
-      for (int i = 0; i < NR_INDEXES; ++i) {
-        if (tripleAVLFilePhases[i].isInUse()) return true;
-      }
-      return false;
-    }
-
-
-    /**
-     * Tests if the phase contains any triples
-     * @return <code>true</code> if the phase contains 1 or more triples
-     */
-    boolean isEmpty() {
-      return tripleAVLFilePhases[TI_3012].isEmpty();
-    }
-
-
-    /**
-     * Gets the number of triples in the phase
-     * @return The number of triples in this phase
-     */
-    long getNrTriples() {
-      return tripleAVLFilePhases[TI_3012].getNrTriples();
-    }
-
-
-    /**
-     * Adds a new triple to the graph if it doesn't already exist.
-     * @param node0 the first element of the new triple
-     * @param node1 the second element of the new triple
-     * @param node2 the third element of the new triple
-     * @param node3 the fourth element of the new triple
-     * @throws StatementStoreException An IO or data structure error
-     */
-    void addTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
-      assert node0 >= NodePool.MIN_NODE;
-      assert node1 >= NodePool.MIN_NODE;
-      assert node2 >= NodePool.MIN_NODE;
-      assert node3 >= NodePool.MIN_NODE;
-
-      //if (
-      //  DEBUG && nodePool != null &&
-      //  !nodePool.isValid(node0) && !nodePool.isValid(node1) &&
-      //  !nodePool.isValid(node2) && !nodePool.isValid(node3)
-      //) throw new AssertionError(
-      //  "Attempt to add a triple with an invalid node"
-      //);
-
-      long[] triple = new long[]{node0, node1, node2, node3};
-
-      for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i].asyncAddTriple(triple);
-
-      if (node1 == rdfTypeNode && node2 == graphTypeNode && node3 == systemGraphNode) graphNodes.add(node0);
-    }
-
-
-    /**
-     * Removes the specified triple.
-     * @param node0 the value for the first element of the triple
-     * @param node1 the value for the second element of the triple
-     * @param node2 the value for the third element of the triple
-     * @param node3 the value for the fourth element of the triple
-     * @throws StatementStoreException An IO or structural error
-     */
-    void removeTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
-      if (
-          node0 < NodePool.MIN_NODE ||
-          node1 < NodePool.MIN_NODE ||
-          node2 < NodePool.MIN_NODE ||
-          node3 < NodePool.MIN_NODE
-      ) {
-        throw new StatementStoreException("Attempt to remove a triple with node number out of range: " + node0 + " " + node1 + " " + node2 + " " + node3);
-      }
-
-      try {
-        for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i].removeTriple(node0, node1, node2, node3);
-        // removeTriple listeners can be informed here
-      } catch (IOException e) {
-        throw new StatementStoreException("I/O error", e);
-      }
-      if (node1 == rdfTypeNode && node2 == graphTypeNode && node3 == systemGraphNode) graphNodes.remove(node0);
-    }
-
-
-    /**
-     * Finds triples matching the given specification.
-     * @param variableMask the mask used to indicate the desired index.
-     * @param node0 The 0 node of the triple to find.
-     * @param node1 The 1 node of the triple to find.
-     * @param node2 The 2 node of the triple to find.
-     * @param node3 The 3 node of the triple to find.
-     * @return A StoreTuples containing all the triples which match the search.
-     * @throws StatementStoreException An IO or structural error
-     */
-    StoreTuples findTuples(int variableMask, long node0, long node1, long node2, long node3) throws StatementStoreException {
-      if (
-          node0 < NodePool.NONE ||
-          node1 < NodePool.NONE ||
-          node2 < NodePool.NONE ||
-          node3 < NodePool.NONE
-      ) {
-        // There is at least one query node.  Return an empty StoreTuples.
-        return TuplesOperations.empty();
-      }
-
-      if (0 == (variableMask & MASK3)) throw new StatementStoreException("This version of find is for re-ordering graphs, based on a given mask.");
-      try {
-        switch (variableMask) {
-          case MASK3:
-            return tripleAVLFilePhases[TI_3012].findTuples(node3);
-          case MASK0 | MASK3:
-            return tripleAVLFilePhases[TI_3012].findTuples(node3);
-          case MASK1 | MASK3:
-            return tripleAVLFilePhases[TI_3120].findTuples(node3);
-          case MASK0 | MASK1 | MASK3:
-            return tripleAVLFilePhases[TI_3012].findTuples(node3);
-          case MASK2 | MASK3:
-            return tripleAVLFilePhases[TI_3201].findTuples(node3);
-          case MASK0 | MASK2 | MASK3:
-            return tripleAVLFilePhases[TI_3201].findTuples(node3);
-          case MASK1 | MASK2 | MASK3:
-            return tripleAVLFilePhases[TI_3120].findTuples(node3);
-          case MASK0 | MASK1 | MASK2 | MASK3:
-            return tripleAVLFilePhases[TI_3012].findTuples(node3);
-          default:
-            throw new AssertionError();
-        }
-      } catch (IOException ex) {
-        throw new StatementStoreException("I/O error", ex);
-      }
-    }
-
-
-    /**
-     * Finds triples matching the given specification.
-     * @param node0 The 0 node of the triple to find.
-     * @param node1 The 1 node of the triple to find.
-     * @param node2 The 2 node of the triple to find.
-     * @param node3 The 3 node of the triple to find.
-     * @return A StoreTuples containing all the triples which match the search.
-     * @throws StatementStoreException An IO or structural error
-     */
-    StoreTuples findTuples(long node0, long node1, long node2, long node3) throws StatementStoreException {
-      if (
-          node0 < NodePool.NONE ||
-          node1 < NodePool.NONE ||
-          node2 < NodePool.NONE ||
-          node3 < NodePool.NONE
-      ) {
-        // There is at least one query node.  Return an empty StoreTuples.
-        return TuplesOperations.empty();
-      }
-
-      int variableMask =
-        (node0 != NONE ? MASK0 : 0) |
-        (node1 != NONE ? MASK1 : 0) |
-        (node2 != NONE ? MASK2 : 0) |
-        (node3 != NONE ? MASK3 : 0);
-
-      if (node3 == NONE && variableMask != 0) {
-        return joinGraphedTuples(variableMask, node0, node1, node2);
-      }
-
-
-      try {
-        switch (variableMask) {
-          case 0:
-            return tripleAVLFilePhases[TI_3012].allTuples();
-          case MASK3:
-            return tripleAVLFilePhases[TI_3012].findTuples(node3);
-          case MASK0 | MASK3:
-            return tripleAVLFilePhases[TI_3012].findTuples(node3, node0);
-          case MASK1 | MASK3:
-            return tripleAVLFilePhases[TI_3120].findTuples(node3, node1);
-          case MASK0 | MASK1 | MASK3:
-            return tripleAVLFilePhases[TI_3012].findTuples(node3, node0, node1);
-          case MASK2 | MASK3:
-            return tripleAVLFilePhases[TI_3201].findTuples(node3, node2);
-          case MASK0 | MASK2 | MASK3:
-            return tripleAVLFilePhases[TI_3201].findTuples(node3, node2, node0);
-          case MASK1 | MASK2 | MASK3:
-            return tripleAVLFilePhases[TI_3120].findTuples(node3, node1, node2);
-          case MASK0 | MASK1 | MASK2 | MASK3:
-            if (tripleAVLFilePhases[TI_3012].existsTriple(node3, node0, node1, node2)) {
-              return TuplesOperations.unconstrained();
-            }
-            return TuplesOperations.empty();
-          default:
-            throw new AssertionError("Search structure incorrectly calculated");
-        }
-      } catch (IOException ex) {
-        throw new StatementStoreException("I/O error", ex);
-      }
-    }
-
-
-    StoreTuples findTuples(boolean node0Bound, boolean node1Bound, boolean node2Bound, boolean node3Bound) throws StatementStoreException {
-      // The variable mask does not need MASK3, as this has been taken into account in selectIndex[]
-      int variableMask =
-          (node0Bound ? MASK0 : 0) |
-          (node1Bound ? MASK1 : 0) |
-          (node2Bound ? MASK2 : 0);
-      if (variableMask == 0 || node3Bound) {
-        return tripleAVLFilePhases[selectIndex[variableMask]].allTuples();
-      } else {
-        return joinGraphedTuples(variableMask);
-      }
-    }
-
-
-    /**
-     * Iterates over all graphs, finding requested tuples, and joining all the results together into a single tuples.
-     * @param variableMask Pre-calculated from the bound node parameters.
-     * @param node0 The bound value for node0, or < 0 if not bound.
-     * @param node1 The bound value for node1, or < 0 if not bound.
-     * @param node2 The bound value for node2, or < 0 if not bound.
-     * @return A StoreTuples with all the intermediate tuples appended.
-     * @throws StatementStoreException On an error accessing the store.
-     */
-    StoreTuples joinGraphedTuples(int variableMask, long node0, long node1, long node2) throws StatementStoreException {
-      try {
-        assert (variableMask & MASK3) == 0 : "Must not be asking to join on multiple graphs unless graph is variable.";
-
-        // get the graphNodes if not already configured
-        if (graphNodes.isEmpty()) throw new IllegalStateException("Unable to query for variable graphs until graphs are initialized");
-
-        if (variableMask == (MASK0 | MASK1 | MASK2)) {
-          LiteralGraphTuples result = new LiteralGraphTuples(false);
-          for (long graphNode: graphNodes) {
-            if (tripleAVLFilePhases[TI_3012].existsTriple(node0, node1, node2, graphNode)) {
-              result.appendTuple(new long[] { graphNode });
-            }
-          }
-          return result;
-        }
-
-        ArrayList<StoreTuples> graphedTuples = new ArrayList<StoreTuples>();
-        for (long graphNode: graphNodes) {
-          StoreTuples partialResult = null;
-          switch (variableMask) {
-            case 0:
-              partialResult = tripleAVLFilePhases[TI_3012].findTuplesForMeta(graphNode);
-              break;
-            case MASK0:
-              partialResult = tripleAVLFilePhases[TI_3012].findTuplesForMeta(graphNode, node0);
-              break;
-            case MASK1:
-              partialResult = tripleAVLFilePhases[TI_3120].findTuplesForMeta(graphNode, node1);
-              break;
-            case MASK0 | MASK1:
-              partialResult = tripleAVLFilePhases[TI_3012].findTuplesForMeta(graphNode, node0, node1);
-              break;
-            case MASK2:
-              partialResult = tripleAVLFilePhases[TI_3201].findTuplesForMeta(graphNode, node2);
-              break;
-            case MASK0 | MASK2:
-              partialResult = tripleAVLFilePhases[TI_3201].findTuplesForMeta(graphNode, node2, node0);
-              break;
-            case MASK1 | MASK2:
-              partialResult = tripleAVLFilePhases[TI_3120].findTuplesForMeta(graphNode, node1, node2);
-              break;
-            default:
-              throw new AssertionError("Search structure incorrectly calculated");
-          }
-          graphedTuples.add(partialResult);
-        }
-        return TuplesOperations.appendCompatible(graphedTuples);
-      } catch (TuplesException te) {
-        throw new StatementStoreException("Error accessing Tuples", te);
-      } catch (IOException ex) {
-        throw new StatementStoreException("I/O error", ex);
-      }
-    }
-
-
-    /**
-     * Iterates over all graphs, getting all tuples in the requested order,
-     * and joining all the results together into a single tuples.
-     * @param variableMask Determines the required ordering of the data.
-     * @return A StoreTuples with all the intermediate tuples appended.
-     * @throws StatementStoreException On an error accessing the store.
-     */
-    StoreTuples joinGraphedTuples(int variableMask) throws StatementStoreException {
-      try {
-        assert (variableMask & MASK3) == 0 : "Must not be asking to join on multiple graphs unless graph is variable.";
-
-        // get the graphNodes if not already configured
-        if (graphNodes.isEmpty()) throw new IllegalStateException("Unable to query for variable graphs until graphs are initialized");
-
-        ArrayList<StoreTuples> graphedTuples = new ArrayList<StoreTuples>();
-        for (long graphNode: graphNodes) {
-          int phaseIndex;
-          switch (variableMask) {
-            case 0:
-            case MASK0:
-            case MASK0 | MASK1:
-            case MASK0 | MASK1 | MASK2:
-              phaseIndex = TI_3012;
-              break;
-            case MASK1:
-            case MASK1 | MASK2:
-              phaseIndex = TI_3120;
-              break;
-            case MASK2:
-            case MASK0 | MASK2:
-              phaseIndex = TI_3201;
-              break;
-            default:
-              throw new AssertionError("Search structure incorrectly calculated");
-          }
-          StoreTuples partialResult = tripleAVLFilePhases[phaseIndex].findTuplesForMeta(graphNode);
-          graphedTuples.add(partialResult);
-        }
-        return TuplesOperations.appendCompatible(graphedTuples);
-      } catch (TuplesException te) {
-        throw new StatementStoreException("Error accessing Tuples", te);
-      } catch (IOException ex) {
-        throw new StatementStoreException("I/O error", ex);
-      }
-    }
-
-
-    /**
-     * Test is there exist triples according to a given pattern
-     * @param node0 A subject gNode, or NONE
-     * @param node1 A predicate gNode, or NONE
-     * @param node2 A object gNode, or NONE
-     * @param node3 A subject gNode. May not be NONE
-     * @return <code>true</code> if there exist triples that match the pattern
-     * @throws StatementStoreException A structural or IO exception
-     */
-    boolean existsTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
-      if (node3 == NONE) throw new IllegalStateException("Graph must be specified");
-
-      if (
-          node0 < NodePool.NONE ||
-          node1 < NodePool.NONE ||
-          node2 < NodePool.NONE ||
-          node3 < NodePool.NONE
-      ) {
-        // There is at least one query node (comes from the query, but not in the data pool).
-        // Return an empty StoreTuples.
-        return false;
-      }
-
-      int variableMask =
-          (node0 != NONE ? MASK0 : 0) |
-          (node1 != NONE ? MASK1 : 0) |
-          (node2 != NONE ? MASK2 : 0) |
-          MASK3;
-
-      try {
-        switch (variableMask) {
-          case MASK3:
-            return tripleAVLFilePhases[TI_3012].existsTriples(node3);
-          case MASK0 | MASK3:
-            return tripleAVLFilePhases[TI_3012].existsTriples(node3, node0);
-          case MASK1 | MASK3:
-            return tripleAVLFilePhases[TI_3120].existsTriples(node3, node1);
-          case MASK0 | MASK1 | MASK3:
-            return tripleAVLFilePhases[TI_3012].existsTriples(node3, node0, node1);
-          case MASK2 | MASK3:
-            return tripleAVLFilePhases[TI_3201].existsTriples(node3, node2);
-          case MASK0 | MASK2 | MASK3:
-            return tripleAVLFilePhases[TI_3201].existsTriples(node3, node2, node0);
-          case MASK1 | MASK2 | MASK3:
-            return tripleAVLFilePhases[TI_3120].existsTriples(node3, node1, node2);
-          case MASK0 | MASK1 | MASK2 | MASK3:
-            return tripleAVLFilePhases[TI_3012].existsTriple(node3, node0, node1, node2);
-          default:
-            throw new AssertionError("Search structure incorrectly calculated");
-        }
-      } catch (IOException ex) {
-        throw new StatementStoreException("I/O error", ex);
-      }
-    }
-
-
-    /**
-     * Check that each index contains the same number of triples
-     * @throws AssertionError if the indexes contain a differing number of triples
-     */ 
-    long checkIntegrity() {
-      long nrTriples[] = new long[NR_INDEXES];
-
-      for (int i = 0; i < NR_INDEXES; ++i) nrTriples[i] = tripleAVLFilePhases[i].checkIntegrity();
-
-      for (int i = 1; i < NR_INDEXES; ++i) {
-        if (nrTriples[0] != nrTriples[i]) {
-          StringBuffer sb = new StringBuffer("tripleAVLFiles disagree on the number of triples:");
-          for (int j = 0; j < NR_INDEXES; ++j) sb.append(' ').append(nrTriples[j]);
-          throw new AssertionError(sb.toString());
-        }
-      }
-
-      return nrTriples[0];
-    }
-
-
-    /**
-     * Ask the system for all the known graphs.
-     * @return All the known graph nodes.
-     */
-    List<Long> scanForGraphs() throws StatementStoreException, IOException {
-      List<Long> nodeList = new ArrayList<Long>();
-
-      if (systemGraphNode == NONE || rdfTypeNode == NONE || graphTypeNode == NONE) return nodeList;
-
-      StoreTuples graphTuples = tripleAVLFilePhases[TI_3120].findTuples(systemGraphNode, rdfTypeNode, graphTypeNode);
-      assert graphTuples.getNumberOfVariables() == 1;
-
-      try {
-        graphTuples.beforeFirst();
-        while (graphTuples.next()) nodeList.add(graphTuples.getColumnValue(0));
-      } catch (TuplesException e) {
-        throw new StatementStoreException("Unable to construct a result containing all graphs.", e);
-      }
-
-      return nodeList;
-    }
-
-
-    /**
-     * Increment the reference count on this object.
-     * @return A new token representing the reference.
-     */
-    Token use() {
-      return new Token();
-    }
-
-
-    /**
-     * A token to reference the phase, incrementing the reference count from the perpective
-     * of the garbage collector.
-     */
-    final class Token {
-
-      /** A list of tokens from the underlying indexes */
-      private TripleAVLFile.Phase.Token[] tripleAVLFileTokens = new TripleAVLFile.Phase.Token[NR_INDEXES];
-
-      /** The phase being referenced */
-      private Phase phase = Phase.this;
-
-
-      /**
-       * Creates a token. This creates tokens for the underlying objects as well.
-       */
-      Token() {
-        for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFileTokens[i] = tripleAVLFilePhases[i].use();
-      }
-
-
-      /**
-       * Get the phase that this token represents.
-       * @return The phase referenced by this token.
-       */
-      public Phase getPhase() {
-        assert tripleAVLFileTokens != null : "Invalid Token";
-        return phase;
-      }
-
-
-      /**
-       * Reduce the reference count on the referenced phase by releasing this token.
-       * The token may not be used after being released.
-       */
-      public void release() {
-        assert tripleAVLFileTokens != null : "Invalid Token";
-        for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFileTokens[i].release();
-        tripleAVLFileTokens = null;
-        phase = null;
-      }
-
-    }
-
-  }
-
-
-  /**
-   * @see org.mulgara.store.xa.XAStatementStore#initializeSystemNodes(long, long, long)
-   * Set the various system graph nodes. These may only be set once, but will allow duplicate calls if the values are the same.
-   * @param systemGraphNode The new system graph node.
-   * @param rdfTypeNode The node for <rdf:graph>.
-   * @param systemGraphTypeNode The node for the system graph type.
-   */
-  public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
-    if (this.systemGraphNode != NONE && systemGraphNode != this.systemGraphNode) {
-      throw new IllegalStateException("Cannot set system graph again. Was: " + this.systemGraphNode + ", now: " + systemGraphNode);
-    }
-    if (systemGraphNode < 0) throw new IllegalArgumentException("Attempt to set invalid system graph node");
-    this.systemGraphNode = systemGraphNode;
-
-    if (this.rdfTypeNode != NONE && rdfTypeNode != this.rdfTypeNode) {
-      throw new IllegalStateException("Cannot set the rdf:type node again. Was: " + this.rdfTypeNode + ", now: " + rdfTypeNode);
-    }
-    if (rdfTypeNode < 0) throw new IllegalArgumentException("Attempt to set invalid rdf:type node");
-    this.rdfTypeNode = rdfTypeNode;
-
-    if (this.graphTypeNode != NONE && systemGraphTypeNode != this.graphTypeNode) {
-      throw new IllegalStateException("Cannot set graph type again. Was: " + this.graphTypeNode + ", now: " + systemGraphTypeNode);
-    }
-    if (systemGraphTypeNode < 0) throw new IllegalArgumentException("Attempt to set invalid graph type node");
-    this.graphTypeNode = systemGraphTypeNode;
-  }
-
-}

Copied: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java (from rev 1456, branches/xa11/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java)
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java	                        (rev 0)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -0,0 +1,1796 @@
+/*
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Original Code is the Kowari Metadata Store.
+ *
+ * The Initial Developer of the Original Code is Plugged In Software Pty
+ * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
+ * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
+ * Plugged In Software Pty Ltd. All Rights Reserved.
+ *
+ * Contributor(s): N/A.
+ *
+ * [NOTE: The text of this Exhibit A may differ slightly from the text
+ * of the notices in the Source Code files of the Original Code. You
+ * should use the text of this Exhibit A rather than the text found in the
+ * Original Code Source Code for Your Modifications.]
+ *
+ */
+package org.mulgara.store.statement.xa11;
+
+import java.io.*;
+import java.nio.*;
+
+// Java 2 standard packages
+import java.util.*;
+
+// Third party packages
+import org.apache.log4j.Logger;
+
+// Locally written packages
+import org.mulgara.query.*;
+import org.mulgara.store.nodepool.*;
+import org.mulgara.store.statement.*;
+import org.mulgara.store.statement.xa.TripleAVLFile;
+import org.mulgara.store.tuples.StoreTuples;
+import org.mulgara.store.tuples.TuplesOperations;
+import org.mulgara.store.xa.AbstractBlockFile;
+import org.mulgara.store.xa.Block;
+import org.mulgara.store.xa.BlockFile;
+import org.mulgara.store.xa.LockFile;
+import org.mulgara.store.xa.PersistableMetaRoot;
+import org.mulgara.store.xa.SimpleXAResourceException;
+import org.mulgara.store.xa.XAStatementStore;
+import org.mulgara.store.xa.XAUtils;
+import org.mulgara.util.Constants;
+
+/**
+ * An implementation of {@link StatementStore}.
+ *
+ * @created 2008-09-30
+ * @author Paul Gearon
+ * @company <A href="mailto:info at PIsoftware.com">Plugged In Software</A>
+ * @copyright &copy;2001-2004 <a href="http://www.pisoftware.com/">Plugged In Software Pty Ltd</a>
+ * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
+ */
+public final class XA11StatementStoreImpl implements XAStatementStore {
+
+  /** Logger. */
+  private final static Logger logger = Logger.getLogger(XA11StatementStoreImpl.class);
+
+  /** The value of the invalid gNode */
+  final static long NONE = NodePool.NONE;
+
+  /** The subject/predicate/object index */
+  final static int TI_3012 = 0;
+
+  /** The predicate/object/subject index */
+  final static int TI_3120 = 1;
+
+  /** The object/subject/predicate index */
+  final static int TI_3201 = 2;
+
+  /** The number of indexes */
+  final static int NR_INDEXES = 3;
+
+  /** The ordering of indexes, as indexed by the TI_ values */
+  private final static int[][] orders = {
+      {3, 0, 1, 2},  // TI_3012
+      {3, 1, 2, 0},  // TI_3120
+      {3, 2, 0, 1}   // TI_3201
+  };
+
+  private final static int[] selectIndex = {
+    /* 3XXX */ TI_3012,
+    /* 3XX0 */ TI_3012,
+    /* 3X1X */ TI_3120,
+    /* 3X10 */ TI_3012,
+    /* 32XX */ TI_3201,
+    /* 32X0 */ TI_3201,
+    /* 321X */ TI_3120,
+    /* 3210 */ TI_3012
+  };
+
+  /** A number to identify the correct file type */
+  private final static int FILE_MAGIC = 0xa5e7f21e;
+
+  /** The version of file format */
+  private final static int FILE_VERSION = 9;
+
+  /** Index of the file magic number within each of the two on-disk metaroots. */
+  private final static int IDX_MAGIC = 0;
+
+  /** Index of the file version number within each of the two on-disk metaroots. */
+  private final static int IDX_VERSION = 1;
+
+  /** Index of the valid flag (in ints) within each of the two on-disk metaroots. */
+  private final static int IDX_VALID = 2;
+
+  /** The index of the phase number in the on-disk phase. */
+  private final static int IDX_PHASE_NUMBER = 3;
+
+  /** The size of the header of a metaroot in ints. */
+  private final static int HEADER_SIZE_INTS = 4;
+
+  /** The size of the header of a metaroot in longs. */
+  private final static int HEADER_SIZE_LONGS = (HEADER_SIZE_INTS + 1) / 2;
+
+  /** The size of a metaroot in longs. */
+  private final static int METAROOT_SIZE = HEADER_SIZE_LONGS + Phase.RECORD_SIZE;
+
+  /** The number of metaroots in the metaroot file. */
+  private final static int NR_METAROOTS = 2;
+
+  /** The mask for a bound Subject */
+  private final static int MASK0 = 1;
+
+  /** The mask for a bound Predicate */
+  private final static int MASK1 = 2;
+
+  /** The mask for a bound Object */
+  private final static int MASK2 = 4;
+
+  /** The mask for a bound Graph. This must always be set. */
+  private final static int MASK3 = 8;
+
+  /** The node number for the system graph. Globalized to <#>. */
+  private long systemGraphNode = NONE;
+
+  /** The node number for <rdf:type>. */
+  private long rdfTypeNode = NONE;
+
+  /** The node number for the graph class <mulgara:ModelType>. */
+  private long graphTypeNode = NONE;
+
+  /** The name of the triple store which forms the base name for the graph files. */
+  private String fileName;
+
+  /** The LockFile that protects the graph from being opened twice. */
+  private LockFile lockFile;
+
+  /** The BlockFile for the node pool metaroot file. */
+  private BlockFile metarootFile = null;
+
+  /** The metaroot blocks of the metaroot file. */
+  private Block[] metarootBlocks = new Block[NR_METAROOTS];
+
+  /** An error flag that is set during file initialization if the file version is incorrect */
+  private boolean wrongFileVersion = false;
+
+  /** The files containing indexed triples */
+  private TripleAVLFile[] tripleAVLFiles = new TripleAVLFile[NR_INDEXES];
+
+  /** The current read/write phase. Only the latest phase can write. */
+  private Phase currentPhase = null;
+
+  /**
+   * Determines if modifications can be performed without creating a new
+   * (in-memory) phase. If dirty is false and the current phase is in use (by
+   * unclosed Tupleses) then a new phase must be created to protect the existing
+   * Tupleses before any further modifications are made.
+   */
+  private boolean dirty = true;
+
+  /**
+   * The index of the phase in the metaroot. May be 0 or 1 as the commited phase swaps
+   * between the two metaroots.
+   */
+  private int phaseIndex = 0;
+
+  /** The number of the current phase */
+  private int phaseNumber = 0;
+
+  /** A reference token for keeping the commited phase available until we no longer need it */
+  private Phase.Token committedPhaseToken = null;
+
+  /** A synchronization object for locking access to the committed phase */
+  private Object committedPhaseLock = new Object();
+
+  /** A reference token for keeping the recording phase available until we no longer need it */
+  private Phase.Token recordingPhaseToken = null;
+
+  /** The list of graphs known to this statement store. */
+  private List<Long> committedGraphNodes;
+
+  /**
+   * This flag indicates that the current object has been fully written, and may be considered
+   * as committed when the rest of the system is ready.
+   */
+  private boolean prepared = false;
+
+  /** A set of objects to be informed when nodes are released. */
+  private List<ReleaseNodeListener> releaseNodeListeners = new ArrayList<ReleaseNodeListener>();
+
+
+  /**
+   * Creates a statement store using a base filename.
+   *
+   * @param fileName The base filename to operate from.
+   * @throws IOException The mass storage could not be accessed.
+   */
+  public XA11StatementStoreImpl(String fileName) throws IOException {
+    this.fileName = fileName;
+
+    lockFile = LockFile.createLockFile(fileName + ".g.lock");
+
+    try {
+      // Check that the metaroot file was created with a compatible version of the triplestore.
+      RandomAccessFile metarootRAF = null;
+      try {
+        metarootRAF = new RandomAccessFile(fileName + ".g", "r");
+        if (metarootRAF.length() >= 2 * Constants.SIZEOF_INT) {
+          int fileMagic = metarootRAF.readInt();
+          int fileVersion = metarootRAF.readInt();
+          if (AbstractBlockFile.byteOrder != ByteOrder.BIG_ENDIAN) {
+            fileMagic = XAUtils.bswap(fileMagic);
+            fileVersion = XAUtils.bswap(fileVersion);
+          }
+          wrongFileVersion = fileMagic != FILE_MAGIC || fileVersion != FILE_VERSION;
+        } else {
+          wrongFileVersion = false;
+        }
+      } catch (FileNotFoundException ex) {
+        wrongFileVersion = false;
+      } finally {
+        if (metarootRAF != null) metarootRAF.close();
+      }
+
+      for (int i = 0; i < NR_INDEXES; ++i) {
+        String suffix = ".g_" + orders[i][0] + orders[i][1] + orders[i][2] + orders[i][3];
+        tripleAVLFiles[i] = new TripleAVLFile(fileName + suffix, orders[i]);
+      }
+    } catch (IOException ex) {
+      try {
+        close();
+      } catch (StatementStoreException ex2) { /* no-op */ }
+      throw ex;
+    }
+  }
+
+
+  /**
+   * Returns <code>true</code> if there are no triples in the graph
+   * @return <code>true</code> if there are no triples in the graph
+   */
+  public synchronized boolean isEmpty() {
+    checkInitialized();
+    return currentPhase.isEmpty();
+  }
+
+
+  /**
+   * Returns a count of the number of triples in the graph
+   * @return a count of the number of triples in the graph
+   */
+  public synchronized long getNrTriples() {
+    checkInitialized();
+    return currentPhase.getNrTriples();
+  }
+
+
+  /**
+   * Gets the PhaseNumber attribute of the XAGraphImpl object
+   * @return The PhaseNumber value
+   */
+  public synchronized int getPhaseNumber() {
+    checkInitialized();
+    return phaseNumber;
+  }
+
+
+  /**
+   * Adds a feature to the ReleaseNodeListener attribute of the XAGraphImpl object
+   * @param l The feature to be added to the ReleaseNodeListener attribute
+   */
+  public synchronized void addReleaseNodeListener(ReleaseNodeListener l) {
+    if (!releaseNodeListeners.contains(l)) releaseNodeListeners.add(l);
+  }
+
+
+  /**
+   * Removes a release node listener.
+   * @param l The listener to remove.
+   */
+  public synchronized void removeReleaseNodeListener(ReleaseNodeListener l) {
+    releaseNodeListeners.remove(l);
+  }
+
+
+  /**
+   * Adds a new triple to the graph if it doesn't already exist.
+   * @param node0 the first element of the new triple
+   * @param node1 the second element of the new triple
+   * @param node2 the third element of the new triple
+   * @param node3 the fourth element of the new triple
+   * @throws StatementStoreException Due to structural or IO errors.
+   */
+  public synchronized void addTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
+    checkInitialized();
+    if (
+        node0 < NodePool.MIN_NODE ||
+        node1 < NodePool.MIN_NODE ||
+        node2 < NodePool.MIN_NODE ||
+        node3 < NodePool.MIN_NODE
+    ) {
+      throw new StatementStoreException(
+          "Attempt to add a triple with node number out of range: " + node0 + " " + node1 + " " + node2 + " " + node3
+      );
+    }
+
+    if (!dirty && currentPhase.isInUse()) {
+      try {
+        new Phase();
+      } catch (IOException ex) {
+        throw new StatementStoreException("I/O error", ex);
+      }
+    }
+
+    currentPhase.addTriple(node0, node1, node2, node3);
+  }
+
+
+  /**
+   * Removes all triples matching the given specification.
+   * @param node0 the value for the first element of the triples
+   * @param node1 the value for the second element of the triples
+   * @param node2 the value for the third element of the triples
+   * @param node3 the value for the fourth element of the triples
+   * @throws StatementStoreException if something exceptional happens
+   */
+  public synchronized void removeTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+    checkInitialized();
+    if (node0 != NONE && node1 != NONE && node2 != NONE && node3 != NONE) {
+      if (!dirty && currentPhase.isInUse()) {
+        try {
+          new Phase();
+        } catch (IOException ex) {
+          throw new StatementStoreException("I/O error", ex);
+        }
+      }
+
+      // Remove the triple.
+      currentPhase.removeTriple(node0, node1, node2, node3);
+    } else {
+      // Find all the tuples matching the specification and remove them.
+      StoreTuples tuples = currentPhase.findTuples(node0, node1, node2, node3);
+      try {
+        try {
+          if (!tuples.isEmpty()) {
+            // There is at least one triple to remove so protect the
+            // Tuples as we make changes to the triplestore.
+            try {
+              new Phase();
+            } catch (IOException ex) {
+              throw new StatementStoreException("I/O error", ex);
+            }
+
+            long[] triple = new long[] { node0, node1, node2, node3 };
+            int[] columnMap = tuples.getColumnOrder();
+            int nrColumns = columnMap.length;
+            tuples.beforeFirst();
+            while (tuples.next()) {
+              // Copy the row data over to the triple.
+              for (int col = 0; col < nrColumns; ++col) {
+                triple[columnMap[col]] = tuples.getColumnValue(col);
+              }
+
+              currentPhase.removeTriple(triple[0], triple[1], triple[2], triple[3]);
+            }
+          }
+        } finally {
+          tuples.close();
+        }
+      } catch (TuplesException ex) {
+        throw new StatementStoreException("Exception while iterating over temporary Tuples.", ex);
+      }
+    }
+  }
+
+
+  /**
+   * Finds triples matching the given specification.
+   * @param node0 The 0 node of the triple to find.
+   * @param node1 The 1 node of the triple to find.
+   * @param node2 The 2 node of the triple to find.
+   * @param node3 The 3 node of the triple to find.
+   * @return A set of all the triples which match the search.
+   * @throws StatementStoreException Due to a structural or IO error.
+   */
+  public synchronized StoreTuples findTuples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+    checkInitialized();
+    dirty = false;
+    return currentPhase.findTuples(node0, node1, node2, node3);
+  }
+
+  
+  /**
+   * Finds triples matching the given specification and index mask.
+   * @param mask The mask of the index to use. This is only allowable for 3 variables
+   *             and a given graph.
+   * @param node0 The 0 node of the triple to find.
+   * @param node1 The 1 node of the triple to find.
+   * @param node2 The 2 node of the triple to find.
+   * @param node3 The 3 node of the triple to find.
+   * @return A set of all the triples which match the search.
+   * @throws StatementStoreException Due to a structural or IO error.
+   */
+  public synchronized StoreTuples findTuples(
+      int mask, long node0, long node1, long node2, long node3
+  ) throws StatementStoreException {
+    checkInitialized();
+    dirty = false;
+    if (!checkMask(mask, node0, node1, node2, node3)) throw new StatementStoreException("Bad explicit index selection for given node pattern.");
+    return currentPhase.findTuples(mask, node0, node1, node2, node3);
+  }
+
+
+  /**
+   * Tests a mask for consistency against the nodes it will be used to find.
+   * @param mask The mask to test.
+   * @param node0 The 0 node of the triple to find.
+   * @param node1 The 1 node of the triple to find.
+   * @param node2 The 2 node of the triple to find.
+   * @param node3 The 3 node of the triple to find. Must not be NONE.
+   * @return <code>true</code> if the mask is consistent with the given nodes.
+   */
+  private static boolean checkMask(int mask, long node0, long node1, long node2, long node3) {
+    // The graph must be bound
+    if (node3 != NONE) return false;
+    if (node0 != NONE && 0 == (mask & MASK0)) return false;
+    if (node1 != NONE && 0 == (mask & MASK1)) return false;
+    if (node2 != NONE && 0 == (mask & MASK2)) return false;
+    return true;
+  }
+
+
+  /**
+   * Returns a StoreTuples which contains all triples in the store.  The
+   * parameters provide a hint about how the StoreTuples will be used.  This
+   * information is used to select the index from which the StoreTuples will be
+   * obtained.
+   * @param node0Bound specifies that node0 will be bound
+   * @param node1Bound specifies that node1 will be bound
+   * @param node2Bound specifies that node2 will be bound
+   * @return the {@link StoreTuples}
+   * @throws StatementStoreException if something exceptional happens
+   */
+  public synchronized StoreTuples findTuples(boolean node0Bound, boolean node1Bound, boolean node2Bound, boolean node3Bound) throws StatementStoreException {
+    checkInitialized();
+    dirty = false;
+    return currentPhase.findTuples(node0Bound, node1Bound, node2Bound, node3Bound);
+  }
+
+
+  /**
+   * Returns <code>true</code> if any triples match the given specification.
+   * Allows wild cards StatementStore.NONE for any of the node numbers except node3.
+   * @param node0 The 0 node of the triple to find.
+   * @param node1 The 1 node of the triple to find.
+   * @param node2 The 2 node of the triple to find.
+   * @param node3 The 3 node of the triple to find.
+   * @return <code>true</code> if any matching triples exist in the graph.
+   * @throws StatementStoreException Due to a structural or IO error.
+   */
+  public synchronized boolean existsTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+    checkInitialized();
+    return currentPhase.existsTriples(node0, node1, node2, node3);
+  }
+
+
+  public XAStatementStore newReadOnlyStatementStore() {
+    return new ReadOnlyGraph();
+  }
+
+
+  public XAStatementStore newWritableStatementStore() {
+    return this;
+  }
+
+
+  /**
+   * Close all files, removing empty space from the ends as required.
+   * @throws StatementStoreException if an error occurs while truncating,
+   * flushing or closing one of the three files.
+   */
+  public synchronized void close() throws StatementStoreException {
+    try {
+      unmap();
+    } finally {
+      try {
+        IOException savedEx = null;
+
+        for (int i = 0; i < NR_INDEXES; ++i) {
+          try {
+            if (tripleAVLFiles[i] != null) tripleAVLFiles[i].close();
+          } catch (IOException ex) {
+            savedEx = ex;
+          }
+        }
+
+        if (metarootFile != null) {
+          try {
+            metarootFile.close();
+          } catch (IOException ex) {
+            savedEx = ex;
+          }
+        }
+
+        if (savedEx != null) throw new StatementStoreException("I/O error closing graph.", savedEx);
+      } finally {
+        if (lockFile != null) {
+          lockFile.release();
+          lockFile = null;
+        }
+      }
+    }
+  }
+
+
+  /**
+   * Close this graph, if it is currently open, and remove all files associated with it.
+   * @throws StatementStoreException Due to an IO error.
+   */
+  public synchronized void delete() throws StatementStoreException {
+    currentPhase = null;
+    try {
+      unmap();
+    } finally {
+      try {
+        IOException savedEx = null;
+
+        for (int i = 0; i < NR_INDEXES; ++i) {
+          try {
+            if (tripleAVLFiles[i] != null) tripleAVLFiles[i].delete();
+          } catch (IOException ex) {
+            savedEx = ex;
+          }
+        }
+
+        if (metarootFile != null) {
+          try {
+            metarootFile.delete();
+          } catch (IOException ex) {
+            savedEx = ex;
+          }
+        }
+
+        if (savedEx != null) throw new StatementStoreException("I/O error deleting graph.", savedEx);
+      } finally {
+        for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFiles[i] = null;
+        metarootFile = null;
+        if (lockFile != null) {
+          lockFile.release();
+          lockFile = null;
+        }
+      }
+    }
+  }
+
+
+  /**
+   * Try to safely close the store if this was not done explicitly.
+   */
+  protected void finalize() {
+    try {
+      close();
+    } catch (Throwable t) {
+      logger.warn("Exception in finalize while trying to close the statement store.", t);
+    }
+  }
+
+
+  /**
+   * A manually tracked reference to this object was released. Does nothing.
+   */
+  public void release() {
+    if (logger.isDebugEnabled()) logger.debug("Release " + this.getClass() + ":" + System.identityHashCode(this));
+  }
+
+
+  /**
+   * This in called in response to the resource being manually refreshed.
+   * This implementation does nothing here.
+   */
+  public void refresh() {
+    if (logger.isDebugEnabled()) {
+      logger.debug("Refresh " + this.getClass() + ":" + System.identityHashCode(this));
+    }
+  }
+
+
+  //
+  // Methods from SimpleXAResource.
+  //
+
+  /**
+   * Clears this store to a fresh state.
+   * @param phaseNumber The phase number to set to.
+   * @throws IOException Error with file access
+   * @throws SimpleXAResourceException Error with the data structures.
+   */
+  public synchronized void clear(int phaseNumber) throws IOException, SimpleXAResourceException {
+    if (logger.isDebugEnabled()) {
+      logger.debug("Clear(" + phaseNumber + ") " + this.getClass() + ":" + System.identityHashCode(this));
+    }
+    if (currentPhase != null) throw new IllegalStateException("Graph already has a current phase.");
+
+    openMetarootFile(true);
+
+    synchronized (committedPhaseLock) {
+      committedPhaseToken = new Phase().use();
+    }
+    this.phaseNumber = phaseNumber;
+    phaseIndex = 1;
+    for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFiles[i].clear();
+
+    new Phase();
+  }
+
+
+  /**
+   * Clear the state of the database.
+   * @throws IOException Filesystem error
+   * @throws SimpleXAResourceException Error in the data structures.
+   */
+  public synchronized void clear() throws IOException, SimpleXAResourceException {
+    if (logger.isDebugEnabled()) logger.debug("Clear " + this.getClass() + ":" + System.identityHashCode(this));
+    if (currentPhase == null) clear(0);
+
+    // could throw an exception if clear() is called after any other
+    // operations are performed.  Calling clear() multiple times should be
+    // permitted.
+  }
+
+
+  /**
+   * Perform all the operations for a commit and return when all the data structures are in place.
+   * @throws SimpleXAResourceException Due to a bad transaction state, or an IO error while preparing.
+   */
+  public synchronized void prepare() throws SimpleXAResourceException {
+    if (logger.isDebugEnabled()) logger.debug("Prepare " + this.getClass() + ":" + System.identityHashCode(this));
+    checkInitialized();
+
+    // check that prepare() was not caleld twice
+    if (prepared) throw new SimpleXAResourceException("prepare() called twice.");
+
+    try {
+      // Perform a prepare.
+      recordingPhaseToken = currentPhase.use();
+      Phase recordingPhase = currentPhase;
+      new Phase();
+
+      // Ensure that all data associated with the phase is on disk.
+      for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFiles[i].force();
+
+      // Write the metaroot.
+      int newPhaseIndex = 1 - phaseIndex;
+      int newPhaseNumber = phaseNumber + 1;
+
+      Block block = metarootBlocks[newPhaseIndex];
+      block.putInt(IDX_VALID, 0); // should already be invalid.
+      block.putInt(IDX_PHASE_NUMBER, newPhaseNumber);
+      logger.debug("Writing graph metaroot for phase: " + newPhaseNumber);
+      recordingPhase.writeToBlock(block, HEADER_SIZE_LONGS);
+      block.write();
+      metarootFile.force();
+      block.putInt(IDX_VALID, 1);
+      block.write();
+      metarootFile.force();
+
+      phaseIndex = newPhaseIndex;
+      phaseNumber = newPhaseNumber;
+      prepared = true;
+    } catch (IOException ex) {
+      logger.error("I/O error while performing prepare.", ex);
+      throw new SimpleXAResourceException("I/O error while performing prepare.", ex);
+    } finally {
+      if (!prepared) {
+        // Something went wrong. An exception is on its way out
+        logger.error("Prepare failed.");
+        if (recordingPhaseToken != null) {
+          recordingPhaseToken.release();
+          recordingPhaseToken = null;
+        }
+      }
+    }
+  }
+
+
+  /**
+   * Update the metadata to point to the prepared data structures.
+   * @throws SimpleXAResourceException Due to a bad transaction state, or an IO error.
+   */
+  public synchronized void commit() throws SimpleXAResourceException {
+    if (logger.isDebugEnabled()) logger.debug("Commit " + this.getClass() + ":" + System.identityHashCode(this));
+
+    // check that prepare has been called
+    if (!prepared) throw new SimpleXAResourceException("commit() called without previous prepare().");
+
+    // Perform a commit.
+    try {
+      // Invalidate the metaroot of the old phase.
+      Block block = metarootBlocks[1 - phaseIndex];
+      block.putInt(IDX_VALID, 0);
+      block.write();
+      metarootFile.force();
+
+      // Release the token for the previously committed phase.
+      synchronized (committedPhaseLock) {
+        if (committedPhaseToken != null) committedPhaseToken.release();
+        committedPhaseToken = recordingPhaseToken;
+        committedGraphNodes = currentPhase.graphNodes;
+      }
+      recordingPhaseToken = null;
+    } catch (IOException ex) {
+      logger.fatal("I/O error while performing commit.", ex);
+      throw new SimpleXAResourceException("I/O error while performing commit.", ex);
+    } finally {
+      prepared = false;
+      if (recordingPhaseToken != null) {
+        // Something went wrong! An exception is on its way out
+        recordingPhaseToken.release();
+        recordingPhaseToken = null;
+
+        logger.error("Commit failed.  Calling close().");
+        try {
+          close();
+        } catch (Throwable t) {
+          logger.error("Exception on forced close()", t);
+        }
+      }
+    }
+  }
+
+
+  /**
+   * Read the state from the metaroot file and use it to set up this object
+   * @return An array of 0, 1, or 2 valid phases that can be selected as the last committed phase.
+   * @throws SimpleXAResourceException Due to an IO error, or a data error in the metaroot file.
+   */
+  public synchronized int[] recover() throws SimpleXAResourceException {
+    if (logger.isDebugEnabled()) logger.debug("Recover " + this.getClass() + ":" + System.identityHashCode(this));
+    if (currentPhase != null) return new int[0];
+    if (wrongFileVersion) throw new SimpleXAResourceException("Wrong metaroot file version.");
+
+    try {
+      openMetarootFile(false);
+    } catch (IOException ex) {
+      throw new SimpleXAResourceException("I/O error", ex);
+    }
+
+    // Count the number of valid phases.
+    int phaseCount = 0;
+    if (metarootBlocks[0].getInt(IDX_VALID) != 0) ++phaseCount;
+    if (metarootBlocks[1].getInt(IDX_VALID) != 0) ++phaseCount;
+
+    // Read the phase numbers.
+    int[] phaseNumbers = new int[phaseCount];
+    int index = 0;
+    if (metarootBlocks[0].getInt(IDX_VALID) != 0) phaseNumbers[index++] = metarootBlocks[0].getInt(IDX_PHASE_NUMBER);
+    if (metarootBlocks[1].getInt(IDX_VALID) != 0) phaseNumbers[index++] = metarootBlocks[1].getInt(IDX_PHASE_NUMBER);
+    return phaseNumbers;
+  }
+
+
+  /**
+   * Choose a phase from the metaroot file to use
+   * @param phaseNumber The number of the phase to select. This must be one of the valid
+   *        phases present in the metaroot file.
+   * @throws IOException Due to an error on the filesystem
+   * @throws SimpleXAResourceException If the file structures are incorrect.
+   */
+  public synchronized void selectPhase(int phaseNumber) throws IOException, SimpleXAResourceException {
+    if (logger.isDebugEnabled()) {
+      logger.debug("SelectPhase(" + phaseNumber + ") " + this.getClass() + ":" + System.identityHashCode(this));
+    }
+    if (currentPhase != null) throw new SimpleXAResourceException("selectPhase() called on initialized Graph.");
+    if (metarootFile == null) throw new SimpleXAResourceException("Graph metaroot file is not open.");
+
+    // Locate the metaroot corresponding to the given phase number.
+    if (
+        metarootBlocks[0].getInt(IDX_VALID) != 0 &&
+        metarootBlocks[0].getInt(IDX_PHASE_NUMBER) == phaseNumber
+    ) {
+      phaseIndex = 0;
+      // A new phase will be saved in the other metaroot.
+    } else if (
+        metarootBlocks[1].getInt(IDX_VALID) != 0 &&
+        metarootBlocks[1].getInt(IDX_PHASE_NUMBER) == phaseNumber
+    ) {
+      phaseIndex = 1;
+      // A new phase will be saved in the other metaroot.
+    } else {
+      throw new SimpleXAResourceException("Invalid phase number: " + phaseNumber);
+    }
+
+    // Load a duplicate of the selected phase.  The duplicate will have a
+    // phase number which is one higher than the original phase.
+    try {
+      synchronized (committedPhaseLock) {
+        committedPhaseToken = new Phase(metarootBlocks[phaseIndex], HEADER_SIZE_LONGS).use();
+      }
+      this.phaseNumber = phaseNumber;
+    } catch (IllegalStateException ex) {
+      throw new SimpleXAResourceException("Cannot construct initial phase.", ex);
+    }
+    new Phase();
+
+    // Invalidate the on-disk metaroot that the new phase will be saved to.
+    Block block = metarootBlocks[1 - phaseIndex];
+    block.putInt(IDX_VALID, 0);
+    block.write();
+    metarootFile.force();
+  }
+
+
+  /**
+   * Return to the data structure state from the beginning of the transaction.
+   * @throws SimpleXAResourceException Due to an IO error.
+   */
+  public synchronized void rollback() throws SimpleXAResourceException {
+    if (logger.isDebugEnabled()) logger.debug("Rollback " + this.getClass() + ":" + System.identityHashCode(this));
+    checkInitialized();
+    try {
+      if (prepared) {
+        // Restore phaseIndex and phaseNumber to their previous values.
+        phaseIndex = 1 - phaseIndex;
+        --phaseNumber;
+        recordingPhaseToken = null;
+        prepared = false;
+
+        // Invalidate the metaroot of the other phase.
+        Block block = metarootBlocks[1 - phaseIndex];
+        block.putInt(IDX_VALID, 0);
+        block.write();
+        metarootFile.force();
+      }
+    } catch (IOException ex) {
+      throw new SimpleXAResourceException("I/O error while performing rollback (invalidating metaroot)", ex);
+    } finally {
+      try {
+        new Phase(committedPhaseToken.getPhase());
+      } catch (IOException ex) {
+        throw new SimpleXAResourceException("I/O error while performing rollback (new committed phase)", ex);
+      }
+    }
+  }
+
+
+  /**
+   * Get a string representation of the current state of the graph.
+   * @return A string representing the current state
+   */
+  public synchronized String toString() {
+    if (currentPhase == null) return "Uninitialized Graph.";
+    return currentPhase.toString();
+  }
+
+
+  /**
+   * Attempt to cleanly close all mapped files.
+   */
+  public synchronized void unmap() {
+    if (committedPhaseToken != null) {
+      recordingPhaseToken = null;
+      prepared = false;
+
+      try {
+        new Phase(committedPhaseToken.getPhase());
+      } catch (Throwable t) {
+        logger.warn("Exception while rolling back in unmap()", t);
+      }
+      currentPhase = null;
+
+      synchronized (committedPhaseLock) {
+        committedPhaseToken.release();
+        committedPhaseToken = null;
+      }
+    }
+
+    if (tripleAVLFiles != null) {
+      for (int i = 0; i < NR_INDEXES; ++i) {
+        if (tripleAVLFiles[i] != null) tripleAVLFiles[i].unmap();
+      }
+    }
+
+    if (metarootFile != null) {
+      if (metarootBlocks[0] != null) metarootBlocks[0] = null;
+      if (metarootBlocks[1] != null) metarootBlocks[1] = null;
+      metarootFile.unmap();
+    }
+  }
+
+
+  /**
+   * Check that the data structures are valid
+   * @return The number of triples in the database
+   */
+  synchronized long checkIntegrity() {
+    checkInitialized();
+    return currentPhase.checkIntegrity();
+  }
+
+
+  /**
+   * Open the metaroot file and read in the contents
+   * @param clear If <code>true</code> then the file will be reset to empty.
+   * @throws IOException Due to a filesystem error.
+   * @throws SimpleXAResourceException If the data structures are inconsistent.
+   */
+  private void openMetarootFile(boolean clear) throws IOException, SimpleXAResourceException {
+    if (metarootFile == null) {
+      metarootFile = AbstractBlockFile.openBlockFile(fileName + ".g", METAROOT_SIZE * Constants.SIZEOF_LONG, BlockFile.IOType.EXPLICIT);
+
+      long nrBlocks = metarootFile.getNrBlocks();
+      if (nrBlocks != NR_METAROOTS) {
+        if (nrBlocks > 0) {
+          logger.info("Graph metaroot file for triple store \"" + fileName + "\" has invalid number of blocks: " + nrBlocks);
+          if (nrBlocks < NR_METAROOTS) {
+            clear = true;
+            metarootFile.clear();
+          }
+        } else {
+          // Perform initialization on empty file.
+          clear = true;
+        }
+        metarootFile.setNrBlocks(NR_METAROOTS);
+      }
+
+      metarootBlocks[0] = metarootFile.readBlock(0);
+      metarootBlocks[1] = metarootFile.readBlock(1);
+    }
+
+    if (clear) {
+      // Invalidate the metaroots on disk.
+      metarootBlocks[0].putInt(IDX_MAGIC, FILE_MAGIC);
+      metarootBlocks[0].putInt(IDX_VERSION, FILE_VERSION);
+      metarootBlocks[0].putInt(IDX_VALID, 0);
+      metarootBlocks[0].write();
+      metarootBlocks[1].putInt(IDX_MAGIC, 0);
+      metarootBlocks[1].putInt(IDX_VERSION, 0);
+      metarootBlocks[1].putInt(IDX_VALID, 0);
+      metarootBlocks[1].write();
+      metarootFile.force();
+    }
+  }
+
+
+  /**
+   * Tests that the current object has been initialized.
+   * @throws IllegalStateException Throws this unchecked exception if the object is not initialized.
+   */
+  private void checkInitialized() {
+    if (currentPhase == null) throw new IllegalStateException("No current phase.  Graph has not been initialized or has been closed.");
+  }
+
+
+  final class ReadOnlyGraph implements XAStatementStore {
+
+    private Phase phase = null;
+
+    private Phase.Token token = null;
+
+
+    /**
+     * Create a read-only graph attached to the current outer database
+     */
+    ReadOnlyGraph() {
+      synchronized (committedPhaseLock) {
+        if (committedPhaseToken == null) {
+          throw new IllegalStateException("Cannot create read only view of uninitialized Graph.");
+        }
+      }
+    }
+
+
+    public synchronized boolean isEmpty() {
+      return phase.isEmpty();
+    }
+
+
+    /**
+     * Returns a count of the number of triples in the graph
+     * @return a count of the number of triples in the graph
+     */
+    public synchronized long getNrTriples() {
+      return phase.getNrTriples();
+    }
+
+
+    /**
+     * Adds a triple to the graph.
+     * @param node0 The 0 node of the triple.
+     * @param node1 The 1 node of the triple.
+     * @param node2 The 2 node of the triple.
+     * @param node3 The 3 node of the triple.
+     */
+    public void addTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
+      throw new UnsupportedOperationException("Trying to modify a read-only graph.");
+    }
+
+
+    /**
+     * Removes all triples matching the given specification.
+     * @param node0 the value for the first element of the triples
+     * @param node1 the value for the second element of the triples
+     * @param node2 the value for the third element of the triples
+     * @param node3 the value for the fourth element of the triples
+     */
+    public void removeTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+      throw new UnsupportedOperationException("Trying to modify a read-only graph.");
+    }
+
+
+    /**
+     * Finds triples matching the given specification.
+     * @param node0 The 0 node of the triple to find.
+     * @param node1 The 1 node of the triple to find.
+     * @param node2 The 2 node of the triple to find.
+     * @param node3 The 3 node of the triple to find.
+     * @return A StoreTuples which contains the triples which match the search.
+     */
+    public synchronized StoreTuples findTuples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+      return phase.findTuples(node0, node1, node2, node3);
+    }
+
+    /**
+     * Finds triples matching the given specification.
+     * @param mask The mask of the index to use. This is only allowable for 3 variables
+     *             and a given graph.
+     * @param node0 The 0 node of the triple to find.
+     * @param node1 The 1 node of the triple to find.
+     * @param node2 The 2 node of the triple to find.
+     * @param node3 The 3 node of the triple to find.
+     * @return A StoreTuples which contains the triples which match the search.
+     * @throws StatementStoreException A structural or IO error
+     */
+    public synchronized StoreTuples findTuples(int mask, long node0, long node1, long node2, long node3) throws StatementStoreException {
+      if (!checkMask(mask, node0, node1, node2, node3)) throw new StatementStoreException("Bad explicit index selection for given node pattern.");
+      return phase.findTuples(mask, node0, node1, node2, node3);
+    }
+
+
+    /**
+     * Returns a StoreTuples which contains all triples in the store.  The
+     * parameters provide a hint about how the StoreTuples will be used.  This
+     * information is used to select the index from which the StoreTuples will
+     * be obtained.
+     * @param node0Bound specifies that node0 will be bound
+     * @param node1Bound specifies that node1 will be bound
+     * @param node2Bound specifies that node2 will be bound
+     * @return the {@link StoreTuples}
+     * @throws StatementStoreException if something exceptional happens
+     */
+    public synchronized StoreTuples findTuples(boolean node0Bound, boolean node1Bound, boolean node2Bound, boolean node3Bound) throws StatementStoreException {
+      return phase.findTuples(node0Bound, node1Bound, node2Bound, node3Bound);
+    }
+
+
+    public synchronized boolean existsTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+      return phase.existsTriples(node0, node1, node2, node3);
+    }
+
+
+    public XAStatementStore newReadOnlyStatementStore() {
+      throw new UnsupportedOperationException();
+    }
+
+
+    public XAStatementStore newWritableStatementStore() {
+      throw new UnsupportedOperationException();
+    }
+
+
+    public void close() {
+      throw new UnsupportedOperationException("Trying to close a read-only graph.");
+    }
+
+
+    public void delete() {
+      throw new UnsupportedOperationException("Trying to delete a read-only graph.");
+    }
+
+
+    /**
+     * Release the phase.
+     */
+    public synchronized void release() {
+      if (logger.isDebugEnabled()) logger.debug("Releasing " + this.getClass() + ":" + System.identityHashCode(this));
+      try {
+        if (token != null) token.release();
+      } finally {
+        phase = null;
+        token = null;
+      }
+    }
+
+
+    public synchronized void refresh() {
+      if (logger.isDebugEnabled()) logger.debug("Refreshing " + this.getClass() + ":" + System.identityHashCode(this));
+
+      synchronized (committedPhaseLock) {
+        Phase committedPhase = committedPhaseToken.getPhase();
+        if (phase != committedPhase) {
+          if (token != null) token.release();
+          phase = committedPhase;
+          token = phase.use();
+        }
+      }
+    }
+
+    public void addReleaseNodeListener(ReleaseNodeListener l) {
+      throw new UnsupportedOperationException();
+    }
+
+    public void removeReleaseNodeListener(ReleaseNodeListener l) {
+      throw new UnsupportedOperationException();
+    }
+
+    public void prepare() {
+      if (logger.isDebugEnabled()) logger.debug("Preparing " + this.getClass() + ":" + System.identityHashCode(this));
+    }
+
+    public void commit() {
+      if (logger.isDebugEnabled()) logger.debug("Commit " + this.getClass() + ":" + System.identityHashCode(this));
+    }
+
+    public void rollback() {
+      if (logger.isDebugEnabled()) logger.debug("Rollback " + this.getClass() + ":" + System.identityHashCode(this));
+    }
+
+    public void clear() {
+      if (logger.isDebugEnabled()) logger.debug("Clearing " + this.getClass() + ":" + System.identityHashCode(this));
+    }
+
+    public void clear(int phaseNumber) {
+      if (logger.isDebugEnabled()) logger.debug("Clearing (" + phaseNumber + ") " + this.getClass() + ":" + System.identityHashCode(this));
+    }
+
+    public int[] recover() {
+      if (logger.isDebugEnabled()) logger.debug("Recovering " + this.getClass() + ":" + System.identityHashCode(this));
+      throw new UnsupportedOperationException("Attempting to recover ReadOnlyGraph");
+    }
+
+    public void selectPhase(int phaseNumber) {
+      if (logger.isDebugEnabled()) logger.debug("Selecting Phase " + this.getClass() + ":" + System.identityHashCode(this));
+      throw new UnsupportedOperationException("Attempting to selectPhase of ReadOnlyGraph");
+    }
+
+    public int getPhaseNumber() {
+      return phaseNumber;
+    }
+
+
+    /**
+     * Not used on a read-only graph
+     */
+    public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
+      // do nothing
+    }
+  }
+
+
+  /**
+   * This class represents the state of the the database at a particular time. Only the most
+   * recent phase can be written to.
+   */
+  final class Phase implements PersistableMetaRoot {
+
+    /** The size of the data this object stores in the metaroot */
+    final static int RECORD_SIZE = TripleAVLFile.Phase.RECORD_SIZE * NR_INDEXES;
+
+    /** Maintaines parallel structural phases between all of the parallel tree data structures */
+    private TripleAVLFile.Phase[] tripleAVLFilePhases = new TripleAVLFile.Phase[NR_INDEXES];
+
+    /** The list of graphs valid in this phase. */
+    private List<Long> graphNodes = null;
+
+
+    /**
+     * Creates a new phase based on the current state of the database.
+     * This sets the latest phase on the outer statement store.
+     * @throws IOException Error on the filesystem.
+     */
+    Phase() throws IOException {
+      for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i] = tripleAVLFiles[i].new Phase();
+      currentPhase = this;
+      dirty = true;
+      try {
+        graphNodes = committedGraphNodes == null ? scanForGraphs() : new ArrayList<Long>(committedGraphNodes);
+      } catch (StatementStoreException e) {
+        throw new IOException("Unable to get metadata for phase: " + e.getMessage());
+      }
+    }
+
+
+    /**
+     * A copy constructor for duplicating a phase structure. This sets the latest phase
+     * on the outer statement store.
+     * @throws IOException Error on the filesystem.
+     */
+    Phase(Phase p) throws IOException {
+      assert p != null;
+
+      for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i] = tripleAVLFiles[i].new Phase(p.tripleAVLFilePhases[i]);
+      currentPhase = this;
+      dirty = true;
+      graphNodes = new ArrayList<Long>(p.graphNodes);
+    }
+
+
+    /**
+     * Create a phase based on information found in a buffer that came from a metaroot
+     * @param b The buffer containing the phase information.
+     * @param offset The start of the phase information in the buffer
+     * @throws IOException A filesystem error occurred while accessing the buffer.
+     */
+    Phase(Block b, int offset) throws IOException {
+      for (int i = 0; i < NR_INDEXES; ++i) {
+        tripleAVLFilePhases[i] = tripleAVLFiles[i].new Phase(b, offset);
+        offset += TripleAVLFile.Phase.RECORD_SIZE;
+      }
+      currentPhase = this;
+      dirty = false;
+      try {
+        graphNodes = scanForGraphs();
+      } catch (StatementStoreException sse) {
+        throw new IOException("Error accessing graph data during initialization");
+      }
+    }
+
+
+    /**
+     * Writes this PersistableMetaRoot to the specified Block. The ints are
+     * written at the specified offset.
+     * @param b The metaroot Block to write this object to.
+     * @param offset The start within the buffer of where the phase information should be written to.
+     */
+    public void writeToBlock(Block b, int offset) {
+      for (int i = 0; i < NR_INDEXES; ++i) {
+        tripleAVLFilePhases[i].writeToBlock(b, offset);
+        offset += TripleAVLFile.Phase.RECORD_SIZE;
+      }
+    }
+
+
+    /**
+     * Create a string representation of the current phase.
+     * @return A string representing this phase
+     */
+    public String toString() {
+      StringBuffer sb = new StringBuffer();
+      for (int i = 0; i < NR_INDEXES; ++i) {
+        StoreTuples ts = tripleAVLFilePhases[i].allTuples();
+        try {
+          sb.append(ts).append('\n');
+        } finally {
+          try {
+            ts.close();
+          } catch (TuplesException ex) {
+            logger.warn("TuplesException while closing Tuples", ex);
+            return ex.toString();
+          }
+        }
+      }
+      return sb.toString();
+    }
+
+
+    /**
+     * Tests if any part of this phase has a reference being kept to it
+     * @return <code>true</code> if any part of this phase is being used.
+     */
+    boolean isInUse() {
+      for (int i = 0; i < NR_INDEXES; ++i) {
+        if (tripleAVLFilePhases[i].isInUse()) return true;
+      }
+      return false;
+    }
+
+
+    /**
+     * Tests if the phase contains any triples
+     * @return <code>true</code> if the phase contains 1 or more triples
+     */
+    boolean isEmpty() {
+      return tripleAVLFilePhases[TI_3012].isEmpty();
+    }
+
+
+    /**
+     * Gets the number of triples in the phase
+     * @return The number of triples in this phase
+     */
+    long getNrTriples() {
+      return tripleAVLFilePhases[TI_3012].getNrTriples();
+    }
+
+
+    /**
+     * Adds a new triple to the graph if it doesn't already exist.
+     * @param node0 the first element of the new triple
+     * @param node1 the second element of the new triple
+     * @param node2 the third element of the new triple
+     * @param node3 the fourth element of the new triple
+     * @throws StatementStoreException An IO or data structure error
+     */
+    void addTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
+      assert node0 >= NodePool.MIN_NODE;
+      assert node1 >= NodePool.MIN_NODE;
+      assert node2 >= NodePool.MIN_NODE;
+      assert node3 >= NodePool.MIN_NODE;
+
+      //if (
+      //  DEBUG && nodePool != null &&
+      //  !nodePool.isValid(node0) && !nodePool.isValid(node1) &&
+      //  !nodePool.isValid(node2) && !nodePool.isValid(node3)
+      //) throw new AssertionError(
+      //  "Attempt to add a triple with an invalid node"
+      //);
+
+      long[] triple = new long[]{node0, node1, node2, node3};
+
+      for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i].asyncAddTriple(triple);
+
+      if (node1 == rdfTypeNode && node2 == graphTypeNode && node3 == systemGraphNode) graphNodes.add(node0);
+    }
+
+
+    /**
+     * Removes the specified triple.
+     * @param node0 the value for the first element of the triple
+     * @param node1 the value for the second element of the triple
+     * @param node2 the value for the third element of the triple
+     * @param node3 the value for the fourth element of the triple
+     * @throws StatementStoreException An IO or structural error
+     */
+    void removeTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
+      if (
+          node0 < NodePool.MIN_NODE ||
+          node1 < NodePool.MIN_NODE ||
+          node2 < NodePool.MIN_NODE ||
+          node3 < NodePool.MIN_NODE
+      ) {
+        throw new StatementStoreException("Attempt to remove a triple with node number out of range: " + node0 + " " + node1 + " " + node2 + " " + node3);
+      }
+
+      try {
+        for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i].removeTriple(node0, node1, node2, node3);
+        // removeTriple listeners can be informed here
+      } catch (IOException e) {
+        throw new StatementStoreException("I/O error", e);
+      }
+      if (node1 == rdfTypeNode && node2 == graphTypeNode && node3 == systemGraphNode) graphNodes.remove(node0);
+    }
+
+
+    /**
+     * Finds triples matching the given specification.
+     * @param variableMask the mask used to indicate the desired index.
+     * @param node0 The 0 node of the triple to find.
+     * @param node1 The 1 node of the triple to find.
+     * @param node2 The 2 node of the triple to find.
+     * @param node3 The 3 node of the triple to find.
+     * @return A StoreTuples containing all the triples which match the search.
+     * @throws StatementStoreException An IO or structural error
+     */
+    StoreTuples findTuples(int variableMask, long node0, long node1, long node2, long node3) throws StatementStoreException {
+      if (
+          node0 < NodePool.NONE ||
+          node1 < NodePool.NONE ||
+          node2 < NodePool.NONE ||
+          node3 < NodePool.NONE
+      ) {
+        // There is at least one query node.  Return an empty StoreTuples.
+        return TuplesOperations.empty();
+      }
+
+      if (0 == (variableMask & MASK3)) throw new StatementStoreException("This version of find is for re-ordering graphs, based on a given mask.");
+      try {
+        switch (variableMask) {
+          case MASK3:
+            return tripleAVLFilePhases[TI_3012].findTuples(node3);
+          case MASK0 | MASK3:
+            return tripleAVLFilePhases[TI_3012].findTuples(node3);
+          case MASK1 | MASK3:
+            return tripleAVLFilePhases[TI_3120].findTuples(node3);
+          case MASK0 | MASK1 | MASK3:
+            return tripleAVLFilePhases[TI_3012].findTuples(node3);
+          case MASK2 | MASK3:
+            return tripleAVLFilePhases[TI_3201].findTuples(node3);
+          case MASK0 | MASK2 | MASK3:
+            return tripleAVLFilePhases[TI_3201].findTuples(node3);
+          case MASK1 | MASK2 | MASK3:
+            return tripleAVLFilePhases[TI_3120].findTuples(node3);
+          case MASK0 | MASK1 | MASK2 | MASK3:
+            return tripleAVLFilePhases[TI_3012].findTuples(node3);
+          default:
+            throw new AssertionError();
+        }
+      } catch (IOException ex) {
+        throw new StatementStoreException("I/O error", ex);
+      }
+    }
+
+
+    /**
+     * Finds triples matching the given specification.
+     * @param node0 The 0 node of the triple to find.
+     * @param node1 The 1 node of the triple to find.
+     * @param node2 The 2 node of the triple to find.
+     * @param node3 The 3 node of the triple to find.
+     * @return A StoreTuples containing all the triples which match the search.
+     * @throws StatementStoreException An IO or structural error
+     */
+    StoreTuples findTuples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+      if (
+          node0 < NodePool.NONE ||
+          node1 < NodePool.NONE ||
+          node2 < NodePool.NONE ||
+          node3 < NodePool.NONE
+      ) {
+        // There is at least one query node.  Return an empty StoreTuples.
+        return TuplesOperations.empty();
+      }
+
+      int variableMask =
+        (node0 != NONE ? MASK0 : 0) |
+        (node1 != NONE ? MASK1 : 0) |
+        (node2 != NONE ? MASK2 : 0) |
+        (node3 != NONE ? MASK3 : 0);
+
+      if (node3 == NONE && variableMask != 0) {
+        return joinGraphedTuples(variableMask, node0, node1, node2);
+      }
+
+
+      try {
+        switch (variableMask) {
+          case 0:
+            return tripleAVLFilePhases[TI_3012].allTuples();
+          case MASK3:
+            return tripleAVLFilePhases[TI_3012].findTuples(node3);
+          case MASK0 | MASK3:
+            return tripleAVLFilePhases[TI_3012].findTuples(node3, node0);
+          case MASK1 | MASK3:
+            return tripleAVLFilePhases[TI_3120].findTuples(node3, node1);
+          case MASK0 | MASK1 | MASK3:
+            return tripleAVLFilePhases[TI_3012].findTuples(node3, node0, node1);
+          case MASK2 | MASK3:
+            return tripleAVLFilePhases[TI_3201].findTuples(node3, node2);
+          case MASK0 | MASK2 | MASK3:
+            return tripleAVLFilePhases[TI_3201].findTuples(node3, node2, node0);
+          case MASK1 | MASK2 | MASK3:
+            return tripleAVLFilePhases[TI_3120].findTuples(node3, node1, node2);
+          case MASK0 | MASK1 | MASK2 | MASK3:
+            if (tripleAVLFilePhases[TI_3012].existsTriple(node3, node0, node1, node2)) {
+              return TuplesOperations.unconstrained();
+            }
+            return TuplesOperations.empty();
+          default:
+            throw new AssertionError("Search structure incorrectly calculated");
+        }
+      } catch (IOException ex) {
+        throw new StatementStoreException("I/O error", ex);
+      }
+    }
+
+
+    StoreTuples findTuples(boolean node0Bound, boolean node1Bound, boolean node2Bound, boolean node3Bound) throws StatementStoreException {
+      // The variable mask does not need MASK3, as this has been taken into account in selectIndex[]
+      int variableMask =
+          (node0Bound ? MASK0 : 0) |
+          (node1Bound ? MASK1 : 0) |
+          (node2Bound ? MASK2 : 0);
+      if (variableMask == 0 || node3Bound) {
+        return tripleAVLFilePhases[selectIndex[variableMask]].allTuples();
+      } else {
+        return joinGraphedTuples(variableMask);
+      }
+    }
+
+
+    /**
+     * Iterates over all graphs, finding requested tuples, and joining all the results together into a single tuples.
+     * @param variableMask Pre-calculated from the bound node parameters.
+     * @param node0 The bound value for node0, or < 0 if not bound.
+     * @param node1 The bound value for node1, or < 0 if not bound.
+     * @param node2 The bound value for node2, or < 0 if not bound.
+     * @return A StoreTuples with all the intermediate tuples appended.
+     * @throws StatementStoreException On an error accessing the store.
+     */
+    StoreTuples joinGraphedTuples(int variableMask, long node0, long node1, long node2) throws StatementStoreException {
+      try {
+        assert (variableMask & MASK3) == 0 : "Must not be asking to join on multiple graphs unless graph is variable.";
+
+        // get the graphNodes if not already configured
+        if (graphNodes.isEmpty()) throw new IllegalStateException("Unable to query for variable graphs until graphs are initialized");
+
+        if (variableMask == (MASK0 | MASK1 | MASK2)) {
+          LiteralGraphTuples result = new LiteralGraphTuples(false);
+          for (long graphNode: graphNodes) {
+            if (tripleAVLFilePhases[TI_3012].existsTriple(node0, node1, node2, graphNode)) {
+              result.appendTuple(new long[] { graphNode });
+            }
+          }
+          return result;
+        }
+
+        ArrayList<StoreTuples> graphedTuples = new ArrayList<StoreTuples>();
+        for (long graphNode: graphNodes) {
+          StoreTuples partialResult = null;
+          switch (variableMask) {
+            case 0:
+              partialResult = tripleAVLFilePhases[TI_3012].findTuplesForMeta(graphNode);
+              break;
+            case MASK0:
+              partialResult = tripleAVLFilePhases[TI_3012].findTuplesForMeta(graphNode, node0);
+              break;
+            case MASK1:
+              partialResult = tripleAVLFilePhases[TI_3120].findTuplesForMeta(graphNode, node1);
+              break;
+            case MASK0 | MASK1:
+              partialResult = tripleAVLFilePhases[TI_3012].findTuplesForMeta(graphNode, node0, node1);
+              break;
+            case MASK2:
+              partialResult = tripleAVLFilePhases[TI_3201].findTuplesForMeta(graphNode, node2);
+              break;
+            case MASK0 | MASK2:
+              partialResult = tripleAVLFilePhases[TI_3201].findTuplesForMeta(graphNode, node2, node0);
+              break;
+            case MASK1 | MASK2:
+              partialResult = tripleAVLFilePhases[TI_3120].findTuplesForMeta(graphNode, node1, node2);
+              break;
+            default:
+              throw new AssertionError("Search structure incorrectly calculated");
+          }
+          graphedTuples.add(partialResult);
+        }
+        return TuplesOperations.appendCompatible(graphedTuples);
+      } catch (TuplesException te) {
+        throw new StatementStoreException("Error accessing Tuples", te);
+      } catch (IOException ex) {
+        throw new StatementStoreException("I/O error", ex);
+      }
+    }
+
+
+    /**
+     * Iterates over all graphs, getting all tuples in the requested order,
+     * and joining all the results together into a single tuples.
+     * @param variableMask Determines the required ordering of the data.
+     * @return A StoreTuples with all the intermediate tuples appended.
+     * @throws StatementStoreException On an error accessing the store.
+     */
+    StoreTuples joinGraphedTuples(int variableMask) throws StatementStoreException {
+      try {
+        assert (variableMask & MASK3) == 0 : "Must not be asking to join on multiple graphs unless graph is variable.";
+
+        // get the graphNodes if not already configured
+        if (graphNodes.isEmpty()) throw new IllegalStateException("Unable to query for variable graphs until graphs are initialized");
+
+        ArrayList<StoreTuples> graphedTuples = new ArrayList<StoreTuples>();
+        for (long graphNode: graphNodes) {
+          int phaseIndex;
+          switch (variableMask) {
+            case 0:
+            case MASK0:
+            case MASK0 | MASK1:
+            case MASK0 | MASK1 | MASK2:
+              phaseIndex = TI_3012;
+              break;
+            case MASK1:
+            case MASK1 | MASK2:
+              phaseIndex = TI_3120;
+              break;
+            case MASK2:
+            case MASK0 | MASK2:
+              phaseIndex = TI_3201;
+              break;
+            default:
+              throw new AssertionError("Search structure incorrectly calculated");
+          }
+          StoreTuples partialResult = tripleAVLFilePhases[phaseIndex].findTuplesForMeta(graphNode);
+          graphedTuples.add(partialResult);
+        }
+        return TuplesOperations.appendCompatible(graphedTuples);
+      } catch (TuplesException te) {
+        throw new StatementStoreException("Error accessing Tuples", te);
+      } catch (IOException ex) {
+        throw new StatementStoreException("I/O error", ex);
+      }
+    }
+
+
+    /**
+     * Test is there exist triples according to a given pattern
+     * @param node0 A subject gNode, or NONE
+     * @param node1 A predicate gNode, or NONE
+     * @param node2 A object gNode, or NONE
+     * @param node3 A subject gNode. May not be NONE
+     * @return <code>true</code> if there exist triples that match the pattern
+     * @throws StatementStoreException A structural or IO exception
+     */
+    boolean existsTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+      if (node3 == NONE) throw new IllegalStateException("Graph must be specified");
+
+      if (
+          node0 < NodePool.NONE ||
+          node1 < NodePool.NONE ||
+          node2 < NodePool.NONE ||
+          node3 < NodePool.NONE
+      ) {
+        // There is at least one query node (comes from the query, but not in the data pool).
+        // Return an empty StoreTuples.
+        return false;
+      }
+
+      int variableMask =
+          (node0 != NONE ? MASK0 : 0) |
+          (node1 != NONE ? MASK1 : 0) |
+          (node2 != NONE ? MASK2 : 0) |
+          MASK3;
+
+      try {
+        switch (variableMask) {
+          case MASK3:
+            return tripleAVLFilePhases[TI_3012].existsTriples(node3);
+          case MASK0 | MASK3:
+            return tripleAVLFilePhases[TI_3012].existsTriples(node3, node0);
+          case MASK1 | MASK3:
+            return tripleAVLFilePhases[TI_3120].existsTriples(node3, node1);
+          case MASK0 | MASK1 | MASK3:
+            return tripleAVLFilePhases[TI_3012].existsTriples(node3, node0, node1);
+          case MASK2 | MASK3:
+            return tripleAVLFilePhases[TI_3201].existsTriples(node3, node2);
+          case MASK0 | MASK2 | MASK3:
+            return tripleAVLFilePhases[TI_3201].existsTriples(node3, node2, node0);
+          case MASK1 | MASK2 | MASK3:
+            return tripleAVLFilePhases[TI_3120].existsTriples(node3, node1, node2);
+          case MASK0 | MASK1 | MASK2 | MASK3:
+            return tripleAVLFilePhases[TI_3012].existsTriple(node3, node0, node1, node2);
+          default:
+            throw new AssertionError("Search structure incorrectly calculated");
+        }
+      } catch (IOException ex) {
+        throw new StatementStoreException("I/O error", ex);
+      }
+    }
+
+
+    /**
+     * Check that each index contains the same number of triples
+     * @throws AssertionError if the indexes contain a differing number of triples
+     */ 
+    long checkIntegrity() {
+      long nrTriples[] = new long[NR_INDEXES];
+
+      for (int i = 0; i < NR_INDEXES; ++i) nrTriples[i] = tripleAVLFilePhases[i].checkIntegrity();
+
+      for (int i = 1; i < NR_INDEXES; ++i) {
+        if (nrTriples[0] != nrTriples[i]) {
+          StringBuffer sb = new StringBuffer("tripleAVLFiles disagree on the number of triples:");
+          for (int j = 0; j < NR_INDEXES; ++j) sb.append(' ').append(nrTriples[j]);
+          throw new AssertionError(sb.toString());
+        }
+      }
+
+      return nrTriples[0];
+    }
+
+
+    /**
+     * Ask the system for all the known graphs.
+     * @return All the known graph nodes.
+     */
+    List<Long> scanForGraphs() throws StatementStoreException, IOException {
+      List<Long> nodeList = new ArrayList<Long>();
+
+      if (systemGraphNode == NONE || rdfTypeNode == NONE || graphTypeNode == NONE) return nodeList;
+
+      StoreTuples graphTuples = tripleAVLFilePhases[TI_3120].findTuples(systemGraphNode, rdfTypeNode, graphTypeNode);
+      assert graphTuples.getNumberOfVariables() == 1;
+
+      try {
+        graphTuples.beforeFirst();
+        while (graphTuples.next()) nodeList.add(graphTuples.getColumnValue(0));
+      } catch (TuplesException e) {
+        throw new StatementStoreException("Unable to construct a result containing all graphs.", e);
+      }
+
+      return nodeList;
+    }
+
+
+    /**
+     * Increment the reference count on this object.
+     * @return A new token representing the reference.
+     */
+    Token use() {
+      return new Token();
+    }
+
+
+    /**
+     * A token to reference the phase, incrementing the reference count from the perpective
+     * of the garbage collector.
+     */
+    final class Token {
+
+      /** A list of tokens from the underlying indexes */
+      private TripleAVLFile.Phase.Token[] tripleAVLFileTokens = new TripleAVLFile.Phase.Token[NR_INDEXES];
+
+      /** The phase being referenced */
+      private Phase phase = Phase.this;
+
+
+      /**
+       * Creates a token. This creates tokens for the underlying objects as well.
+       */
+      Token() {
+        for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFileTokens[i] = tripleAVLFilePhases[i].use();
+      }
+
+
+      /**
+       * Get the phase that this token represents.
+       * @return The phase referenced by this token.
+       */
+      public Phase getPhase() {
+        assert tripleAVLFileTokens != null : "Invalid Token";
+        return phase;
+      }
+
+
+      /**
+       * Reduce the reference count on the referenced phase by releasing this token.
+       * The token may not be used after being released.
+       */
+      public void release() {
+        assert tripleAVLFileTokens != null : "Invalid Token";
+        for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFileTokens[i].release();
+        tripleAVLFileTokens = null;
+        phase = null;
+      }
+
+    }
+
+  }
+
+
+  /**
+   * @see org.mulgara.store.xa.XAStatementStore#initializeSystemNodes(long, long, long)
+   * Set the various system graph nodes. These may only be set once, but will allow duplicate calls if the values are the same.
+   * @param systemGraphNode The new system graph node.
+   * @param rdfTypeNode The node for <rdf:graph>.
+   * @param systemGraphTypeNode The node for the system graph type.
+   */
+  public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
+    if (this.systemGraphNode != NONE && systemGraphNode != this.systemGraphNode) {
+      throw new IllegalStateException("Cannot set system graph again. Was: " + this.systemGraphNode + ", now: " + systemGraphNode);
+    }
+    if (systemGraphNode < 0) throw new IllegalArgumentException("Attempt to set invalid system graph node");
+    this.systemGraphNode = systemGraphNode;
+
+    if (this.rdfTypeNode != NONE && rdfTypeNode != this.rdfTypeNode) {
+      throw new IllegalStateException("Cannot set the rdf:type node again. Was: " + this.rdfTypeNode + ", now: " + rdfTypeNode);
+    }
+    if (rdfTypeNode < 0) throw new IllegalArgumentException("Attempt to set invalid rdf:type node");
+    this.rdfTypeNode = rdfTypeNode;
+
+    if (this.graphTypeNode != NONE && systemGraphTypeNode != this.graphTypeNode) {
+      throw new IllegalStateException("Cannot set graph type again. Was: " + this.graphTypeNode + ", now: " + systemGraphTypeNode);
+    }
+    if (systemGraphTypeNode < 0) throw new IllegalArgumentException("Attempt to set invalid graph type node");
+    this.graphTypeNode = systemGraphTypeNode;
+  }
+
+}

Deleted: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java
===================================================================
--- branches/xa11/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,166 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is the Kowari Metadata Store.
- *
- * The Initial Developer of the Original Code is Plugged In Software Pty
- * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
- * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
- * Plugged In Software Pty Ltd. All Rights Reserved.
- *
- * Contributor(s): N/A.
- *
- * [NOTE: The text of this Exhibit A may differ slightly from the text
- * of the notices in the Source Code files of the Original Code. You
- * should use the text of this Exhibit A rather than the text found in the
- * Original Code Source Code for Your Modifications.]
- *
- */
-package org.mulgara.store.statement.xa11;
-
-// Java 2 standard packages
-import java.io.*;
-
-// JUnit
-import junit.framework.*;
-
-// log4j
-import org.apache.log4j.*;
-
-// locally written packages
-import org.mulgara.store.statement.*;
-import org.mulgara.store.tuples.TestTuples;
-import org.mulgara.util.*;
-
-
-/**
- * Test case for {@link XA11StatementStoreImpl}.
- *
- * @author <a href="http://staff.pisoftware.com/david">David Makepeace</a>
- * @author <a href="http://staff.pisoftware.com/pag">Paul Gearon</a>
- * @copyright &copy;2001-2004 <a href="http://www.pisoftware.com/">Plugged In Software Pty Ltd</a>
- * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
- */
-public class XA11StatementStoreImplUnitTest extends StatementStoreAbstractUnitTest {
-
-  /** Logger. */
-  @SuppressWarnings("unused")
-  private final static Logger logger = Logger.getLogger(XA11StatementStoreImplUnitTest.class);
-
-  /**
-   * start of filenames to build the graph with.
-   */
-  private final static String DBFILENAME = "graphtest";
-
-  /**
-   * Description of the Field
-   */
-  private XA11StatementStoreImpl xaStore;
-
-
-  /**
-   * Named constructor.
-   *
-   * @param name The name of the test.
-   */
-  public XA11StatementStoreImplUnitTest(String name) {
-    super(name);
-  }
-
-
-  /**
-   * Hook for test runner to obtain a test suite from.
-   *
-   * @return The test suite to run.
-   */
-  public static Test suite() {
-    return new TestSuite(XA11StatementStoreImplUnitTest.class);
-    //TestSuite suite = new TestSuite();
-    //suite.addTest(new GraphImplTest("testRemoveTriples"));
-    //suite.addTest(new GraphImplTest("testFindTriplesByNode0"));
-    //suite.addTest(new GraphImplTest("testFindTriplesByNode1"));
-    //suite.addTest(new GraphImplTest("testFindTriplesByNode2"));
-    //suite.addTest(new GraphImplTest("testFindTriplesByNode01"));
-    //suite.addTest(new GraphImplTest("testFindTriplesByNode02"));
-    //suite.addTest(new GraphImplTest("testFindTriplesByNode12"));
-    //return suite;
-  }
-
-
-  /**
-   * Default test runner.
-   *
-   * @param args The command line arguments
-   */
-  public static void main(String[] args) {
-
-    junit.textui.TestRunner.run(suite());
-  }
-
-
-  /**
-   * A method to call for each graph before running tests on it.
-   *
-   * @throws Exception EXCEPTION TO DO
-   */
-  protected void setUp() throws Exception {
-    boolean exceptionOccurred = true;
-    try {
-      // create the graph object, using a new file
-      store = new XA11StatementStoreImpl(
-          TempDir.getTempDir().getPath() + File.separatorChar + DBFILENAME
-      );
-      xaStore = (XA11StatementStoreImpl) store;
-      xaStore.clear();
-      super.setUp();
-      exceptionOccurred = false;
-    }
-    finally {
-      if (exceptionOccurred) {
-        tearDown();
-      }
-    }
-  }
-
-
-  /**
-   * The teardown method for JUnit
-   *
-   * @throws Exception EXCEPTION TO DO
-   */
-  protected void tearDown() throws Exception {
-    if (xaStore != null) {
-      xaStore.unmap();
-      if (System.getProperty("os.name").startsWith("Win")) {
-        // Need this for Windows or truncate() always fails for mapped files.
-        System.gc();
-        System.runFinalization();
-      }
-    }
-    super.tearDown();
-  }
-
-  /**
-   * Return a dump of all tuples, sorted by the primary index: 3012.
-   * @see org.mulgara.store.statement.StatementStoreAbstractUnitTest#getDump()
-   */
-  protected TestTuples getDump() {
-    TestTuples expected = new TestTuples();
-    add(expected, StatementStore.VARIABLES, new long[] {1, 2, 3, 1});
-    add(expected, StatementStore.VARIABLES, new long[] {1, 2, 4, 2});
-    add(expected, StatementStore.VARIABLES, new long[] {2, 5, 6, 2});
-    add(expected, StatementStore.VARIABLES, new long[] {1, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
-    add(expected, StatementStore.VARIABLES, new long[] {2, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
-    add(expected, StatementStore.VARIABLES, new long[] {SYSTEM_GRAPH, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
-    return expected;
-  }
-
-}

Copied: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java (from rev 1456, branches/xa11/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java)
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java	                        (rev 0)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -0,0 +1,166 @@
+/*
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Original Code is the Kowari Metadata Store.
+ *
+ * The Initial Developer of the Original Code is Plugged In Software Pty
+ * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
+ * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
+ * Plugged In Software Pty Ltd. All Rights Reserved.
+ *
+ * Contributor(s): N/A.
+ *
+ * [NOTE: The text of this Exhibit A may differ slightly from the text
+ * of the notices in the Source Code files of the Original Code. You
+ * should use the text of this Exhibit A rather than the text found in the
+ * Original Code Source Code for Your Modifications.]
+ *
+ */
+package org.mulgara.store.statement.xa11;
+
+// Java 2 standard packages
+import java.io.*;
+
+// JUnit
+import junit.framework.*;
+
+// log4j
+import org.apache.log4j.*;
+
+// locally written packages
+import org.mulgara.store.statement.*;
+import org.mulgara.store.tuples.TestTuples;
+import org.mulgara.util.*;
+
+
+/**
+ * Test case for {@link XA11StatementStoreImpl}.
+ *
+ * @author <a href="http://staff.pisoftware.com/david">David Makepeace</a>
+ * @author <a href="http://staff.pisoftware.com/pag">Paul Gearon</a>
+ * @copyright &copy;2001-2004 <a href="http://www.pisoftware.com/">Plugged In Software Pty Ltd</a>
+ * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
+ */
+public class XA11StatementStoreImplUnitTest extends StatementStoreAbstractUnitTest {
+
+  /** Logger. */
+  @SuppressWarnings("unused")
+  private final static Logger logger = Logger.getLogger(XA11StatementStoreImplUnitTest.class);
+
+  /**
+   * start of filenames to build the graph with.
+   */
+  private final static String DBFILENAME = "graphtest";
+
+  /**
+   * Description of the Field
+   */
+  private XA11StatementStoreImpl xaStore;
+
+
+  /**
+   * Named constructor.
+   *
+   * @param name The name of the test.
+   */
+  public XA11StatementStoreImplUnitTest(String name) {
+    super(name);
+  }
+
+
+  /**
+   * Hook for test runner to obtain a test suite from.
+   *
+   * @return The test suite to run.
+   */
+  public static Test suite() {
+    return new TestSuite(XA11StatementStoreImplUnitTest.class);
+    //TestSuite suite = new TestSuite();
+    //suite.addTest(new GraphImplTest("testRemoveTriples"));
+    //suite.addTest(new GraphImplTest("testFindTriplesByNode0"));
+    //suite.addTest(new GraphImplTest("testFindTriplesByNode1"));
+    //suite.addTest(new GraphImplTest("testFindTriplesByNode2"));
+    //suite.addTest(new GraphImplTest("testFindTriplesByNode01"));
+    //suite.addTest(new GraphImplTest("testFindTriplesByNode02"));
+    //suite.addTest(new GraphImplTest("testFindTriplesByNode12"));
+    //return suite;
+  }
+
+
+  /**
+   * Default test runner.
+   *
+   * @param args The command line arguments
+   */
+  public static void main(String[] args) {
+
+    junit.textui.TestRunner.run(suite());
+  }
+
+
+  /**
+   * A method to call for each graph before running tests on it.
+   *
+   * @throws Exception EXCEPTION TO DO
+   */
+  protected void setUp() throws Exception {
+    boolean exceptionOccurred = true;
+    try {
+      // create the graph object, using a new file
+      store = new XA11StatementStoreImpl(
+          TempDir.getTempDir().getPath() + File.separatorChar + DBFILENAME
+      );
+      xaStore = (XA11StatementStoreImpl) store;
+      xaStore.clear();
+      super.setUp();
+      exceptionOccurred = false;
+    }
+    finally {
+      if (exceptionOccurred) {
+        tearDown();
+      }
+    }
+  }
+
+
+  /**
+   * The teardown method for JUnit
+   *
+   * @throws Exception EXCEPTION TO DO
+   */
+  protected void tearDown() throws Exception {
+    if (xaStore != null) {
+      xaStore.unmap();
+      if (System.getProperty("os.name").startsWith("Win")) {
+        // Need this for Windows or truncate() always fails for mapped files.
+        System.gc();
+        System.runFinalization();
+      }
+    }
+    super.tearDown();
+  }
+
+  /**
+   * Return a dump of all tuples, sorted by the primary index: 3012.
+   * @see org.mulgara.store.statement.StatementStoreAbstractUnitTest#getDump()
+   */
+  protected TestTuples getDump() {
+    TestTuples expected = new TestTuples();
+    add(expected, StatementStore.VARIABLES, new long[] {1, 2, 3, 1});
+    add(expected, StatementStore.VARIABLES, new long[] {1, 2, 4, 2});
+    add(expected, StatementStore.VARIABLES, new long[] {2, 5, 6, 2});
+    add(expected, StatementStore.VARIABLES, new long[] {1, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
+    add(expected, StatementStore.VARIABLES, new long[] {2, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
+    add(expected, StatementStore.VARIABLES, new long[] {SYSTEM_GRAPH, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
+    return expected;
+  }
+
+}

Modified: trunk/src/jar/store-stringpool-memory/java/org/mulgara/store/stringpool/memory/MemoryStringPoolImpl.java
===================================================================
--- trunk/src/jar/store-stringpool-memory/java/org/mulgara/store/stringpool/memory/MemoryStringPoolImpl.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/store-stringpool-memory/java/org/mulgara/store/stringpool/memory/MemoryStringPoolImpl.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -694,7 +694,7 @@
     /**
      * Copied from AbstractTuples
      */
-    public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+    public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
       return null;
     }
   }

Modified: trunk/src/jar/store-stringpool-xa11/java/org/mulgara/store/stringpool/xa11/XA11StringPoolImpl.java
===================================================================
--- trunk/src/jar/store-stringpool-xa11/java/org/mulgara/store/stringpool/xa11/XA11StringPoolImpl.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/store-stringpool-xa11/java/org/mulgara/store/stringpool/xa11/XA11StringPoolImpl.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -2085,7 +2085,7 @@
       /**
        * Copied from AbstractTuples
        */
-      public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+      public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
         return null;
       }
 

Modified: trunk/src/jar/store-xa/java/org/mulgara/store/xa/XAStatementStore.java
===================================================================
--- trunk/src/jar/store-xa/java/org/mulgara/store/xa/XAStatementStore.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/store-xa/java/org/mulgara/store/xa/XAStatementStore.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -84,4 +84,12 @@
    */
   public void delete() throws StatementStoreException;
 
+  /**
+   * Informs the statement store of the metadata it uses for managing data.
+   * @param systemGraphNode The node for the system graph.
+   * @param rdfTypeNode The node representing <rdf:type>.
+   * @param systemGraphTypeNode The node used for the SystemResolver graph type.
+   */
+  public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode);
+
 }

Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/AbstractTuples.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/AbstractTuples.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/AbstractTuples.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -69,6 +69,7 @@
   private final static Variable[] emptyVariables = new Variable[] {};
 
   /** Description of the Field */
+  @SuppressWarnings("unused")
   private final static long[] NO_PREFIX = new long[] {};
 
   /** Description of the Field */
@@ -577,7 +578,7 @@
     variables = variableArray;
   }
 
-  public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+  public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
     return null;
   }
 }

Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/DefinablePrefixAnnotation.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/DefinablePrefixAnnotation.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/DefinablePrefixAnnotation.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -42,10 +42,6 @@
 package org.mulgara.store.tuples;
 
 // JDK packages
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Set;
 
 // Third party packages
@@ -73,5 +69,5 @@
    * 
    * @param boundVars  variables available to be bound in beforeFirst.
    */
-  public void definePrefix(Set boundVars) throws TuplesException;
+  public void definePrefix(Set<Variable> boundVars) throws TuplesException;
 }

Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/LeftJoin.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/LeftJoin.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/LeftJoin.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -51,7 +51,6 @@
  */
 public class LeftJoin extends AbstractTuples implements ContextOwner {
 
-  @SuppressWarnings("unused")
   private static Logger logger = Logger.getLogger(LeftJoin.class.getName());
 
   /** The set of tuples to return all row from. */
@@ -576,7 +575,7 @@
     }
 
     /** @see org.mulgara.store.tuples.Tuples#getAnnotation(java.lang.Class) */
-    public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+    public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
       return wrapped.getAnnotation(annotationClass);
     }
 

Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedAppend.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedAppend.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedAppend.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -75,7 +75,7 @@
   /**
    * The propositions to conjoin.
    */
-  private final Tuples[] operands;
+  protected final Tuples[] operands;
 
   /**
    * The return value of the {@link #beforeFirst} method.
@@ -233,7 +233,7 @@
   }
 
 
-  public List getOperands() {
+  public List<Tuples> getOperands() {
     return Arrays.asList(operands);
   }
 
@@ -351,13 +351,13 @@
   public Variable[] getVariables() {
 
     // Container for our variables
-    ArrayList variablesList = new ArrayList();
+    ArrayList<Variable> variablesList = new ArrayList<Variable>();
 
     // Iterate through the tuples objects and get the variables for each
     for (int index = 0; index < operands.length; index++) {
 
       // Get the array of variables for the current tuples object
-      Variable [] variableArray = operands[index].getVariables();
+      Variable[] variableArray = operands[index].getVariables();
 
       // We need to prevent duplicate variables so iterate through the new array
       // and remove duplicates
@@ -372,17 +372,17 @@
     }
 
     // Convert the list to an array
-    Variable [] newVariables = new Variable [variablesList.size()];
-    newVariables = (Variable []) variablesList.toArray(newVariables);
+    Variable[] newVariables = new Variable[variablesList.size()];
+    newVariables = variablesList.toArray(newVariables);
 
     return newVariables;
   }
 
 
-  public Annotation getAnnotation(Class annotation) {
+  public Annotation getAnnotation(Class<? extends Annotation> annotation) {
     if (annotation.equals(DefinablePrefixAnnotation.class) && prefixDefinable) {
       return new DefinablePrefixAnnotation() {
-        public void definePrefix(Set boundVars) throws TuplesException {
+        public void definePrefix(Set<Variable> boundVars) throws TuplesException {
           for (int i = 0; i < operands.length; i++) {
             DefinablePrefixAnnotation annotation = 
                 (DefinablePrefixAnnotation)operands[i].getAnnotation(DefinablePrefixAnnotation.class);

Copied: trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedStoreAppend.java (from rev 1456, branches/xa11/src/jar/tuples/java/org/mulgara/store/tuples/OrderedStoreAppend.java)
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedStoreAppend.java	                        (rev 0)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedStoreAppend.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2008 Fedora Commons, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mulgara.store.tuples;
+
+import org.mulgara.query.TuplesException;
+
+/**
+ * A class for performing appends between identically structured StoreTuples.
+ *
+ * @created Dec 17, 2008
+ * @author Paul Gearon
+ * @copyright &copy; 2005 <a href="http://www.fedora-commons.org/">Fedora Commons</a>
+ */
+public class OrderedStoreAppend extends OrderedAppend implements StoreTuples {
+
+  /**
+   * @param operands
+   * @throws TuplesException
+   */
+  public OrderedStoreAppend(StoreTuples[] operands) throws TuplesException {
+    super(operands);
+    assert operands.length >= 2 : "Performing join on fewer than 2 operands";
+    assert operandsMatch(operands) : "Operands do not match in OrderedStoreAppend";
+  }
+
+  /**
+   * @see org.mulgara.store.tuples.StoreTuples#getColumnOrder()
+   */
+  public int[] getColumnOrder() {
+    return ((StoreTuples)operands[0]).getColumnOrder();
+  }
+
+  /**
+   * Test if all the operands match, like they are supposed to.
+   * @param operands The operands to test.
+   * @return <code>true</code> iff the operands all share column ordering.
+   */
+  private boolean operandsMatch(StoreTuples[] operands) {
+    int[] order = operands[0].getColumnOrder();
+    for (int i = 1; i < operands.length; i++) {
+      int[] newOrder = operands[i].getColumnOrder();
+      if (newOrder.length != order.length) return false;
+      for (int c = 0; c < order.length; c++) if (newOrder[c] != order[c]) return false;
+    }
+    return true;
+  }
+
+}

Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/Tuples.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/Tuples.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/Tuples.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -274,5 +274,5 @@
    *
    * @return An annotation of the class requested, or null if none exists.
    */
-  public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException;
+  public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException;
 }

Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperations.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperations.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperations.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -46,33 +46,17 @@
  * {@link Variable}s to {@link Value}s.
  *
  * @created 2003-01-30
- *
  * @author <a href="http://staff.pisoftware.com/raboczi">Simon Raboczi</a>
- *
- * @version $Revision: 1.12 $
- *
- * @modified $Date: 2005/05/16 11:07:10 $
- *
- * @maintenanceAuthor $Author: amuys $
- *
  * @company <A href="mailto:info at PIsoftware.com">Plugged In Software</A>
- *
- * @copyright &copy; 2003 <A href="http://www.PIsoftware.com/">Plugged In
- *      Software Pty Ltd</A>
- *
+ * @copyright &copy; 2003 <A href="http://www.PIsoftware.com/">Plugged In Software Pty Ltd</A>
  * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
  */
 public abstract class TuplesOperations {
 
-  /**
-   * Logger. This is named after the class.
-   */
-  private final static Logger logger =
-      Logger.getLogger(TuplesOperations.class.getName());
+  /** Logger. This is named after the class. */
+  private final static Logger logger = Logger.getLogger(TuplesOperations.class.getName());
 
-  /**
-   * The factory used to generate new {@link Tuples} instances.
-   */
+  /** The factory used to generate new {@link Tuples} instances. */
   private static TuplesFactory tuplesFactory = TuplesFactory.newInstance();
 
   /**
@@ -82,10 +66,9 @@
    * value to a tuples generates an empty result.
    *
    * @return the expression which is never satisfied, no matter what value any
-   *      variable takes
+   *         variable takes
    */
   public static StoreTuples empty() {
-
     return EmptyTuples.getInstance();
   }
 
@@ -101,7 +84,6 @@
    * @return the expression which is always true, for any value of any variables
    */
   public static StoreTuples unconstrained() {
-
     return UnconstrainedTuples.getInstance();
   }
 
@@ -109,12 +91,11 @@
    * Assign a value to a variable, representing the binding as a tuples with one
    * row and one column.
    *
-   * @param variable PARAMETER TO DO
-   * @param value PARAMETER TO DO
-   * @return RETURNED VALUE TO DO
+   * @param variable The variable to bind
+   * @param value The value in local space to bind the variable to
+   * @return A Tuples with the variable bound to the given value.
    */
   public static Tuples assign(Variable variable, long value) {
-
     return (value == Tuples.UNBOUND) ? (Tuples)unconstrained()
                                      : new Assignment(variable, value);
   }
@@ -122,9 +103,9 @@
   /**
    * This is approximately a disjunction.
    *
-   * @param lhs PARAMETER TO DO
-   * @param rhs PARAMETER TO DO
-   * @return RETURNED VALUE TO DO
+   * @param lhs The first Tuples to be used in the result.
+   * @param rhs The second Tuples to be used in the result.
+   * @return A new Tuples containing all of the bindings from the lhs and rhs parameters.
    * @throws TuplesException if the append fails
    */
   public static Tuples append(Tuples lhs, Tuples rhs) throws TuplesException {
@@ -132,10 +113,16 @@
   }
 
 
+  /**
+   * Creates a new Tuples which contains all of the bindings of the Tuples in the argument list.
+   * If any tuples contains variables not found in the other Tuples, then those values will
+   * remain unbound for the bindings of those Tuples missing those variables.
+   * @param args A list of the Tuples to be used in the result.
+   * @return A Tuples containing all of the bindings from the args list.
+   * @throws TuplesException If the data could not be appended.
+   */
   public static Tuples append(List<? extends Tuples> args) throws TuplesException {
-    if (logger.isDebugEnabled()) {
-      logger.debug("Appending " + args);
-    }
+    if (logger.isDebugEnabled()) logger.debug("Appending " + args);
 
     HashSet<Variable> variableSet = new HashSet<Variable>();
     List<Variable> variables = new ArrayList<Variable>();
@@ -147,25 +134,18 @@
       Tuples operand = i.next();
       if (operand.isUnconstrained()) {
         closeOperands(operands);
-        if (logger.isDebugEnabled()) {
-          logger.debug("Returning unconstrained from append.");
-        }
+        if (logger.isDebugEnabled()) logger.debug("Returning unconstrained from append.");
         return unconstrained();
       } else if (operand.getRowCardinality() == Cursor.ZERO) {
-        if (logger.isDebugEnabled()) {
-          logger.debug("Ignoring append operand " + operand + " with rowcount = " + operand.getRowCount());
-        }
+        if (logger.isDebugEnabled()) logger.debug("Ignoring append operand " + operand + " with rowcount = " + operand.getRowCount());
         continue;
       }
 
       operands.add((Tuples)operand.clone());
 
       Variable[] vars = operand.getVariables();
-      if (leftVars == null) {
-        leftVars = vars;
-      } else {
-        unionCompat = unionCompat && Arrays.equals(leftVars, vars);
-      }
+      if (leftVars == null) leftVars = vars;
+      else unionCompat = unionCompat && Arrays.equals(leftVars, vars);
       for (int j = 0; j < vars.length; j++) {
         if (!variableSet.contains(vars[j])) {
           variableSet.add(vars[j]);
@@ -174,22 +154,16 @@
       }
     }
 
-    if (logger.isDebugEnabled()) {
-      logger.debug("Operands after append-unification: " + operands);
-    }
+    if (logger.isDebugEnabled()) logger.debug("Operands after append-unification: " + operands);
 
     if (operands.isEmpty()) {
-      if (logger.isDebugEnabled()) {
-        logger.debug("Returning empty from append.");
-      }
+      if (logger.isDebugEnabled()) logger.debug("Returning empty from append.");
       return empty();
     }
 
     if (operands.size() == 1) {
-      if (logger.isDebugEnabled()) {
-        logger.debug("Returning singleton from append.");
-      }
-      return (Tuples)operands.get(0);
+      if (logger.isDebugEnabled()) logger.debug("Returning singleton from append.");
+      return operands.get(0);
     }
 
     if (unionCompat) {
@@ -202,9 +176,7 @@
       return result;
     } else {
       List<Tuples> projected = new ArrayList<Tuples>();
-      i = operands.iterator();
-      while (i.hasNext()) {
-        Tuples operand = i.next();
+      for (Tuples operand: operands) {
         Tuples proj = project(operand, variables);
         Tuples sorted = sort(proj);
         projected.add(sorted);
@@ -212,9 +184,7 @@
         operand.close();
       }
 
-      if (logger.isDebugEnabled()) {
-        logger.debug("Returning OrderedAppend from Non-Union compatible append.");
-      }
+      if (logger.isDebugEnabled()) logger.debug("Returning OrderedAppend from Non-Union compatible append.");
       Tuples result = new OrderedAppend(projected.toArray(new Tuples[projected.size()]));
       closeOperands(projected);
       return result;
@@ -223,49 +193,97 @@
 
 
   /**
-   * This is approximately a conjunction.
+   * Creates a new Tuples which contains all of the bindings of the Tuples in the argument list.
+   * All tuples must have an identical pattern, and come directly from the store.
+   * @param args A list of the Tuples directly backed by the store to be used in the result.
+   * @return A StoreTuples containing all of the bindings from the args list.
+   * @throws TuplesException If the data could not be appended.
    */
+  public static StoreTuples appendCompatible(List<StoreTuples> args) throws TuplesException {
+    if (logger.isDebugEnabled()) logger.debug("Compatible append of " + args);
+
+    Variable[] vars = null;
+    List<StoreTuples> operands = new ArrayList<StoreTuples>();
+    for (StoreTuples arg: args) {
+
+      // test for empty or unconstrained data
+      if (arg.isUnconstrained()) {
+        closeOperands(operands);
+        if (logger.isDebugEnabled()) logger.debug("Returning unconstrained from append.");
+        return unconstrained();
+      } else if (arg.getRowCardinality() == Cursor.ZERO) {
+        if (logger.isDebugEnabled()) logger.debug("Ignoring append operand " + arg + " with rowcount = " + arg.getRowCount());
+        continue;
+      }
+
+      operands.add((StoreTuples)arg.clone());
+
+      // test for tuples compatibility
+      if (vars == null) vars = arg.getVariables();
+      else if (!Arrays.equals(vars, arg.getVariables())) {
+        throw new IllegalArgumentException("Incompatible arguments to appendCompatible");
+      }
+
+    }
+
+    if (logger.isDebugEnabled()) logger.debug("Operands after compatible-append-unification: " + operands);
+
+    if (operands.isEmpty()) {
+      if (logger.isDebugEnabled()) logger.debug("Returning empty from append.");
+      return empty();
+    }
+
+    if (operands.size() == 1) {
+      if (logger.isDebugEnabled()) logger.debug("Returning singleton from append.");
+      return operands.get(0);
+    }
+
+    StoreTuples result = new OrderedStoreAppend(operands.toArray(new StoreTuples[operands.size()]));
+    closeOperands(operands);
+    return result;
+  }
+
+
+  /**
+   * Convenience method for doing a binary {@link #join(List)}.
+   * @param lhs The first argument to be joined.
+   * @param rhs The second argument to be joined.
+   * @return A Tuples containing the conjunction of lhs and rhs.
+   */
   public static Tuples join(Tuples lhs, Tuples rhs) throws TuplesException {
     return join(Arrays.asList(new Tuples[] { lhs, rhs }));
   }
 
+  /**
+   * This is approximately a conjunction. Returns a set of bindings containing all the variables
+   * from both parameters. The only bindings returned are those where all the matching variables
+   * in each argument are bound to the same values.
+   * @param args The Tuples to be joined together.
+   * @return A Tuples containing the conjunction of all the arguments.
+   */
   public static Tuples join(List<? extends Tuples> args) throws TuplesException {
     try {
-      if (logger.isDebugEnabled()) {
-        logger.debug(printArgs("Flattening args:", args));
-      }
+      if (logger.isDebugEnabled()) logger.debug(printArgs("Flattening args:", args));
       List<Tuples> operands = flattenOperands(args);
 
-      if (logger.isDebugEnabled()) {
-        logger.debug(printArgs("Unifying args: ", operands));
-      }
+      if (logger.isDebugEnabled()) logger.debug(printArgs("Unifying args: ", operands));
       List<Tuples> unified = unifyOperands(operands);
 
-      if (logger.isDebugEnabled()) {
-        logger.debug(printArgs("Sorting args:", unified));
-      }
+      if (logger.isDebugEnabled()) logger.debug(printArgs("Sorting args:", unified));
       List<Tuples> sorted = sortOperands(unified);
 
-      if (logger.isDebugEnabled()) {
-        logger.debug(printArgs("Preparing result: ", sorted));
-      }
+      if (logger.isDebugEnabled()) logger.debug(printArgs("Preparing result: ", sorted));
       switch (sorted.size()) {
         case 0:
-          if (logger.isDebugEnabled()) {
-            logger.debug("Short-circuit empty");
-          }
+          if (logger.isDebugEnabled()) logger.debug("Short-circuit empty");
           return empty();
 
         case 1:
-          if (logger.isDebugEnabled()) {
-            logger.debug("Short-circuit singleton");
-          }
-          return (Tuples)sorted.get(0);
+          if (logger.isDebugEnabled()) logger.debug("Short-circuit singleton");
+          return sorted.get(0);
 
         default:
-          if (logger.isDebugEnabled()) {
-            logger.debug("return UnboundJoin");
-          }
+          if (logger.isDebugEnabled()) logger.debug("return UnboundJoin");
           Tuples result = new UnboundJoin(sorted.toArray(new Tuples[sorted.size()]));
           closeOperands(sorted);
           return result;
@@ -291,10 +309,7 @@
    */
   public static Tuples subtract(Tuples minuend, Tuples subtrahend) throws TuplesException {
     try {
-
-      if (logger.isDebugEnabled()) {
-        logger.debug("subtracting " + subtrahend + " from " + minuend);
-      }
+      if (logger.isDebugEnabled()) logger.debug("subtracting " + subtrahend + " from " + minuend);
       // get the matching columns
       Set<Variable> matchingVars = getMatchingVars(minuend, subtrahend);
       if (matchingVars.isEmpty()) {
@@ -327,9 +342,7 @@
       try {
         return new Difference(minuend, sortedSubtrahend);
       } finally {
-        if (sortedSubtrahend != subtrahend) {
-          sortedSubtrahend.close();
-        }
+        if (sortedSubtrahend != subtrahend) sortedSubtrahend.close();
       }
 
     } catch (RuntimeException re) {
@@ -355,9 +368,7 @@
   public static Tuples optionalJoin(Tuples standard, Tuples optional, Filter filter, QueryEvaluationContext context) throws TuplesException {
     try {
 
-      if (logger.isDebugEnabled()) {
-        logger.debug("optional join of " + standard + " optional { " + optional + " }");
-      }
+      if (logger.isDebugEnabled()) logger.debug("optional join of " + standard + " optional { " + optional + " }");
 
       // get the matching columns
       Set<Variable> matchingVars = getMatchingVars(standard, optional);
@@ -387,9 +398,7 @@
       }
 
       // yes, there are extra variables
-      if (logger.isDebugEnabled()) {
-        logger.debug("sorting on the common variables: " + matchingVars);
-      }
+      if (logger.isDebugEnabled()) logger.debug("sorting on the common variables: " + matchingVars);
       // re-sort the optional according to the matching variables
       // reorder the optional as necessary
       Tuples sortedOptional = reSort(optional, new ArrayList<Variable>(matchingVars));
@@ -413,27 +422,29 @@
 
   /**
    * Flattens any nested joins to allow polyadic join operations.
+   * @param A list of Tuples which may in turn be nested operations.
+   * @return A flattened list of flattened Tuples. 
    */
   private static List<Tuples> flattenOperands(List<? extends Tuples> operands) throws TuplesException {
     List<Tuples> result = new ArrayList<Tuples>();
-    for (Tuples operand: operands) {
-      result.addAll(flattenOperand(operand));
-    }
-
+    for (Tuples operand: operands) result.addAll(flattenOperand(operand));
     return result;
   }
 
 
+  /**
+   * Flattens a Tuples into a list of Tuples. This means that joins will be expanded into their components.
+   * @param operand The Tuples to flatten
+   * @return A flattened list.
+   * @throws TuplesException If the Tuples could not be accessed.
+   */
   private static List<Tuples> flattenOperand(Tuples operand) throws TuplesException {
     List<Tuples> operands = new ArrayList<Tuples>();
     if (operand instanceof UnboundJoin) {
-      for (Tuples op: operand.getOperands()) {
-        operands.add((Tuples)op.clone());
-      }
+      for (Tuples op: operand.getOperands()) operands.add((Tuples)op.clone());
     } else {
       operands.add((Tuples)operand.clone());
     }
-
     return operands;
   }
 
@@ -442,7 +453,6 @@
    * Unifies bound variables in operands.
    * Prepends a LiteralTuples containing constrained variable bindings.
    * If any operand returns 0-rows returns EmptyTuples.
-   *
    * @param operands List of Tuples to unify.  Consumed by this function.
    * @return List of operands remaining after full unification.
    */
@@ -456,7 +466,7 @@
     }
 
     List<Tuples> result = extractNonReresolvableTuples(operands);
-    // operands is not effectively a List<ReresolvableResolution>
+    // operands is now effectively a List<ReresolvableResolution>
 
     List<ReresolvableResolution> reresolved;
     do {
@@ -466,6 +476,7 @@
         closeOperands(result);
         closeOperands(reresolved);
         logger.debug("Returning empty due to shortcircuiting progressive bindSingleRowOperands");
+        // wrap in an Array list to convert the generic type
         return new ArrayList<Tuples>(Collections.singletonList(empty()));
       }
       operands.addAll(reresolved);
@@ -481,8 +492,7 @@
   /**
    * Extracts all bound names from workingSet into bindings.
    */
-  private static boolean bindSingleRowOperands(Map<Variable,Long> bindings, List<? extends Tuples> workingSet)
-      throws TuplesException {
+  private static boolean bindSingleRowOperands(Map<Variable,Long> bindings, List<? extends Tuples> workingSet) throws TuplesException {
     Iterator<? extends Tuples> iter = workingSet.iterator();
     while (iter.hasNext()) {
       Tuples tuples = iter.next();
@@ -498,22 +508,15 @@
             for (int i = 0; i < vars.length; i++) {
               Long value = new Long(tuples.getColumnValue(tuples.getColumnIndex(vars[i])));
               Long oldValue = (Long)bindings.put(vars[i], value);
-              if (oldValue != null && !value.equals(oldValue)) {
-                return false;
-              }
+              if (oldValue != null && !value.equals(oldValue)) return false;
             }
           } else {
             // This should not happen.
             // If the call to getRowCardinality returns > 0 then beforeFirst,
             // and then next should return true too.
-            logger.error(
-                "No rows but getRowCardinality returned Cursor.ONE: (class=" +
-                tuples.getClass().getName() + ") " + tuples.toString() + "\n" +
-                new StackTrace()
-            );
-            throw new AssertionError(
-                "No rows but getRowCardinality returned Cursor.ONE"
-            );
+            logger.error("No rows but getRowCardinality returned Cursor.ONE: (class=" +
+                    tuples.getClass().getName() + ") " + tuples.toString() + "\n" + new StackTrace());
+            throw new AssertionError("No rows but getRowCardinality returned Cursor.ONE");
           }
           iter.remove();
           tuples.close();
@@ -531,8 +534,7 @@
   }
 
 
-  private static List<Tuples> extractNonReresolvableTuples(List<Tuples> workingSet)
-      throws TuplesException {
+  private static List<Tuples> extractNonReresolvableTuples(List<Tuples> workingSet) throws TuplesException {
     List<Tuples> nonReresolvable = new ArrayList<Tuples>(workingSet.size());
 
     Iterator<Tuples> iter = workingSet.iterator();
@@ -554,8 +556,7 @@
    * @param workingSet A set of ReresolvableResolution, though it will be represented as a set of Tuples
    * @return List of ConstrainedTuples resulting from any resolutions required.
    */
-  private static List<ReresolvableResolution> resolveNewlyBoundFreeNames(List<Tuples> workingSet, Map<Variable,Long> bindings)
-      throws TuplesException {
+  private static List<ReresolvableResolution> resolveNewlyBoundFreeNames(List<Tuples> workingSet, Map<Variable,Long> bindings) throws TuplesException {
     List<ReresolvableResolution> reresolved = new ArrayList<ReresolvableResolution>();
     Iterator<Tuples> iter = workingSet.iterator();
     while (iter.hasNext()) {
@@ -572,19 +573,14 @@
   }
 
 
-  private static Tuples createTuplesFromBindings(Map<Variable,Long> bindings)
-      throws TuplesException {
-    if (bindings.isEmpty()) {
-      return unconstrained();
-    }
+  private static Tuples createTuplesFromBindings(Map<Variable,Long> bindings) throws TuplesException {
+    if (bindings.isEmpty()) return unconstrained();
 
     Set<Variable> keys = bindings.keySet();
     Variable[] vars = keys.toArray(new Variable[keys.size()]);
 
     long[] values = new long[vars.length];
-    for (int i = 0; i < values.length; i++) {
-      values[i] = bindings.get(vars[i]);
-    }
+    for (int i = 0; i < values.length; i++) values[i] = bindings.get(vars[i]);
 
     LiteralTuples tuples = new LiteralTuples(vars);
     tuples.appendTuple(values);
@@ -615,9 +611,7 @@
 
       DefinablePrefixAnnotation definable =
           (DefinablePrefixAnnotation)bestTuples.getAnnotation(DefinablePrefixAnnotation.class);
-      if (definable != null) {
-        definable.definePrefix(boundVars);
-      }
+      if (definable != null) definable.definePrefix(boundVars);
 
       // Add all variables that don't contain UNBOUND to boundVars set.
       // Note: the inefficiency this introduces for distributed results
@@ -627,9 +621,7 @@
       // left-operand it becomes unprefixed.
       Variable[] vars = bestTuples.getVariables();
       for (int i = 0; i < vars.length; i++) {
-        if (!bestTuples.isColumnEverUnbound(i)) {
-          boundVars.add(vars[i]);
-        }
+        if (!bestTuples.isColumnEverUnbound(i)) boundVars.add(vars[i]);
       }
 
       result.add(bestTuples);
@@ -640,8 +632,7 @@
 
 
   // FIXME: Method too long.  Refactor.
-  private static Tuples removeBestTuples(List<Tuples> operands, Set<Variable> boundVars)
-      throws TuplesException {
+  private static Tuples removeBestTuples(List<Tuples> operands, Set<Variable> boundVars) throws TuplesException {
     ListIterator<Tuples> iter = operands.listIterator();
     Tuples minTuples = null;
     double minRowCount = Double.MAX_VALUE;
@@ -652,22 +643,17 @@
     logger.debug("removeBestTuples");
     while (iter.hasNext()) {
       Tuples tuples = (Tuples)iter.next();
-      if (logger.isDebugEnabled()) {
-        logger.debug("tuples: " + tuplesSummary(tuples));
-      }
+      if (logger.isDebugEnabled()) logger.debug("tuples: " + tuplesSummary(tuples));
 
       // Check tuples meets any mandatory left bindings.
       MandatoryBindingAnnotation bindingRequirements =
           (MandatoryBindingAnnotation)tuples.getAnnotation(MandatoryBindingAnnotation.class);
-      if (bindingRequirements != null && !bindingRequirements.meetsRequirement(boundVars)) {
-        continue;
-      }
 
+      if (bindingRequirements != null && !bindingRequirements.meetsRequirement(boundVars)) continue;
+
       Variable[] vars = tuples.getVariables();
       int numLeftBindings = calculateNumberOfLeftBindings(tuples, boundVars);
-      if (logger.isDebugEnabled()) {
-        logger.debug("numLeftBindings: " + numLeftBindings);
-      }
+      if (logger.isDebugEnabled()) logger.debug("numLeftBindings: " + numLeftBindings);
 
       // Basic formula assumes uniform distribution.  So number of rows is the
       // product of the length of each variable taken seperately, hence expected
@@ -703,32 +689,24 @@
       throw new TuplesException("Unable to meet ordering constraints");
     }
 
-    if (logger.isDebugEnabled()) {
-      logger.debug("Selected: " + tuplesSummary(minTuples) + " with weightedRowCount: " + minRowCount);
-    }
+    if (logger.isDebugEnabled()) logger.debug("Selected: " + tuplesSummary(minTuples) + " with weightedRowCount: " + minRowCount);
     operands.remove(minIndex);
     return minTuples;
   }
 
 
-  private static int calculateNumberOfLeftBindings(Tuples tuples,
-      Set<Variable> boundVars) throws TuplesException {
+  private static int calculateNumberOfLeftBindings(Tuples tuples, Set<Variable> boundVars) throws TuplesException {
     int numLeftBindings = 0;
     Variable[] vars = tuples.getVariables();
     // If the tuples supports defining a prefix then
     if (tuples.getAnnotation(DefinablePrefixAnnotation.class) != null) {
       for (int i = 0; i < vars.length; i++) {
-        if (boundVars.contains(vars[i])) {
-          numLeftBindings++;
-        }
+        if (boundVars.contains(vars[i])) numLeftBindings++;
       }
     } else {
       for (int i = 0; i < vars.length; i++) {
-        if (boundVars.contains(vars[i])) {
-          numLeftBindings++;
-        } else {
-          break;
-        }
+        if (boundVars.contains(vars[i])) numLeftBindings++;
+        else break;
       }
     }
 
@@ -745,18 +723,14 @@
    * @return RETURNED VALUE TO DO
    * @throws TuplesException if the projection operation fails
    */
-  public static Tuples project(Tuples tuples, List<Variable> variableList)
-      throws TuplesException {
+  public static Tuples project(Tuples tuples, List<Variable> variableList) throws TuplesException {
     try {
 
       boolean noVariables = (variableList == null) || (variableList.size() == 0);
 
-      if (tuples.isUnconstrained() ||
-         (noVariables && tuples.getRowCardinality() != Cursor.ZERO)) {
+      if (tuples.isUnconstrained() || (noVariables && tuples.getRowCardinality() != Cursor.ZERO)) {
 
-        if (logger.isDebugEnabled()) {
-          logger.debug("returning Unconstrained Tuples.");
-        }
+        if (logger.isDebugEnabled()) logger.debug("returning Unconstrained Tuples.");
 
         return TuplesOperations.unconstrained();
       } else if (tuples.getRowCardinality() == Cursor.ZERO) {
@@ -766,9 +740,7 @@
       } else if ((noVariables) && (tuples instanceof ConstrainedNegationTuples)) {
         return empty();
       } else {
-        if (logger.isDebugEnabled()) {
-          logger.debug("Projecting to " + variableList);
-        }
+        if (logger.isDebugEnabled()) logger.debug("Projecting to " + variableList);
 
         // Perform the actual projection
         Tuples oldTuples = tuples;
@@ -785,12 +757,10 @@
         oldTuples = tuples;
         tuples = removeDuplicates(tuples);
         assert tuples != oldTuples;
-        if (tuples == oldTuples) {
-          logger.warn("removeDuplicates does not change the underlying tuples");
-        } else {
-          oldTuples.close();
-        }
 
+        if (tuples == oldTuples) logger.warn("removeDuplicates does not change the underlying tuples");
+        else oldTuples.close();
+
         assert tuples.hasNoDuplicates();
 
         return tuples;
@@ -801,6 +771,13 @@
   }
 
 
+  /**
+   * Creates a new restriction tuples, based on a normal Tuples and a restriction predicate.
+   * @param tuples The tuples to restrict.
+   * @param pred The predicate describing the restriction.
+   * @return A new Tuples whose bindings only match the restriction.
+   * @throws TuplesException If the Tuples could not be accessed.
+   */
   public static Tuples restrict(Tuples tuples, RestrictPredicate pred) throws TuplesException {
     return new RestrictionTuples(tuples, pred);
   }
@@ -823,9 +800,8 @@
 
   /**
    * Sort into default order, based on the columns and local node numbers.
-   *
    * @param tuples the tuples to sort
-   * @return RETURNED VALUE TO DO
+   * @return A new Tuples with the bindings sorted.
    * @throws TuplesException if the sorting can't be accomplished
    */
   public static Tuples sort(Tuples tuples) throws TuplesException {
@@ -835,17 +811,13 @@
       } else if (tuples.getRowCardinality() == Cursor.ZERO) {
         tuples = empty();
       } else {
-        if (logger.isDebugEnabled()) {
-          logger.debug("Sorting " + tuples.getRowCount() + " rows");
-        }
+        if (logger.isDebugEnabled()) logger.debug("Sorting " + tuples.getRowCount() + " rows");
 
         tuples = tuplesFactory.newTuples(tuples);
         assert tuples.getComparator() != null;
       }
 
-      if (logger.isDebugEnabled()) {
-        logger.debug("Sorted " + tuples.getRowCount() + " rows");
-      }
+      if (logger.isDebugEnabled()) logger.debug("Sorted " + tuples.getRowCount() + " rows");
 
       return tuples;
     } else {
@@ -858,24 +830,15 @@
    *
    * @param tuples the tuples to sort
    * @param rowComparator the ordering
-   * @return RETURNED VALUE TO DO
+   * @return A Tuples with bindings sorted according to the rowComparator.
    * @throws TuplesException if the sorting can't be accomplished
    */
-  public static Tuples sort(Tuples tuples,
-      RowComparator rowComparator) throws TuplesException {
-
+  public static Tuples sort(Tuples tuples, RowComparator rowComparator) throws TuplesException {
     if (!rowComparator.equals(tuples.getComparator())) {
-
       tuples = tuplesFactory.newTuples(tuples, rowComparator);
-
-      if (logger.isDebugEnabled()) {
-        logger.debug("Sorted: " + tuples + " (using supplied row comparator)");
-      }
-
+      if (logger.isDebugEnabled()) logger.debug("Sorted: " + tuples + " (using supplied row comparator)");
       return tuples;
-    }
-    else {
-
+    } else {
       return (Tuples) tuples.clone();
     }
   }
@@ -956,10 +919,9 @@
    * @param tuples  the instance to limit
    * @param rowCount the number of leading rows to retain
    * @return the truncated tuples
-   * @throws TuplesException EXCEPTION TO DO
+   * @throws TuplesException If there was an error accessing the Tuples.
    */
-  public static Tuples limit(Tuples tuples, long rowCount)
-    throws TuplesException {
+  public static Tuples limit(Tuples tuples, long rowCount) throws TuplesException {
     return new LimitedTuples((Tuples) tuples.clone(), rowCount);
   }
 
@@ -967,17 +929,13 @@
    * If a tuples is virtual, evaluate and store it.
    *
    * @param tuples the instance to materialize
-   * @return RETURNED VALUE TO DO
-   * @throws TuplesException EXCEPTION TO DO
+   * @return A set of Tuples with any virtual bindings converted into actual bindings.
+   * @throws TuplesException If there was an error evaluating the virtual bindings
    */
   public static Tuples materialize(Tuples tuples) throws TuplesException {
-
     if (tuples.isMaterialized()) {
-
-      return (Tuples) tuples.clone();
-    }
-    else {
-
+      return (Tuples)tuples.clone();
+    } else {
       return tuplesFactory.newTuples(tuples);
     }
   }
@@ -991,32 +949,27 @@
    * @param tuples  the instance to offset
    * @param rowCount the number of leading rows to remove
    * @return the remaining rows, if any
-   * @throws TuplesException EXCEPTION TO DO
+   * @throws TuplesException If there was an error accessing the tuples.
    */
-  public static Tuples offset(Tuples tuples, long rowCount)
-      throws TuplesException {
-    return new OffsetTuples((Tuples) tuples.clone(), rowCount);
+  public static Tuples offset(Tuples tuples, long rowCount) throws TuplesException {
+    return new OffsetTuples((Tuples)tuples.clone(), rowCount);
   }
 
   /**
    * Filter out duplicate rows.
    *
-   * @param tuples PARAMETER TO DO
-   * @return RETURNED VALUE TO DO
-   * @throws TuplesException EXCEPTION TO DO
+   * @param tuples The tuples to filter.
+   * @return An equivalent Tuples, but with duplicate bindings removed.
+   * @throws TuplesException If there was an error accessing the tuples.
    */
   public static Tuples removeDuplicates(Tuples tuples) throws TuplesException {
 
     if (tuples.hasNoDuplicates()) {
-      if (logger.isDebugEnabled()) {
-        logger.debug("Didn't need to remove duplicates");
-      }
-      return (Tuples) tuples.clone();
+      if (logger.isDebugEnabled()) logger.debug("Didn't need to remove duplicates");
+      return (Tuples)tuples.clone();
     }
 
-    if (logger.isDebugEnabled()) {
-      logger.debug("Removing duplicates");
-    }
+    if (logger.isDebugEnabled()) logger.debug("Removing duplicates");
 
     if (tuples.getComparator() == null) {
       Tuples oldTuples = tuples;
@@ -1032,12 +985,8 @@
       }
 
       return tuples;
-    }
-    else {
-      if (logger.isDebugEnabled()) {
-        logger.debug("Already sorted: " + tuples);
-      }
-
+    } else {
+      if (logger.isDebugEnabled()) logger.debug("Already sorted: " + tuples);
       Tuples result = new DistinctTuples(tuples);
       return result;
     }
@@ -1049,18 +998,16 @@
   }
 
 
-  public static StringBuffer tuplesSummary(Tuples tuples) {
-    StringBuffer buff = new StringBuffer();
+  public static StringBuilder tuplesSummary(Tuples tuples) {
+    StringBuilder buff = new StringBuilder();
 
     buff.append(tuples.getClass().toString());
 
     buff.append("<" + System.identityHashCode(tuples) + ">");
     buff.append("[");
-    if (!tuples.isMaterialized()) {
-      buff.append("~");
-    } else {
-      buff.append("=");
-    }
+    if (!tuples.isMaterialized()) buff.append("~");
+    else buff.append("=");
+
     try {
       buff.append(tuples.getRowUpperBound()).append("]");
     } catch (TuplesException et) {
@@ -1071,17 +1018,13 @@
     Variable[] vars = tuples.getVariables();
     if (vars.length > 0) {
       buff.append(vars[0].toString());
-      for (int i = 1; i < vars.length; i++) {
-        buff.append(", " + vars[i].toString());
-      }
+      for (int i = 1; i < vars.length; i++) buff.append(", " + vars[i].toString());
     }
     buff.append("}");
 
     try {
       MandatoryBindingAnnotation mba = (MandatoryBindingAnnotation)tuples.getAnnotation(MandatoryBindingAnnotation.class);
-      if (mba != null) {
-        buff.append(" :: MBA{ " + mba.requiredVariables() + " }");
-      }
+      if (mba != null) buff.append(" :: MBA{ " + mba.requiredVariables() + " }");
     } catch (TuplesException et) {
       logger.error("Failed to obtain annotation", et);
     }
@@ -1120,15 +1063,18 @@
     // get the variable list
     Variable[] sv = tuples.getVariables();
     for (int i = 0; i < sv.length; i++) {
-      if (!vars.contains(sv[i])) {
-        // extra variable
-        return true;
-      }
+      if (!vars.contains(sv[i])) return true;  // extra variable
     }
     return false;
   }
 
 
+  /**
+   * Convert a list of Tuples into a string.
+   * @param header The header for the returned string.
+   * @param args The tuples to print.
+   * @return The string containing the full list of tuples.
+   */
   private static String printArgs(String header, List<? extends Tuples> args) {
     StringBuilder buff = new StringBuilder(header);
     buff.append("[");
@@ -1146,17 +1092,11 @@
 
 
   private static StringBuilder indentedTuplesTree(Tuples tuples, String indent) {
-
     StringBuilder buff = new StringBuilder();
-
     buff.append("\n").append(indent).append("(").append(tuplesSummary(tuples));
-
     for (Tuples t: tuples.getOperands()) buff.append(" ").append(indentedTuplesTree(t, indent + ".   "));
-
     buff.append(")");
-
     return buff;
   }
 
-
 }

Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/WrappedTuples.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/WrappedTuples.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/WrappedTuples.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -328,7 +328,7 @@
   /**
    * Copied from AbstractTuples.
    */
-  public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+  public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
     return null;
   }
 }

Modified: trunk/src/jar/util-xa/java/org/mulgara/store/xa/AVLNode.java
===================================================================
--- trunk/src/jar/util-xa/java/org/mulgara/store/xa/AVLNode.java	2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/util-xa/java/org/mulgara/store/xa/AVLNode.java	2009-01-24 07:03:51 UTC (rev 1457)
@@ -1285,6 +1285,7 @@
    */
   private int rotateL() throws IOException {
     AVLNode nodeL = getLeftChildNode();
+    if (nodeL == null) throw new IllegalStateException("Invalid tree structure on disk");
     int deltaHeight = (nodeL.block.getByte(IDX_BALANCE_B) >= 0) ?
         rotateLL(nodeL) : rotateLR(nodeL);
     nodeL.release();
@@ -1301,6 +1302,7 @@
    */
   private int rotateR() throws IOException {
     AVLNode nodeR = getRightChildNode();
+    if (nodeR == null) throw new IllegalStateException("Invalid tree structure on disk");
     int deltaHeight = (nodeR.block.getByte(IDX_BALANCE_B) <= 0) ?
         rotateRR(nodeR) : rotateRL(nodeR);
     nodeR.release();
@@ -1443,6 +1445,7 @@
   private int rotateLR(AVLNode nodeL) throws IOException {
     // First perform rotateRR on nodeL.
     AVLNode nodeLR = nodeL.getRightChildNode();
+    if (nodeLR == null) throw new IllegalStateException("Invalid tree structure on disk");
     int deltaHeightL = nodeL.rotateRR(nodeLR);
 
     // Adjust the balance of this node.




More information about the Mulgara-svn mailing list