[Mulgara-svn] r347 - in branches/nw-interface/src/jar: itql/java/org/mulgara itql/java/org/mulgara/itql itql/java/org/mulgara/query itql/java/org/mulgara/query/ast jrdf/java/org/mulgara/jrdf query/java/org/mulgara/query query/java/org/mulgara/server

pag at mulgara.org pag at mulgara.org
Fri Aug 10 21:12:10 UTC 2007


Author: pag
Date: 2007-08-10 16:12:09 -0500 (Fri, 10 Aug 2007)
New Revision: 347

Added:
   branches/nw-interface/src/jar/itql/java/org/mulgara/itql/Interpreter.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/itql/TqlInterpreter.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/itql/URIUtil.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/query/
   branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/
   branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/ApplyRules.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/CommandAst.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Commit.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/CreateGraph.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/DropGraph.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Help.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/LocalAst.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Quit.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Rollback.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/SetUser.java
Modified:
   branches/nw-interface/src/jar/itql/java/org/mulgara/itql/ConstraintExpressionBuilder.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/itql/ItqlInterpreter.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/itql/ModelExpressionBuilder.java
   branches/nw-interface/src/jar/itql/java/org/mulgara/itql/VariableBuilder.java
   branches/nw-interface/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphUnitTest.java
   branches/nw-interface/src/jar/jrdf/java/org/mulgara/jrdf/JRDFLocalGraphUnitTest.java
   branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelExpression.java
   branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelIntersection.java
   branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelLiteral.java
   branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelOperation.java
   branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelPartition.java
   branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelResource.java
   branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelUnion.java
   branches/nw-interface/src/jar/query/java/org/mulgara/query/Query.java
   branches/nw-interface/src/jar/query/java/org/mulgara/server/Session.java
Log:
Copied ItqlInterpreter into TqlInterpreter, and am slowly converting actions into an AST structure (to be run independently of the parsing process). The AST is in a new package called org.mulgara.query.ast. TqlInterpreter is a long way from compiling, but on its way.

Modified: branches/nw-interface/src/jar/itql/java/org/mulgara/itql/ConstraintExpressionBuilder.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/itql/ConstraintExpressionBuilder.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/itql/ConstraintExpressionBuilder.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -100,7 +100,7 @@
   /**
    * The iTQL interpreter
    */
-  private ItqlInterpreter interpreter;
+  private Interpreter interpreter;
 
   /**
    * Create a new builder.  Requires methods on the interpreter in order to
@@ -108,7 +108,7 @@
    *
    * @param newInterpreter the interpreter to use.
    */
-  public ConstraintExpressionBuilder(ItqlInterpreter newInterpreter) {
+  public ConstraintExpressionBuilder(Interpreter newInterpreter) {
     interpreter = newInterpreter;
   }
 

Added: branches/nw-interface/src/jar/itql/java/org/mulgara/itql/Interpreter.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/itql/Interpreter.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/itql/Interpreter.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -0,0 +1,104 @@
+package org.mulgara.itql;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.mulgara.itql.node.PLiteral;
+import org.mulgara.itql.node.TResource;
+import org.mulgara.itql.node.Token;
+import org.mulgara.query.Query;
+import org.mulgara.query.QueryException;
+import org.mulgara.query.Variable;
+import org.mulgara.query.rdf.LiteralImpl;
+
+
+/**
+ * This interface defines the namespaces used while interpreting RDF code.
+ * @author pag
+ *
+ */
+public interface Interpreter {
+
+  //
+  // Constants
+  //
+  /** The rdf namespace prefix. */
+  public static final String RDF = "rdf";
+
+  /** The rdfs namespace prefix. */
+  public static final String RDFS = "rdfs";
+
+  /** The owl namespace prefix. */
+  public static final String OWL = "owl";
+
+  /** The mulgara namespace prefix. */
+  public static final String MULGARA = "mulgara";
+
+  /** The krule namespace prefix. */
+  public static final String KRULE = "krule";
+
+  /** The URI of the rdf namespace. */
+  public static final String RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+
+  /** The URI of the rdfs namespace. */
+  public static final String RDFS_NS = "http://www.w3.org/2000/01/rdf-schema#";
+
+  /** The URI of the owl namespace. */
+  public static final String OWL_NS = "http://www.w3.org/2002/07/owl#";
+
+  /** The URI of the mulgara namespace. */
+  public static final String MULGARA_NS = "http://mulgara.org/mulgara#";
+
+  /** The URI of the krule namespace. */
+  public static final String KRULE_NS = "http://mulgara.org/owl/krule/#";
+
+  /**
+   * Construct a {@link LiteralImpl} from a {@link PLiteral}.
+   *
+   * @param p  the instance to convert
+   */
+  public LiteralImpl toLiteralImpl(PLiteral p);
+
+  /**
+   * Returns an anonymous variable unique for this interpreter.
+   * Note: We really should introduce a new subclass of Variable
+   * that is explicitly anonymous, but for now this will do.
+   */
+  public Variable nextAnonVariable();
+
+  /**
+   * Executes a query and returns its results.
+   *
+   * @param rawQuery a select query, represented as either a {@link
+   *      org.mulgara.itql.node.ASelectCommand} or a {@link
+   *      org.mulgara.itql.node.ASelectSetOfTriples}
+   * @return the answer to the query
+   * @throws QueryException if the query cannot be executed
+   * @throws URISyntaxException if the <code>query</code> contains a resource
+   *      whose text violates <a href="http://www.isi.edu/in-notes/rfc2396.txt">
+   *      RFC\uFFFD2396</a>
+   */
+  public Query buildQuery(org.mulgara.itql.node.Node rawQuery) throws QueryException,
+      URISyntaxException;
+
+  /**
+   * Convert SableCC-generated {@link TResource} tokens into {@link URI}s.
+   *
+   * Resolution will treat the token as an XML
+   * <a href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">qualified
+   * names</a> if the {@link #aliasMap} <code>aliasMap</code> contains a key
+   * for the URI scheme part that can be treated as an XML namespace prefix.
+   * For example, <kbd>dc:title</kbd> is treated as a qname and mapped to the
+   * to the URI <kbd>http://purl.org/dc/elements/1.1/title</kbd>, assuming the
+   * {@link #aliasMap} had an entry mapping <code>"dc"</code> to the Dublin
+   * Core namespace.
+   *
+   * @param token  the token to be converted, which should actually be a
+   *   {@link TResource}
+   * @throws Error if the <var>token</var> text isn't syntactically
+   *   a {@link URI}; this shouldn't ever occur, assuming the <var>token</var>
+   *   is a {@link TResource}
+   */
+  URI toURI(Token token);
+
+}
\ No newline at end of file

Modified: branches/nw-interface/src/jar/itql/java/org/mulgara/itql/ItqlInterpreter.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/itql/ItqlInterpreter.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/itql/ItqlInterpreter.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -90,7 +90,7 @@
  * @copyright &copy;2005 <a href="mailto:pgearon at users.sourceforge.net">Paul Gearon</a>
  * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
  */
-public class ItqlInterpreter extends DepthFirstAdapter {
+public class ItqlInterpreter extends DepthFirstAdapter implements Interpreter {
 
   //
   // Constants
@@ -1353,8 +1353,7 @@
       if (databaseURI == null) {
         return;
       }
-    }
-    else {
+    } else {
       if (serverURI.equals(databaseURI)) {
         return;
       }
@@ -1370,8 +1369,7 @@
     // Switch the underlying session to point at the required server
     if (databaseURI == null) {
       setSession(null, null);
-    }
-    else {
+    } else {
       if (providedSession != null) {
         if (session != providedSession) {
           session = providedSession;
@@ -1398,11 +1396,9 @@
           }
 
           setSession(session, sessionFactory.getSecurityDomain());
-        }
-        catch (SessionFactoryFinderException e) {
+        } catch (SessionFactoryFinderException e) {
           throw new QueryException("Unable to reconnect to " + databaseURI, e);
-        }
-        catch (NonRemoteSessionException e) {
+        } catch (NonRemoteSessionException e) {
           throw new QueryException("Error connecting to the local server", e);
         }
       }
@@ -1605,7 +1601,7 @@
 
     // get the type of model to create; default to mulgara:Model is unspecified
     URI modelTypeURI = (node.getModelType() == null)
-        ? Session.MULGARA_MODEL_URI
+        ? Session.MULGARA_GRAPH_URI
         : toURI(node.getModelType());
 
     try {

Modified: branches/nw-interface/src/jar/itql/java/org/mulgara/itql/ModelExpressionBuilder.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/itql/ModelExpressionBuilder.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/itql/ModelExpressionBuilder.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -94,6 +94,8 @@
    * org.mulgara.itql.node.PModelExpression}, using an <code>aliasMap</code>
    * to resolve aliases.
    *
+   * TODO: aliasMap is currently ignored!
+   * 
    * @param aliasMap the map from targets to aliases
    * @param expression a model expression from the parser
    * @return RETURNED VALUE TO DO
@@ -103,7 +105,7 @@
    *      a resource whose text violates <a
    *      href="http://www.isi.edu/in-notes/rfc2396.txt">RFC?2396</a>
    */
-  public static ModelExpression build(Map aliasMap,
+  public static ModelExpression build(Map<String,URI> aliasMap,
     PModelExpression expression) throws QueryException, URISyntaxException {
 
     // validate aliasMap parameter
@@ -126,7 +128,7 @@
     }
 
     // build the model expression from the parser input
-    ModelExpression modelExpression = buildModelExpression(expression);
+    ModelExpression modelExpression = buildModelExpression(expression, aliasMap);
 
     // logger that we've building successfully built a model expression
     if (logger.isDebugEnabled()) {
@@ -156,7 +158,7 @@
    *      href="http://www.isi.edu/in-notes/rfc2396.txt">RFC?2396</a>
    */
   private static ModelExpression buildModelExpression(
-    PModelExpression rawModelExpression)
+    PModelExpression rawModelExpression, Map<String,URI> aliasMap)
     throws QueryException, URISyntaxException {
 
     // validate the rawModelExpression parameter
@@ -198,8 +200,8 @@
       }
 
       // get the LHS and RHS operands of the union
-      ModelExpression lhs = buildModelExpression(orModelExpression);
-      ModelExpression rhs = buildModelExpression(modelTerm);
+      ModelExpression lhs = buildModelExpression(orModelExpression, aliasMap);
+      ModelExpression rhs = buildModelExpression(modelTerm, aliasMap);
 
       // logger that we've resolved the operands
       if (logger.isDebugEnabled()) {
@@ -209,8 +211,7 @@
 
       // apply the union
       modelExpression = new ModelUnion(lhs, rhs);
-    }
-    else if (rawModelExpression instanceof ATermModelExpression) {
+    } else if (rawModelExpression instanceof ATermModelExpression) {
 
       // logger that we've got a term model expression
       if (logger.isDebugEnabled()) {
@@ -218,8 +219,7 @@
       }
 
       // get the model term
-      PModelTerm modelTerm =
-        ((ATermModelExpression) rawModelExpression).getModelTerm();
+      PModelTerm modelTerm = ((ATermModelExpression)rawModelExpression).getModelTerm();
 
       // logger that we're about to resolve the term into an expression
       if (logger.isDebugEnabled()) {
@@ -227,7 +227,7 @@
       }
 
       // drill down into the model term
-      modelExpression = buildModelExpression(modelTerm);
+      modelExpression = buildModelExpression(modelTerm, aliasMap);
     }
 
     // end if
@@ -263,8 +263,9 @@
    *      a resource whose text violates <a
    *      href="http://www.isi.edu/in-notes/rfc2396.txt">RFC?2396</a>
    */
-  private static ModelExpression buildModelExpression(PModelTerm rawModelTerm)
-    throws QueryException, URISyntaxException {
+  private static ModelExpression buildModelExpression(
+      PModelTerm rawModelTerm, Map<String,URI> aliasMap
+    ) throws QueryException, URISyntaxException {
 
     // validate the rawModelTerm parameter
     if (rawModelTerm == null) {
@@ -299,20 +300,20 @@
       }
 
       // drill down into the model part
-      modelExpression = buildModelExpression(modelPart);
-    }
-    else if (rawModelTerm instanceof AAndModelTerm) {
+      modelExpression = buildModelExpression(modelPart, aliasMap);
 
+    } else if (rawModelTerm instanceof AAndModelTerm) {
+
       // logger that we've got a AND model term
       if (logger.isDebugEnabled()) {
         logger.debug("Found AND contraint term " + rawModelTerm);
       }
 
       // get the model term
-      PModelTerm modelTerm = ((AAndModelTerm) rawModelTerm).getModelTerm();
+      PModelTerm modelTerm = ((AAndModelTerm)rawModelTerm).getModelTerm();
 
       // get the model part
-      PModelPart modelPart = ((AAndModelTerm) rawModelTerm).getModelPart();
+      PModelPart modelPart = ((AAndModelTerm)rawModelTerm).getModelPart();
 
       // logger that we've found the operands of the union
       if (logger.isDebugEnabled()) {
@@ -321,8 +322,8 @@
       }
 
       // get the LHS and RHS operands of the intersection
-      ModelExpression lhs = buildModelExpression(modelTerm);
-      ModelExpression rhs = buildModelExpression(modelPart);
+      ModelExpression lhs = buildModelExpression(modelTerm, aliasMap);
+      ModelExpression rhs = buildModelExpression(modelPart, aliasMap);
 
       // logger that we've resolved the operands
       if (logger.isDebugEnabled()) {
@@ -338,8 +339,7 @@
     // we should not be returning null
     if (modelExpression == null) {
 
-      throw new QueryException("Unable to parse ITQL model term " +
-        "into a valid model expression");
+      throw new QueryException("Unable to parse ITQL model term into a valid model expression");
     }
 
     // end if
@@ -367,8 +367,9 @@
    *      a resource whose text violates <a
    *      href="http://www.isi.edu/in-notes/rfc2396.txt">RFC?2396</a>
    */
-  private static ModelExpression buildModelExpression(PModelPart rawModelPart)
-    throws QueryException, URISyntaxException {
+  private static ModelExpression buildModelExpression(
+      PModelPart rawModelPart, Map<String,URI> aliasMap
+    ) throws QueryException, URISyntaxException {
 
     // validate the rawModelPart parameter
     if (rawModelPart == null) {
@@ -394,8 +395,7 @@
       }
 
       // get the model factor
-      PModelFactor modelFactor =
-        ((AFactorModelPart) rawModelPart).getModelFactor();
+      PModelFactor modelFactor = ((AFactorModelPart)rawModelPart).getModelFactor();
 
       // logger that we're recursing with a model factor
       if (logger.isDebugEnabled()) {
@@ -403,9 +403,8 @@
       }
 
       // drill down into the model part
-      modelExpression = buildModelExpression(modelFactor);
-    }
-    else if (rawModelPart instanceof AXorModelPart) {
+      modelExpression = buildModelExpression(modelFactor, aliasMap);
+    } else if (rawModelPart instanceof AXorModelPart) {
 
       // logger that we've got a AND model term
       if (logger.isDebugEnabled()) {
@@ -413,21 +412,19 @@
       }
 
       // get the model term
-      PModelPart modelPart = ((AXorModelPart) rawModelPart).getModelPart();
+      PModelPart modelPart = ((AXorModelPart)rawModelPart).getModelPart();
 
       // get the model factor
-      PModelFactor modelFactor =
-        ((AXorModelPart) rawModelPart).getModelFactor();
+      PModelFactor modelFactor = ((AXorModelPart)rawModelPart).getModelFactor();
 
       // logger that we've found the operands of the union
       if (logger.isDebugEnabled()) {
-        logger.debug("Recursing with model part " + modelPart + " & model factor " +
-          modelFactor);
+        logger.debug("Recursing with model part " + modelPart + " & model factor " + modelFactor);
       }
 
       // get the LHS and RHS operands of the intersection
-      ModelExpression lhs = buildModelExpression(modelPart);
-      ModelExpression rhs = buildModelExpression(modelFactor);
+      ModelExpression lhs = buildModelExpression(modelPart, aliasMap);
+      ModelExpression rhs = buildModelExpression(modelFactor, aliasMap);
 
       // logger that we've resolved the operands
       if (logger.isDebugEnabled()) {
@@ -443,8 +440,7 @@
     // we should not be returning null
     if (modelExpression == null) {
 
-      throw new QueryException("Unable to parse ITQL model term " +
-        "into a valid model expression");
+      throw new QueryException("Unable to parse ITQL model term into a valid model expression");
     }
 
     // end if
@@ -473,13 +469,13 @@
    *      href="http://www.isi.edu/in-notes/rfc2396.txt">RFC?2396</a>
    */
   private static ModelExpression buildModelExpression(
-    PModelFactor rawModelFactor) throws QueryException, URISyntaxException {
+        PModelFactor rawModelFactor, Map<String,URI> aliasMap
+      ) throws QueryException, URISyntaxException {
 
     // validate the rawModelFactor parameter
     if (rawModelFactor == null) {
 
-      throw new IllegalArgumentException("Null \"rawModelFactor\" " +
-        "parameter");
+      throw new IllegalArgumentException("Null \"rawModelFactor\" parameter");
     }
 
     // end if
@@ -500,8 +496,7 @@
       }
 
       // get the resource
-      String resource =
-        ((AResourceModelFactor) rawModelFactor).getResource().getText();
+      String resource = ((AResourceModelFactor)rawModelFactor).getResource().getText();
 
       // logger that we've found a resource
       if (logger.isDebugEnabled()) {
@@ -509,10 +504,9 @@
       }
 
       // this resource is what we're looking for
-      URI modelURI = new URI(resource);
+      URI modelURI = URIUtil.convertToURI(resource, aliasMap);
       modelExpression = new ModelResource(ServerURIHandler.removePort(modelURI));
-    }
-    else if (rawModelFactor instanceof AExpressionModelFactor) {
+    } else if (rawModelFactor instanceof AExpressionModelFactor) {
 
       // logger that we've got an expression model factor
       if (logger.isDebugEnabled()) {
@@ -520,8 +514,7 @@
       }
 
       // get the model expression
-      PModelExpression embeddedModelExpression =
-        ((AExpressionModelFactor) rawModelFactor).getModelExpression();
+      PModelExpression embeddedModelExpression = ((AExpressionModelFactor)rawModelFactor).getModelExpression();
 
       // logger that we're recursing with a model expression
       if (logger.isDebugEnabled()) {
@@ -529,7 +522,7 @@
       }
 
       // build the model expression
-      modelExpression = buildModelExpression(embeddedModelExpression);
+      modelExpression = buildModelExpression(embeddedModelExpression, aliasMap);
     }
 
     // end if

Added: branches/nw-interface/src/jar/itql/java/org/mulgara/itql/TqlInterpreter.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/itql/TqlInterpreter.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/itql/TqlInterpreter.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -0,0 +1,2726 @@
+/*
+ * 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):
+ *  Copywrite in the anon-variable support:
+ *  The Australian Commonwealth Government
+ *  Department of Defense
+ *  Developed by Netymon Pty Ltd
+ *  under contract 4500507038
+ *  contributed to the Mulgara Project under the 
+ *    Mozilla Public License version 1.1
+ *  per clause 4.1.3 and 4.1.4 of the above contract.
+ *
+ * [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.itql;
+
+// Java 2 standard packages
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.rmi.server.UnicastRemoteObject;
+import java.rmi.RemoteException;
+import java.rmi.NoSuchObjectException;
+
+// Third party packages
+import org.apache.log4j.Logger; // Apache Log4J
+import org.jrdf.graph.*; // JRDF
+
+// Locally written packages
+
+// Automatically generated packages (SableCC)
+import org.mulgara.itql.analysis.*;
+import org.mulgara.itql.lexer.*;
+import org.mulgara.itql.node.*;
+import org.mulgara.itql.parser.*;
+import org.mulgara.query.*;
+import org.mulgara.query.ast.ApplyRules;
+import org.mulgara.query.ast.CommandAst;
+import org.mulgara.query.ast.Commit;
+import org.mulgara.query.ast.CreateGraph;
+import org.mulgara.query.ast.DropGraph;
+import org.mulgara.query.ast.Help;
+import org.mulgara.query.ast.Quit;
+import org.mulgara.query.ast.Rollback;
+import org.mulgara.query.ast.SetUser;
+import org.mulgara.query.rdf.*;
+import org.mulgara.rules.*;
+import org.mulgara.server.NonRemoteSessionException;
+import org.mulgara.server.Session;
+import org.mulgara.server.SessionFactory;
+import org.mulgara.server.driver.SessionFactoryFinder;
+import org.mulgara.server.driver.SessionFactoryFinderException;
+
+// emory util package
+import edu.emory.mathcs.util.remote.io.*;
+import edu.emory.mathcs.util.remote.io.server.impl.*;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.ZipInputStream;
+
+/**
+ * Interactive TQL (ITQL) command interpreter.
+ * <p>
+ * Performs parsing and converting TQL requests to query objects for execution;
+ * Based on ItqlInterpreter.
+ * </p>
+ *
+ * @created 2007-08-09
+ * @author Paul Gearon
+ * @copyright &copy;2007 <a href="mailto:pgearon at users.sourceforge.net">Paul Gearon</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class TqlInterpreter extends DepthFirstAdapter implements Interpreter {
+
+  /** Get line separator. */
+  private static final String EOL = System.getProperty("line.separator");
+
+  /** The logger */
+  static final Logger logger = Logger.getLogger(TqlInterpreter.class.getName());
+
+  /** A constraint expression builder. */
+  private ConstraintExpressionBuilder builder = new ConstraintExpressionBuilder(this);
+
+  /** Variable factory for this interpreter. */
+  private VariableFactory variableFactory = new VariableFactoryImpl();
+
+  /** Lexer... */
+  Lexer2 lexer = new Lexer2();
+
+  //
+  // Members
+  //
+
+  /** The map from targets to aliases */
+  private Map<String,URI> aliasMap = null;
+
+  /** The log file to record all iTQL requests */
+  private PrintWriter itqlLog = null;
+
+  /** The location of the log iTQL file */
+  private String itqlLogFile = null;
+
+  /** The command for the callbacks to fill, while parseCommand is running */
+  CommandAst lastCommand = null;
+  
+  /** The last exception or error, to be filled in during the callback operations. */
+  Throwable lastError = null;
+
+  //
+  // Interpreter options
+  //
+
+
+  /** The next anonymous variable suffix. */
+  private int anonSuffix = 0;
+
+  //
+  // Constructors
+  //
+
+  /**
+   * Creates a new ITQL command interpreter.
+   *
+   * @param aliasMap the map from targets to aliases, never <code>null</code>
+   */
+  public TqlInterpreter(Map<String,URI> aliasMap) {
+
+    // validate aliasMap parameter
+    if (aliasMap == null) {
+      throw new IllegalArgumentException("Null \"alias\" parameter");
+    }
+
+    // set members
+    this.setAliasMap(aliasMap);
+
+    // log the creation of this interpreter
+    if (logger.isDebugEnabled()) {
+      logger.debug("Itql interpreter created");
+    }
+
+    // is this session configured for logging.
+    if (System.getProperty("itql.command.log") != null) {
+      itqlLogFile = System.getProperty("itql.command.log");
+      logger.info("iTQL command logging has been enabled.  Logging to " + System.getProperty("itql.command.log"));
+    }
+  }
+
+  /**   
+   * Set up default aliases.
+   *
+   * @return A map of aliases to their fully qualified names
+   */        
+  public static Map<String,URI> getDefaultAliases() {
+    Map<String,URI> aliases = new HashMap<String,URI>();
+    aliases.put(RDF, URI.create(RDF_NS));
+    aliases.put(RDFS, URI.create(RDFS_NS));
+    aliases.put(OWL, URI.create(OWL_NS));
+    aliases.put(MULGARA, URI.create(MULGARA_NS));
+    aliases.put(KRULE, URI.create(KRULE_NS));
+    return aliases;
+  }  
+
+
+  //
+  // Public API
+  //
+
+  /**
+   * Parses the given TQL command.
+   *
+   * @param command the command to parse in TQL syntax
+   * @return A {@link List} of ASTs, one for each command
+   * @throws ParserException if the syntax of the command is incorrect
+   * @throws LexerException if the syntax of the command is incorrect
+   * @throws IOException if the <var>command</var> cannot be paersed
+   * @throws IllegalArgumentException if the <var>command</var> is <code>null</code>
+   */
+  public List<CommandAst> parseCommand(String command) throws ParserException, LexerException, Exception {
+
+    // validate command parameter
+    if ((command == null) || command.equals("")) {
+      throw new IllegalArgumentException("Null \"command\" parameter");
+    }
+
+    // log that we're going to execute the command
+    if (logger.isDebugEnabled()) {
+      logger.debug("Parsing command " + command);
+    }
+
+    // log the iTQL command - system property itql.command.log must be set
+    this.logItql(command);
+
+    // Reset the variable incrementer in the query.
+    variableFactory.reset();
+
+    // push the command into the lexer
+    lexer.add(command);
+    
+    // create a list of AST versions of the command
+    List<CommandAst> commandList = new LinkedList<CommandAst>();
+
+    // if the lexer saw terminators, parse the associated commands
+    while (lexer.nextCommand()) {
+
+      Start commandTree = null;
+
+      // parse the command
+      try {
+        Parser parser = new Parser(lexer);
+        commandTree = parser.parse();
+        
+      } catch (ParserException pe) {
+        // clear the parser
+        flush();
+        throw pe;
+        
+      } catch (LexerException le) {
+
+        // clear the parser
+        flush();
+        throw le;
+      }
+
+      // build the command
+      try {
+        // this populates lastCommand
+        resetInterpreter();
+        commandTree.apply(this);
+        // take the lastCommand result, and add it to the list of results
+        commandList.add(lastCommand);
+      } catch (Exception e) {
+        flush();
+        throw e;
+      } catch (Error e) {
+        flush();
+        throw e;
+      }
+
+      if (logger.isDebugEnabled()) {
+        logger.debug("Successfully parsed command " + command);
+      }
+    }
+    return commandList;
+  }
+
+  /**
+   * Discard any unparsed tokens.
+   *
+   */
+  private void flush() {
+    lexer.leftoverTokenList.clear();
+  }
+
+  // isQuitRequested()
+
+  /**
+   * Parse a string into a {@link Query}.  Convenience method over parseCommand.
+   *
+   * @param queryString a string containing an ITQL query
+   * @return the corresponding {@link Query} instance
+   * @throws IOException if <var>queryString</var> can't be buffered.
+   * @throws LexerException if <var>queryString</var> can't be tokenized.
+   * @throws ParserException if <var>queryString</var> is not syntactic.
+   */
+  public Query parseQuery(String queryString) throws IOException,
+      LexerException, ParserException {
+
+    if (queryString == null) {
+      throw new IllegalArgumentException("Null \"queryString\" parameter");
+    }
+
+    // clean up query
+    queryString = queryString.trim();
+    while (queryString.endsWith(";")) {
+      queryString = queryString.substring(0, queryString.length() - 1);
+    }
+
+    // log that we're going to execute the command
+    if (logger.isDebugEnabled()) {
+      logger.debug("Parsing query \"" + queryString + "\"");
+    }
+
+    // execute the command
+    Parser parser = new Parser(new Lexer(new PushbackReader(new StringReader(queryString), 256)));
+    resetInterpreter();
+    parser.parse().apply(this);
+
+    if (lastCommand == null) throw new ParserException(null, "Parameter was not a query");
+
+    // return the results of the command
+    if (!(lastCommand instanceof Query)) throw new IllegalArgumentException("Command was not a query: " + queryString);
+    return (Query)lastCommand;
+  }
+
+
+  //
+  // Methods overridden from DepthFirstAdapter
+  // Provides callback mechanism for SableCC
+  //
+
+  /**
+   * Displays help information to the user.
+   *
+   * @param node the help command
+   */
+  public void outAHelpCommand(AHelpCommand node) {
+
+    // log the command
+    if (logger.isDebugEnabled()) logger.debug("Processing help command " + node);
+
+    lastCommand = new Help(node.getCommandPrefix());
+  }
+
+
+  /**
+   * Quits a session.
+   *
+   * @param node the quit command
+   */
+  public void outAQuitCommand(AQuitCommand node) {
+
+    // log the command
+    if (logger.isDebugEnabled()) logger.debug("Processing quit command " + node);
+
+    lastCommand = new Quit();
+  }
+
+
+  /**
+   * Commits a transaction.
+   *
+   * @param node the commit command
+   */
+  public void outACommitCommand(ACommitCommand node) {
+
+    // log the command
+    if (logger.isDebugEnabled()) logger.debug("Processing commit command " + node);
+
+    lastCommand = new Commit();
+  }
+
+
+  /**
+   * Rolls back a transaction.
+   *
+   * @param node the rollback command
+   */
+  public void outARollbackCommand(ARollbackCommand node) {
+
+    // log the command
+    if (logger.isDebugEnabled()) logger.debug("Processing rollback command " + node);
+    lastCommand = new Rollback();
+  }
+
+
+  /**
+   * Creates a query.
+   *
+   * @param node the query command
+   */
+  public void outASelectCommand(ASelectCommand node) {
+
+    // log the command
+    if (logger.isDebugEnabled()) logger.debug("Processing select command " + node);
+
+    resetInterpreter();
+
+    // build the query
+    try {
+      lastCommand = this.buildQuery(node.getQuery());
+    } catch (QueryException qe) {
+      logger.warn("Couldn't answer query", qe);
+      lastError = qe;
+    } catch (URISyntaxException use) {
+      logger.warn("Invalid resource URI. " + use.getMessage());
+      lastError = use;
+    }
+  }
+
+
+  /**
+   * Substitutes the user associated with this session.
+   *
+   * @param node the su command
+   */
+  public void outASuCommand(ASuCommand node) {
+
+    // log the command
+    if (logger.isDebugEnabled()) logger.debug("Processing su command " + node);
+
+    lastCommand = new SetUser(node.getUser().getText(), node.getPassword().getText(), toURI(node.getResource()));
+  }
+
+
+  /**
+   * Associates an alias prefix with a target.
+   *
+   * @param node the alias command
+   */
+  public void outAAliasCommand(AAliasCommand node) {
+
+    // log the command
+    if (logger.isDebugEnabled()) logger.debug("Processing alias command " + node);
+
+    // get the prefix and target
+    String aliasPrefix = node.getPrefix().getText();
+    String aliasTarget = node.getTarget().getText();
+
+    try {
+
+      // convert the target to a URI
+      URI aliasTargetURI = new URI(aliasTarget);
+
+      // log the conversion
+      if (logger.isDebugEnabled()) logger.debug("Converted " + aliasTarget + " to URI " + aliasTargetURI);
+
+      // add the alias pair to the map
+      this.addAliasPair(aliasPrefix, aliasTargetURI);
+
+      // log that we've added the pair to the map
+      if (logger.isDebugEnabled()) logger.debug("Aliased " + aliasTarget + " as " + aliasPrefix);
+
+    } catch (URISyntaxException use) {
+      // log the failed URI creation
+      logger.warn("Unable to create URI from alias target " + aliasTarget);
+    }
+  }
+
+
+  /**
+   * Applies a set of rules in a model to data in another model.
+   *
+   * @param node the alias command
+   */
+  public void outAApplyCommand(AApplyCommand node) {
+
+    // log the command
+    if (logger.isDebugEnabled()) logger.debug("Processing apply command " + node);
+
+    // get the rule graph and target graph
+    URI ruleGraph = toURI(node.getRules());
+    URI baseGraph = toURI(node.getBase());
+    Token dest = node.getDestination();
+    URI destGraph = (dest == null) ? baseGraph : toURI(dest);
+
+    lastCommand = new ApplyRules(ruleGraph, baseGraph, destGraph);
+  }
+
+
+  /**
+   * Creates a new database/model.
+   *
+   * @param node the create command
+   */
+  public void outACreateCommand(ACreateCommand node) {
+
+    // log the command
+    if (logger.isDebugEnabled()) logger.debug("Processing create command " + node);
+
+    // get the name of the model to create
+    URI graphURI = toURI(node.getModel());
+
+    // get the type of model to create; default to mulgara:Model is unspecified
+    URI graphTypeURI = (node.getModelType() == null)
+        ? Session.MULGARA_GRAPH_URI
+        : toURI(node.getModelType());
+
+    // log that we're asking the driver to create the resource
+    if (logger.isDebugEnabled()) logger.debug("Creating new graph " + graphURI);
+
+    graphURI = getCanonicalUriAlias(graphURI);
+
+    if (logger.isDebugEnabled()) logger.debug("Model is alias for " + graphURI);
+
+    lastCommand = new CreateGraph(graphURI, graphTypeURI);
+  }
+
+  /**
+   * Drop (delete) a database/model.
+   *
+   * @param node the drop command
+   */
+  public void outADropCommand(ADropCommand node) {
+
+    // log the command
+    if (logger.isDebugEnabled()) logger.debug("Processing drop command " + node);
+
+    // get the name of the database/model to drop
+    lastCommand = new DropGraph(toURI(node.getResource()));
+  }
+
+  /**
+   * Load the contents of a file into a database/model.
+   *
+   * @param node the load command
+   */
+  public void outALoadCommand(ALoadCommand node) {
+
+    this.setLastError(null);
+    this.setLastAnswer(null);
+    this.setLastMessage("");
+
+    RemoteInputStream remoteInputStream = null;
+    RemoteInputStreamSrvImpl srv = null;
+
+    // log the command
+    if (logger.isDebugEnabled()) {
+
+      logger.debug("Processing load command " + node);
+    }
+
+    // get constituents of the load command
+    URI sourceURI = toURI(node.getSource());
+    URI destinationURI = toURI(node.getDestination());
+
+    try {
+
+      long stmtCount = 0;
+
+      // update the session
+      this.updateSession(new ModelResource(destinationURI));
+
+
+      // are we loading the file locally from the client?
+      if ( node.getLocality() != null &&
+           (node.getLocality() instanceof ALocalLocality) ) {
+
+        if ( logger.isInfoEnabled() ) {
+          logger.info("loading local resource : " + sourceURI );
+        }
+
+        try {
+
+          //open an InputStream
+          InputStream inputStream = sourceURI.toURL().openStream();
+
+          //is the file/stream compressed?
+          String path = (sourceURI == null) ? "" : sourceURI.toString();
+          inputStream = adjustForCompression(path, inputStream);
+
+          // open and wrap the inputstream
+          srv = new RemoteInputStreamSrvImpl(inputStream);
+
+          // prepare it for exporting
+          UnicastRemoteObject.exportObject(srv);
+
+          remoteInputStream = new RemoteInputStream(srv);
+
+          // modify the database
+          stmtCount =
+              this.getSession().setModel(remoteInputStream,
+                                         destinationURI, // model to redefine
+                                         new ModelResource(sourceURI));
+        }
+        catch (IOException ex) {
+          logger.error("Error attempting to load : " + sourceURI, ex);
+          throw new QueryException("Error attempting to load : " + sourceURI, ex);
+        } finally {
+          if ( srv != null ) {
+            try {
+              UnicastRemoteObject.unexportObject(srv, false);
+            } catch ( NoSuchObjectException ex ) {};
+          }
+        }
+      }
+      else {
+
+        if ( logger.isInfoEnabled() ) {
+          logger.info("loading remote resource : " + sourceURI );
+        }
+
+        // modify the database using a remote file located on the server
+        // default behaviour
+
+        stmtCount =
+            this.getSession().setModel(destinationURI, // model to redefine
+                                       new ModelResource(sourceURI));
+      }
+      update();
+
+      // log that we've loaded the contents of the file
+      if (logger.isDebugEnabled()) {
+
+        logger.debug("Loaded " + stmtCount + " statements from " + sourceURI +
+                     " into " + destinationURI);
+      }
+
+      // tell the user
+      if (stmtCount > 0L) {
+
+        this.setLastMessage("Successfully loaded " + stmtCount +
+                            " statements from " + sourceURI + " into " +
+                            destinationURI);
+      }
+      else {
+
+        this.setLastMessage("WARNING: No valid RDF statements found in " +
+                            sourceURI);
+      } // end if
+    }
+    catch (QueryException qe) {
+
+      // let the user know the problem
+      this.setLastError(qe);
+      this.setLastAnswer(null);
+      this.setLastMessage("Could not load " + sourceURI + " into " +
+                          destinationURI + EOL + this.getCause(qe, 2));
+      logger.warn("Failed to load " + sourceURI + " into " + destinationURI,
+                  qe);
+    }
+    catch (RuntimeException re) {
+
+      // let the user know the problem
+      this.setLastError(re);
+      this.setLastAnswer(null);
+      this.setLastMessage("Failed to load statements:" + this.getCause(re, 0));
+      logger.fatal("Failed to load statements", re);
+    }
+    finally {
+
+      // close the inputstream in-case the server was not able to
+      // complete the task.
+      if ( remoteInputStream != null ) {
+        try {
+          remoteInputStream.close();
+        } catch ( Exception ex ) {};
+      }
+
+    }
+    // try-catch
+
+  }
+
+  // outALoadCommand()
+
+  /**
+   * Executes an iTQL script.
+   *
+   * @param node the execute command
+   */
+  public void outAExecuteCommand(AExecuteCommand node) {
+
+    this.setLastError(null);
+    this.setLastAnswer(null);
+    this.setLastMessage("");
+
+    // log the command
+    if (logger.isDebugEnabled()) {
+
+      logger.debug("Processing execute command " + node);
+    }
+
+    // get the name of the script to execute
+    String resource = node.getResource().getText();
+
+    // keep a record of the line number
+    int line = 0;
+
+    try {
+
+      // convert the script to a URL
+      URL scriptURL = new URL(resource);
+
+      // log that we're executing a script
+      if (logger.isDebugEnabled()) {
+
+        logger.debug("Executing  script " + scriptURL);
+      }
+
+      // create a buffer to hold the results in
+      StringBuffer resultsMsg = new StringBuffer();
+
+      // create a reader to read the contents of the script
+      BufferedReader scriptIn =
+          new BufferedReader(new InputStreamReader(scriptURL.openStream()));
+
+      // execute the script!
+      String command = scriptIn.readLine();
+
+      while (command != null) {
+
+        // increment the line number
+        line++;
+
+        if (!command.equals("")) {
+
+          // execute the command
+          executeCommand(command);
+        }
+
+        // end if
+        // get the next command
+        command = scriptIn.readLine();
+      }
+
+      // end if
+      // tell the user
+      resultsMsg.append("Completed execution of script " + resource);
+      this.setLastMessage(resultsMsg.toString());
+    }
+    catch (ParserException pe) {
+
+      // let the user know the problem
+      this.setLastError(pe);
+      this.setLastAnswer(null);
+      this.setLastMessage("Syntax error in script (line " + line + "): " +
+                          pe.getMessage());
+      logger.warn("Unable to execute script - " + resource + EOL +
+                  this.getCause(pe, 0));
+    }
+    catch (LexerException le) {
+
+      // let the user know the problem
+      this.setLastError(le);
+      this.setLastAnswer(null);
+      this.setLastMessage("Syntax error in script (line " + line + "): " +
+                          le.getMessage());
+      logger.warn("Unable to execute script - " + resource + EOL +
+                  this.getCause(le, 0));
+    }
+    catch (MalformedURLException mue) {
+
+      // let the user know the problem
+      this.setLastError(mue);
+      this.setLastAnswer(null);
+      this.setLastMessage("Could not execute script: Invalid script URL.");
+      logger.warn("Invalid script source URL." + EOL + this.getCause(mue, 0));
+    }
+    catch (Exception e) {
+
+      // let the user know the problem
+      this.setLastError(e);
+      this.setLastAnswer(null);
+      this.setLastMessage("Could not execute script." + EOL +
+                          this.getCause(e, 0));
+      logger.error("Unable to execute script - " + resource + EOL +
+                   this.getCause(e, 0));
+    }
+    // try-catch
+  }
+
+  // outAExecuteCommand()
+
+  /**
+   * Inserts a triple, model, database or the results of a query into a model or
+   * database.
+   *
+   * @param node the insert command
+   */
+  public void outAInsertCommand(AInsertCommand node) {
+
+    this.setLastError(null);
+    this.setLastAnswer(null);
+    this.setLastMessage("");
+
+    // log the command
+    if (logger.isDebugEnabled()) {
+
+      logger.debug("Processing insert command " + node);
+    }
+
+    // get the resource we're inserting data into
+    URI resourceURI = toURI(node.getResource());
+
+    try {
+
+      // log that we're inserting the statments
+      if (logger.isDebugEnabled()) {
+
+        logger.debug("Inserting statements into " + resourceURI);
+      }
+
+      // update the session
+      this.updateSession(new ModelResource(resourceURI));
+
+      // insert the statements into the model
+      insertStatements(resourceURI, node.getTripleFactor());
+      update();
+
+      // log that we've inserted the statments
+      if (logger.isDebugEnabled()) {
+
+        logger.debug("Completed inserting statements into " + resourceURI);
+      }
+
+      // tell the user
+      this.setLastMessage(
+          "Successfully inserted statements into " + resourceURI
+          );
+    }
+    catch (QueryException qe) {
+
+      // let the user know the problem
+      this.setLastError(qe);
+      this.setLastAnswer(null);
+      this.setLastMessage("Could not insert statements into " + resourceURI +
+                          EOL + this.getCause(qe, 2));
+      logger.warn("Failed to insert statements into " + resourceURI, qe);
+    }
+    catch (URISyntaxException use) {
+
+      // let the user know the problem
+      this.setLastError(use);
+      this.setLastAnswer(null);
+      this.setLastMessage("Could not insert into resource: Invalid resource " +
+                          "URI.");
+      logger.warn("Invalid resource URI." + EOL + this.getCause(use, 0));
+    }
+    catch (RuntimeException re) {
+
+      // let the user know the problem
+      this.setLastError(re);
+      this.setLastAnswer(null);
+      this.setLastMessage("Failed to insert statements:" + this.getCause(re, 0));
+      logger.fatal("Failed to insert statements", re);
+    }
+  }
+
+  // outAInsertCommand()
+
+  /**
+   * Deletes a triple, model, database or the results of a query from a model or
+   * database.
+   *
+   * @param node the delete command
+   */
+  public void outADeleteCommand(ADeleteCommand node) {
+
+    this.setLastError(null);
+    this.setLastAnswer(null);
+    this.setLastMessage("");
+
+    // log the command
+    if (logger.isDebugEnabled()) {
+
+      logger.debug("Processing delete command " + node);
+    }
+
+    // get the resource we're deleting data from
+    URI resourceURI = toURI(node.getResource());
+
+    try {
+
+      // log that we're deleting the statments
+      if (logger.isDebugEnabled()) {
+
+        logger.debug("Deleting statements from " + resourceURI);
+      }
+
+      // update the session
+      this.updateSession(new ModelResource(resourceURI));
+
+      // delete the statements from the model
+      deleteStatements(resourceURI, node.getTripleFactor());
+      update();
+
+      // log that we've inserted the statments
+      if (logger.isDebugEnabled()) {
+
+        logger.debug("Completed deleting statements from " + resourceURI);
+      }
+
+      // tell the user
+      this.setLastMessage(
+          "Successfully deleted statements from " + resourceURI
+          );
+    }
+    catch (QueryException qe) {
+
+      // let the user know the problem
+      this.setLastError(qe);
+      this.setLastAnswer(null);
+      this.setLastMessage("Could not delete statements from " + resourceURI +
+                          EOL + this.getCause(qe, 2));
+      logger.warn("Failed to delete statements from " + resourceURI, qe);
+    }
+    catch (URISyntaxException use) {
+
+      // let the user know the problem
+      this.setLastError(use);
+      this.setLastAnswer(null);
+      this.setLastMessage("Could not delete from resource: Invalid resource " +
+                          "URI.");
+      logger.warn("Invalid resource URI." + EOL + this.getCause(use, 0));
+    }
+    catch (RuntimeException re) {
+
+      // let the user know the problem
+      this.setLastError(re);
+      this.setLastAnswer(null);
+      this.setLastMessage("Failed to delete statements:" + this.getCause(re, 0));
+      logger.fatal("Failed to delete statements", re);
+    }
+
+    // try-catch
+  }
+
+  // outADeleteCommand()
+
+  /**
+   * Sets an interpreter property.
+   *
+   * @param node the set command
+   */
+  public void outASetCommand(ASetCommand node) {
+
+    this.setLastError(null);
+    this.setLastAnswer(null);
+    this.setLastMessage("");
+
+    // log the command
+    if (logger.isDebugEnabled()) {
+
+      logger.debug("Processing set command " + node);
+    }
+
+    // get the option to set
+    PSetOption option = node.getSetOption();
+
+    // log that we've got the option
+    if (logger.isDebugEnabled()) {
+
+      logger.debug("Found option " + option);
+    }
+
+    // get the value
+    PSetOptionMode optionMode = node.getSetOptionMode();
+    boolean optionSet = false;
+
+    if (optionMode instanceof AOffSetOptionMode) {
+
+      optionSet = false;
+    }
+    else {
+
+      optionSet = true;
+    } // end if
+
+    // set the option
+    if (option instanceof ATimeSetOption) {
+
+      // set the time option
+      this.setTimeOption(optionSet);
+
+      // return the user a message
+      this.setLastMessage("Command timing is " + (optionSet ? "on" : "off"));
+    }
+    else if (option instanceof AAutocommitSetOption) {
+
+      /* Do not assume this.  As the server may have
+         encountered an error.
+      if (optionSet == autoCommit) {
+        if (logger.isDebugEnabled()) {
+          logger.debug("Autocommit option is already " + autoCommit);
+        } // end if
+        return;
+      }
+      */
+
+      try {
+
+        // log that we got a autocommit option
+        if (logger.isDebugEnabled()) {
+
+          logger.debug("Found autocommit option, setting to " +
+                       (optionSet ? "on" : "off"));
+        } // end if
+
+        // set the auto commit status
+        if (session != null) {
+          this.getSession().setAutoCommit(optionSet);
+          update();
+        }
+        autoCommit = optionSet;
+
+        if (logger.isDebugEnabled()) {
+          logger.debug("Set autocommit to " + (optionSet ? "on" : "off"));
+        }
+
+        // return the user a message
+        this.setLastMessage("Auto commit is " + (optionSet ? "on" : "off"));
+      }
+      catch (QueryException qe) {
+
+        // let the user know the problem
+        this.setLastError(qe);
+        this.setLastAnswer(null);
+        this.setLastMessage("Unable to set interpreter option" + EOL +
+                            this.getCause(qe, 2));
+        logger.warn("Unable to set interpreter property", qe);
+      }
+
+      // try-catch
+    }
+    else {
+
+      // this should never get through the parser, if it does it probably
+      // means the grammar has been updated
+      this.setLastMessage("Unknown interpreter option");
+    }
+
+    // end if
+    // log the option setting
+    if (logger.isDebugEnabled()) {
+
+      logger.debug(option + "has been set to " + optionSet);
+    }
+  }
+
+  // outASetCommand()
+
+  /**
+   * Backs up the contents of a server to a local or remote file.
+   *
+   * @param node the backup command
+   */
+  public void outABackupCommand(ABackupCommand node) {
+
+    this.setLastError(null);
+    this.setLastAnswer(null);
+    this.setLastMessage("");
+
+    RemoteOutputStream outputStream = null;
+    RemoteOutputStreamSrvImpl srv = null;
+
+    // log the command
+    if (logger.isDebugEnabled()) {
+
+      logger.debug("Processing backup command " + node);
+    }
+
+    // get the server we'll be backing up
+    URI sourceURI = toURI(node.getSource());
+
+    // get the resource we're writing to
+    URI destinationURI = toURI(node.getDestination());
+
+    try {
+
+      // set the server uri given a possible model
+      this.setBackupServer(sourceURI);
+
+      // are we backing up a file locally to the client?
+      if ( node.getLocality() != null &&
+           (node.getLocality() instanceof ALocalLocality) ) {
+
+        if ( logger.isInfoEnabled() ) {
+          logger.info("backing up local resource : " + sourceURI );
+        }
+
+        try {
+
+          // open and wrap the outputstream
+          srv = new RemoteOutputStreamSrvImpl(
+                  new FileOutputStream(destinationURI.getPath()));
+
+          // prepare it for exporting
+          UnicastRemoteObject.exportObject(srv);
+
+          outputStream = new RemoteOutputStream(srv);
+
+        }
+        catch (IOException ex) {
+          logger.error("Error attempting to backing up : " + sourceURI, ex);
+        }
+
+        try {
+
+          // back it up to the local file system
+          this.getSession().backup(sourceURI, outputStream);
+
+        } finally {
+
+          // ensure the stream is closed in case the server was not able
+          // to close it.
+          if ( outputStream != null ) {
+            try {
+              outputStream.close();
+            } catch ( IOException ioex ) {};
+            if ( srv != null ) {
+              try {
+                UnicastRemoteObject.unexportObject(srv, false);
+              } catch ( NoSuchObjectException ex ) {};
+            }
+          }
+        }
+
+      }
+      else {
+
+        // back it up via the server
+        this.getSession().backup(sourceURI, destinationURI);
+      }
+
+      // log that we've inserted the statments
+      if (logger.isDebugEnabled()) {
+
+        logger.debug("Completed backing up " + sourceURI +
+                     " to " + destinationURI);
+      }
+
+      // tell the user
+      this.setLastMessage("Successfully backed up " + sourceURI +
+                          " to " + destinationURI + ".");
+    }
+    catch (QueryException qe) {
+
+      // let the user know the problem
+      this.setLastError(qe);
+      this.setLastAnswer(null);
+      this.setLastMessage("Could not backup " + sourceURI + " to " +
+                          destinationURI + EOL + this.getCause(qe, 2) + ".");
+      logger.warn("Failed to backup server " + sourceURI + " to " +
+                  destinationURI,
+                  qe);
+    }
+
+    // try-catch
+  }
+
+  // outABackupCommand()
+
+  /**
+   * Restores the contents of a server from a file.
+   *
+   * @param node the restore command
+   */
+  public void outARestoreCommand(ARestoreCommand node) {
+
+    this.setLastError(null);
+    this.setLastAnswer(null);
+    this.setLastMessage("");
+
+    RemoteInputStream inputStream = null;
+    RemoteInputStreamSrvImpl srv = null;
+
+    // log the command
+    if (logger.isDebugEnabled()) {
+
+      logger.debug("Processing restore command " + node);
+    }
+
+    // get the server we'll be restoring to
+    URI destinationURI = toURI(node.getDestination());
+
+    // get the resource we're reading from
+    URI sourceURI = toURI(node.getSource());
+
+    try {
+
+      // log that we're backing up a server
+      if (logger.isDebugEnabled()) {
+
+        logger.debug("Restoring server " + destinationURI + " from " +
+                     sourceURI);
+      }
+
+      setServerURI(destinationURI);
+
+      // are we loading the file locally from the client?
+      if ( node.getLocality() != null &&
+           (node.getLocality() instanceof ALocalLocality) ) {
+
+        if ( logger.isInfoEnabled() ) {
+          logger.info("restoring local resource : " + sourceURI );
+        }
+
+        try {
+
+          // open and wrap the inputstream
+          srv = new RemoteInputStreamSrvImpl(sourceURI.toURL().openStream());
+
+          // prepare it for exporting
+          UnicastRemoteObject.exportObject(srv);
+
+          inputStream = new RemoteInputStream(srv);
+
+          // modify the database
+          this.getSession().restore( inputStream, destinationURI, sourceURI);
+        }
+        catch (IOException ex) {
+          logger.error("Error attempting to restore : " + sourceURI, ex);
+          throw new QueryException("Error attempting to restore : " + sourceURI, ex);
+        }
+        finally {
+          if ( srv != null ) {
+            try {
+              UnicastRemoteObject.unexportObject(srv, false);
+            } catch ( NoSuchObjectException ex ) {};
+          }
+        }
+      }
+      else {
+
+        // restore it from the server
+        this.getSession().restore(destinationURI, sourceURI);
+
+      }
+
+      update();
+
+      // log that we've inserted the statments
+      if (logger.isDebugEnabled()) {
+
+        logger.debug("Completed restoring " + destinationURI + " from " +
+                     sourceURI);
+      }
+
+      // tell the user
+      this.setLastMessage("Successfully restored " + destinationURI + " from " +
+                          sourceURI);
+    }
+    catch (QueryException qe) {
+
+      // let the user know the problem
+      this.setLastError(qe);
+      this.setLastAnswer(null);
+      this.setLastMessage("Could not restore " + destinationURI + " from " +
+                          sourceURI + EOL + this.getCause(qe, 2));
+      logger.warn("Failed to restore server " + destinationURI + " from " +
+                  sourceURI, qe);
+    }
+    finally {
+
+      // close the inputstream in-case the server was not able to
+      // complete the task.
+      if ( inputStream != null ) {
+        try {
+         inputStream.close();
+        }
+        catch ( Exception ex ) {};
+      }
+    }
+  }
+
+  /**
+   * Returns a set of statements from the iTQL query object.
+   *
+   * @param setOfTriples the set of statements defined in the query.
+   * @param variableMap the variable map to store the value of the variable
+   *   against the variable object.
+   * @throws URISyntaxException if <code>tripleFactor</code> contains a query or
+   *      a resource that that violates <a
+   *      href="http://www.isi.edu/in-notes/rfc2396.txt">RFC\uFFFD2396</a>
+   * @throws QueryException if an invalid node is used in the set of triples.
+   * @return a set of statements from the iTQL query.
+   */
+  @SuppressWarnings("unchecked")
+  public Set<org.jrdf.graph.Triple> getStatements(ATripleSetOfTriples setOfTriples, Map<String,VariableNodeImpl> variableMap)
+      throws QueryException, URISyntaxException {
+  
+    List<ATriple> tripleList = (List<ATriple>)setOfTriples.getTriple();
+    HashSet<org.jrdf.graph.Triple> statements = new HashSet<org.jrdf.graph.Triple>();
+  
+    // Check that each set of triples has the predicate bound.
+    for (Iterator<ATriple> i = tripleList.iterator(); i.hasNext(); ) {
+  
+      // get the triple
+      ATriple triple = i.next();
+  
+      // Convert the Subject, Predicate and Object.
+      org.jrdf.graph.Node subject = toNode(triple.getSubject(), variableMap);
+      org.jrdf.graph.Node predicate = toNode(triple.getPredicate(), variableMap);
+      org.jrdf.graph.Node object = toNode(triple.getObject(), variableMap);
+  
+      // Predicate cannot be a blank node.
+      if (predicate instanceof BlankNode) {
+        throw new QueryException("Predicate must be a valid URI");
+      }
+  
+      // Check that the subject or predicate node is not a literal.
+      if (subject instanceof LiteralImpl ||
+          predicate instanceof LiteralImpl) {
+  
+        // throw an exception indicating we have a bad triple
+        throw new QueryException(
+            "Subject or Predicate cannot be a literal");
+      }
+  
+      // Create a new statement using the triple elements
+      org.jrdf.graph.Triple jrdfTriple = new TripleImpl(
+          (SubjectNode) subject, (PredicateNode) predicate,
+          (ObjectNode) object);
+  
+      // add the statement to the statement set
+      statements.add(jrdfTriple);
+    }
+  
+    return statements;
+  }
+
+  /**
+   * Executes a query and returns its results.
+   *
+   * @param rawQuery a select query, represented as either a {@link
+   *      org.mulgara.itql.node.ASelectCommand} or a {@link
+   *      org.mulgara.itql.node.ASelectSetOfTriples}
+   * @return the answer to the query
+   * @throws QueryException if the query cannot be executed
+   * @throws URISyntaxException if the <code>query</code> contains a resource
+   *      whose text violates <a href="http://www.isi.edu/in-notes/rfc2396.txt">
+   *      RFC\uFFFD2396</a>
+   */
+  public Query buildQuery(org.mulgara.itql.node.Node rawQuery) throws
+      QueryException, URISyntaxException {
+  
+    // validate query parameter
+    if (rawQuery == null) {
+  
+      throw new IllegalArgumentException("Null \"rawQuery\" parameter");
+    }
+  
+    // end if
+    // create the variables needed...
+    LinkedList variables = null;
+    AFromClause fromClause;
+    AWhereClause whereClause;
+    AOrderClause orderClause;
+    AHavingClause havingClause;
+    ALimitClause limitClause;
+    AOffsetClause offsetClause;
+  
+    // cast the correct way (we don't have a common superclass, event though we
+    // have methods with the same names)
+    if (rawQuery instanceof AQuery) {
+  
+      AQuery query = (AQuery) rawQuery;
+      PSelectClause selectClause = query.getSelectClause();
+      if (selectClause instanceof ANormalSelectSelectClause) {
+        variables = ( (ANormalSelectSelectClause) selectClause).getElement();
+      }
+      fromClause = ( (AFromClause) query.getFromClause());
+      whereClause = ( (AWhereClause) query.getWhereClause());
+      orderClause = ( (AOrderClause) query.getOrderClause());
+      havingClause = ( (AHavingClause) query.getHavingClause());
+      limitClause = ( (ALimitClause) query.getLimitClause());
+      offsetClause = ( (AOffsetClause) query.getOffsetClause());
+    }
+    else if (rawQuery instanceof ASelectSetOfTriples) {
+  
+      ASelectSetOfTriples query = (ASelectSetOfTriples) rawQuery;
+      variables = new LinkedList();
+      variables.add(query.getSubject());
+      variables.add(query.getPredicate());
+      variables.add(query.getObject());
+      fromClause = ( (AFromClause) query.getFromClause());
+      whereClause = ( (AWhereClause) query.getWhereClause());
+      orderClause = ( (AOrderClause) query.getOrderClause());
+      havingClause = ( (AHavingClause) query.getHavingClause());
+      limitClause = ( (ALimitClause) query.getLimitClause());
+      offsetClause = ( (AOffsetClause) query.getOffsetClause());
+    }
+    else {
+  
+      // we only handle AQuery and ASelectSetOfTriples
+      throw new IllegalArgumentException("Invalid type for \"rawQuery\" " +
+                                         "parameter");
+    }
+  
+    if (fromClause == null) {
+  
+      throw new QueryException("FROM clause missing.");
+    }
+  
+    if (whereClause == null) {
+  
+      throw new QueryException("WHERE clause missing.");
+    }
+  
+    // end if
+    // log that we're about to build the variable list
+    if (logger.isDebugEnabled()) {
+      logger.debug("Building query variable list from " + variables);
+    }
+  
+    // build the variable list
+    List variableList = this.buildVariableList(variables);
+  
+    // log that we've built the variable list
+    if (logger.isDebugEnabled()) {
+      logger.debug("Built variable list " + variableList);
+    }
+  
+    // get the model expression from the parser
+    PModelExpression rawModelExpression = fromClause.getModelExpression();
+  
+    // log that we're about to build the model expression
+    if (logger.isDebugEnabled()) {
+      logger.debug("Building model expression from " + rawModelExpression);
+    }
+  
+    // parse the text into a model expression
+    ModelExpression modelExpression =
+        ModelExpressionBuilder.build(this.getAliasMap(), rawModelExpression);
+  
+    // log that we've built the model expression
+    if (logger.isDebugEnabled()) {
+      logger.debug("Built model expression " + modelExpression);
+    }
+  
+    // get the constraint expression from the parser
+    PConstraintExpression rawConstraintExpression =
+        whereClause.getConstraintExpression();
+  
+    // log that we're about to build the constraint expression
+    if (logger.isDebugEnabled()) {
+      logger.debug("Building constraint expression from " +
+                   rawConstraintExpression);
+    }
+  
+    // parse the text into a constraint expression
+    ConstraintExpression constraintExpression = build(rawConstraintExpression);
+  
+    // log that we've build the constraint expression
+    if (logger.isDebugEnabled()) {
+      logger.debug("Built constraint expression " + constraintExpression);
+    }
+  
+    // build the order list
+    List orderList = Collections.EMPTY_LIST;
+  
+    if (orderClause != null) {
+  
+      orderList = buildOrderList(orderClause.getOrderElement());
+    }
+  
+    // build the having clause
+    ConstraintHaving havingExpression = null;
+  
+    if (havingClause != null) {
+      // get the constraint expression from the parser
+      PConstraintExpression rawHavingExpression =
+          havingClause.getConstraintExpression();
+  
+      // log that we're about to build the constraint expression
+      if (logger.isDebugEnabled()) {
+        logger.debug("Building constraint expression from " +
+                     rawHavingExpression);
+      }
+  
+      // parse the text into a constraint expression
+      havingExpression = buildHaving(rawHavingExpression);
+    }
+  
+    // build the limit
+    Integer limit = null;
+  
+    if (limitClause != null) {
+  
+      try {
+  
+        limit = new Integer(limitClause.getNumber().getText());
+      }
+      catch (NumberFormatException e) {
+  
+        throw new Error("Sable parser permitted non-integer limit", e);
+      }
+    }
+  
+    // build the offset
+    int offset = 0;
+  
+    if (offsetClause != null) {
+  
+      try {
+  
+        offset = Integer.parseInt(offsetClause.getNumber().getText());
+      }
+      catch (NumberFormatException e) {
+  
+        throw new Error("Sable parser permitted non-integer offset", e);
+      }
+    }
+  
+    // build a query using the information we've obtained from the parser
+    // (all answers are acceptable)
+    lastQuery = new Query(variableList, modelExpression, constraintExpression,
+        havingExpression, orderList, limit, offset, new UnconstrainedAnswer());
+  
+    return lastQuery;
+  }
+
+  /* (non-Javadoc)
+   * @see org.mulgara.itql.QueryInterpreter#toLiteralImpl(org.mulgara.itql.node.PLiteral)
+   */
+  public LiteralImpl toLiteralImpl(PLiteral p) {
+  
+    ALiteral aLiteral = (ALiteral) p;
+  
+    // Determine the datatype URI, if present
+    URI datatypeURI = null;
+    if (aLiteral.getDatatype() != null) {
+      datatypeURI = toURI( ( (ADatatype) aLiteral.getDatatype()).getResource());
+    }
+  
+    // Determine the language code
+    String language = (datatypeURI == null) ? "" : null;
+  
+    if (datatypeURI == null) {
+      return new LiteralImpl(getLiteralText(aLiteral), language);
+    }
+    else {
+      return new LiteralImpl(getLiteralText(aLiteral), datatypeURI);
+    }
+  }
+
+  /* (non-Javadoc)
+   * @see org.mulgara.itql.QueryInterpreter#toURI(org.mulgara.itql.node.Token)
+   */
+  public URI toURI(Token token) {
+  
+    assert token instanceof TResource;
+    return URIUtil.convertToURI(token.getText(), aliasMap);
+  }
+
+  //
+  // Static methods brought in from the late ConstraintExpressionBuilder
+  //
+  
+  /**
+   * Builds a {@link org.mulgara.query.ConstraintExpression} object from a
+   * {@link org.mulgara.itql.node.PConstraintExpression}, using an <code>aliasMap</code>
+   * to resolve aliases.
+   *
+   * @param expression a constraint expression from the parser
+   * @return RETURNED VALUE TO DO
+   * @throws QueryException if <code>rawConstraintExpression</code> does not
+   *      represent a valid query
+   * @throws URISyntaxException if the <code>rawConstraintExpression</code>
+   *      contains a resource whose text violates <a
+   *      href="http://www.isi.edu/in-notes/rfc2396.txt">RFC?2396</a>
+   */
+  public ConstraintExpression build(PConstraintExpression expression) throws
+      QueryException, URISyntaxException {
+  
+    // validate aliasMap parameter
+    if (aliasMap == null) {
+      throw new IllegalArgumentException("Null \"aliasMap\" parameter");
+    }
+  
+    // validate expression parameter
+    if (expression == null) {
+      throw new IllegalArgumentException("Null \"expression\" parameter");
+    }
+  
+    // log that we're building a constraint expression
+    if (logger.isDebugEnabled()) {
+      logger.debug("Building constraint expression from " + expression);
+    }
+  
+    // build the contraint expression from the parser input
+    expression.apply( (Switch) builder);
+    ConstraintExpression constraintExpression = builder.
+        getConstraintExpression();
+  
+    // log that we've building successfully built a constraint expression
+    if (logger.isDebugEnabled()) {
+      logger.debug("Successfully built constraint expression from " +
+                   expression);
+    }
+  
+    // return the contraint expression
+    return constraintExpression;
+  }
+
+  /* (non-Javadoc)
+   * @see org.mulgara.itql.QueryInterpreter#nextAnonVariable()
+   */
+  public Variable nextAnonVariable() {
+    return new Variable("av__" + this.anonSuffix++);
+  }
+
+  /**
+   * Returns the text of the given <code>literal</code>.
+   *
+   * @param literal the literal to retrieve the text from
+   * @return The LiteralText value
+   */
+  public static String getLiteralText(ALiteral literal) {
+  
+    // validate the literal parameter
+    if (literal == null) {
+  
+      throw new IllegalArgumentException("Null \"literal\" " + "parameter");
+    }
+  
+    // end if
+    // the text of the literal
+    StringBuffer literalText = new StringBuffer();
+  
+    // get all the strands in this literal
+    List strands = literal.getStrand();
+  
+    // add each strand together to make the literal text
+    for (Iterator i = strands.iterator(); i.hasNext(); ) {
+  
+      // get the strand
+      PStrand strand = (PStrand) i.next();
+  
+      // add the strand to the literal text
+      if (strand instanceof AUnescapedStrand) {
+  
+        literalText.append( ( (AUnescapedStrand) strand).getText().getText());
+      }
+      else if (strand instanceof AEscapedStrand) {
+  
+        literalText.append( ( (AEscapedStrand) strand).getEscapedtext().getText());
+      } // end if
+  
+    } // end for
+  
+    // return the text
+    return literalText.toString();
+  }
+
+  /**
+   * Sets the error of the last query. Methods overriding <code>DepthFirstAdapter</code>
+   * are expected to set a result for successful queries, and <code>null</code>
+   * for failed ones.
+   *
+   * @param lastError the exception of the last command execution
+   */
+  void setLastError(Exception lastError) {
+
+    // carefully set the answer by value rather than reference
+    this.lastError =
+        (lastError == null) ? null : new ItqlInterpreterException(lastError);
+  }
+
+  /**
+   * Sets the results of the last command execution. Methods overriding <code>DepthFirstAdapter</code>
+   * are expected to set a results message, even if that message is null.
+   *
+   * @param lastMessage the results of the last command execution
+   */
+  void setLastMessage(String lastMessage) {
+
+    this.lastMessage = lastMessage;
+  }
+
+  // setLastMessage()
+
+  /**
+   * Returns the driver used to communicate with the database.
+   *
+   * @return the driver used to communicate with the database
+   */
+  Session getSession() throws QueryException {
+
+    if (providedSession != null) {
+      if (session != providedSession) {
+        session = providedSession;
+      }
+    }
+
+    if (this.session == null) {
+      throw new QueryException("Null session");
+    }
+    return this.session;
+  }
+
+  // getCause()
+
+  // outASelectCommand()
+  
+  // getCommandStartTime()
+  
+  /**
+   * Sets the driver used to communicate with the database.
+   *
+   * @param session  the driver used to communicate with the database
+   * @param securityDomainURI  the security domain of the <var>session</var>
+   * @throws QueryException if the state of the original session couldn't be
+   *   propagated to the new <var>session</var>.
+   */
+  void setSession(Session session, URI securityDomainURI) throws QueryException {
+    // override all sessions with the provided one.
+    if (providedSession != null) {
+      session = providedSession;
+      return;
+    }
+  
+    if (logger.isDebugEnabled()) {
+      logger.debug(
+          "Setting session to " + session + ", security domain " +
+          securityDomainURI
+          );
+    }
+  
+    // Short-circuit reassignment of the same session
+    if (this.session == session) {
+      if (logger.isDebugEnabled()) {
+        logger.debug("Didn't need to set session");
+      }
+      return;
+    }
+  
+    // We can't change sessions if we're in the midst of a transaction which
+    // has already updated the server
+    if (transactionUpdated) {
+      throw new QueryException(
+          "Can't access more than one server in a transaction"
+          );
+    }
+  
+    // Propagate the autoCommit property to the new session
+    if (!autoCommit) {
+      if (logger.isDebugEnabled()) {
+        logger.debug("Setting autocommit to " + autoCommit + " on " + serverURI);
+      }
+      if (session != null) {
+        session.setAutoCommit(autoCommit);
+      }
+      if (this.session != null) {
+        this.session.setAutoCommit(true); // TODO: this requires a compensating
+        //       transaction in case of
+        //       failure
+      }
+    }
+  
+    // Propagate the login to the new session
+    Login login = (Login) loginMap.get(securityDomainURI);
+    if (login != null) {
+      if (logger.isDebugEnabled()) {
+        logger.debug("Logging " + login.username + " into " + serverURI);
+      }
+      session.login(securityDomainURI, login.username, login.password);
+    }
+    else {
+      if (logger.isDebugEnabled()) {
+        logger.debug("No credentials to propagate for " + securityDomainURI);
+      }
+    }
+  
+    if (this.session != null) {
+      // Close existing session
+      if (logger.isDebugEnabled()) {
+        logger.debug("Closing session");
+      }
+  
+      try {
+        this.session.close();
+      }
+      catch (QueryException e) {
+        logger.warn("Couldn't close session (abandoning)", e);
+      }
+  
+      if (logger.isDebugEnabled()) {
+        logger.debug("Closed session");
+      }
+    }
+  
+    // Reassign session
+    if (session != null) {
+      isLocal = session.isLocal();
+    }
+    this.session = session;
+    this.securityDomainURI = securityDomainURI;
+  }
+
+  // getCommandStartTime()
+  
+  /**
+   * Sets the alias map associated with this session.
+   *
+   * @param aliasMap the alias map associated with this session
+   */
+  void setAliasMap(Map<String,URI> aliasMap) {
+    this.aliasMap = aliasMap;
+  }
+
+  /**
+   * Returns the alias map associated with this session.
+   *
+   * @return the alias namespace map associated with this session
+   */
+  Map<String,URI> getAliasMap() {
+    return this.aliasMap;
+  }
+
+  /**
+   * Builds a list of {@link org.mulgara.query.Variable}s from a list of
+   * {@link org.mulgara.itql.node.PVariable}s. Note. Variables in both the
+   * <code>rawVariableList</code> and the returned list will <strong>not
+   * </strong> contain the variable prefix <code>$</code> in their name.
+   *
+   * @param rawVariableList a list of {@link
+   *      org.mulgara.itql.node.PVariable}s from the parser
+   * @return a list of {@link org.mulgara.query.Variable}s, suitable for use
+   *      in creating a {@link org.mulgara.query.Query}
+   * @throws QueryException if the <code>rawVariableList</code> cannot be parsed
+   *      into a list of {@link org.mulgara.query.Variable}s
+   */
+  List<Object> buildVariableList(LinkedList rawVariableList) throws
+      QueryException, URISyntaxException {
+  
+    // Empty variable list.
+    if (rawVariableList == null) {
+      return (List<Object>)Collections.EMPTY_LIST;
+    }
+  
+    // validate rawVariableList parameter
+    if (rawVariableList.size() == 0) {
+      throw new IllegalArgumentException("Empty \"rawVariableList\" parameter");
+    }
+  
+    // Construct the required builder
+    VariableBuilder variableBuilder = new VariableBuilder(this,
+        variableFactory);
+  
+    // end if
+    // log that we're building the variable list
+    if (logger.isDebugEnabled()) {
+      logger.debug("Building variable list from " + rawVariableList);
+    }
+  
+    // copy each variable from the query into the list
+    for (Iterator i = rawVariableList.iterator(); i.hasNext(); ) {
+      PElement element = (PElement) i.next();
+      element.apply( (Switch) variableBuilder);
+    }
+  
+    // Get the variable list
+    List<Object> variableList = variableBuilder.getVariableList();
+  
+    // make sure that we return a list with something in it
+    if (variableList.size() == 0) {
+      throw new QueryException("No variables parseable from query");
+    }
+  
+    // log that we've successfully built the variable list
+    if (logger.isDebugEnabled()) {
+      logger.debug("Built variable list " + variableList);
+    }
+  
+    // return the list
+    return variableList;
+  }
+
+  /**
+   * Builds a list of {@link org.mulgara.query.Variable}s from a list of
+   * {@link org.mulgara.itql.node.POrderElement}s. Note. Variables in both
+   * the <code>rawVariableList</code> and the returned list will <strong>not
+   * </strong> contain the variable prefix <code>$</code> in their name.
+   *
+   * @param rawOrderList PARAMETER TO DO
+   * @return a list of {@link org.mulgara.query.Variable}s, suitable for use
+   *      in creating a {@link org.mulgara.query.Query}
+   * @throws QueryException if the <code>rawOrderElementList</code> cannot be
+   *      parsed into a list of {@link org.mulgara.query.Variable}s
+   */
+  List buildOrderList(LinkedList rawOrderList) throws QueryException {
+  
+    // validate rawOrderElementList parameter
+    if ( (rawOrderList == null) || (rawOrderList.size() == 0)) {
+  
+      throw new IllegalArgumentException("Null \"rawOrderList\" parameter");
+    }
+  
+    // end if
+    // log that we're building the variable list
+    if (logger.isDebugEnabled()) {
+      logger.debug("Building order list from " + rawOrderList);
+    }
+  
+    // create a list for the parsed variables
+    List orderList = new ArrayList(rawOrderList.size());
+  
+    // copy each variable from the query into the list
+    for (Iterator i = rawOrderList.iterator(); i.hasNext(); ) {
+  
+      AOrderElement order = (AOrderElement) i.next();
+  
+      // get the name of this variable
+      String variableName =
+          ( (AVariable) order.getVariable()).getIdentifier().getText();
+  
+      // log that we've found a variable
+      if (logger.isDebugEnabled()) {
+        logger.debug("Found variable $" + variableName);
+      }
+  
+      // Figure out which way to order, ascending or descending
+      boolean ascending;
+      PDirection direction = order.getDirection();
+  
+      if (direction == null) {
+        ascending = true;
+      }
+      else if (direction instanceof AAscendingDirection) {
+        ascending = true;
+      }
+      else if (direction instanceof ADescendingDirection) {
+        ascending = false;
+      }
+      else {
+        throw new Error("Unknown direction field in order");
+      }
+  
+      // add a new variable to the list
+      orderList.add(new Order(new Variable(variableName), ascending));
+    }
+  
+    // end for
+    // make sure that we return a list with something in it
+    if (orderList.size() == 0) {
+  
+      throw new QueryException("No variables parseable from query");
+    }
+  
+    // log that we've successfully built the order list
+    if (logger.isDebugEnabled()) {
+  
+      logger.debug("Built order list " + orderList);
+    }
+  
+    // return the list
+    return orderList;
+  }
+
+  /**
+   * Resets the parser state in preparation for a new command.
+   */
+  private void resetInterpreter() {
+    lastCommand = null;
+    lastError = null;
+  }
+  
+  
+  /**
+   * Notify that the current session has been updated.
+   */
+  private void update() {
+    transactionUpdated = !autoCommit;
+  }
+
+  // outASelectCommand()
+  
+  /**
+   * If the <code>FROM</code> clause of query refers to models in a different
+   * server than the one we're pointed at, change the {@link #session}.
+   *
+   * @param modelExpression a <code>FROM</code> clause, never <code>null</code>
+   * @throws QueryException if the <var>modelExpression</var> can't be resolved
+   *   by any single server
+   */
+  private void updateSession(ModelExpression modelExpression) throws
+      QueryException {
+    assert modelExpression != null;
+  
+    if (providedSession != null) {
+      session = providedSession;
+      return;
+    }
+  
+    URI databaseURI = null;
+  
+    // Check to see that we're aimed at the right server
+    Set databaseURISet = modelExpression.getDatabaseURIs();
+    assert databaseURISet != null;
+    if (logger.isDebugEnabled()) {
+      logger.debug(
+          "Current server is " + serverURI + ", updating for " + databaseURISet
+          );
+    }
+    switch (databaseURISet.size()) {
+      case 0:
+  
+        // Query presumably contains only URLs -- any server can deal with
+        // this, including the current one
+        if (session == null) {
+          try {
+            serverURI = SessionFactoryFinder.findServerURI();
+  
+            SessionFactory sessionFactory =
+                SessionFactoryFinder.newSessionFactory(serverURI, !isLocal);
+  
+            // Switch the underlying session to point at the required server
+            setSession(sessionFactory.newSession(),
+                       sessionFactory.getSecurityDomain());
+          }
+          catch (SessionFactoryFinderException e) {
+            throw new QueryException("Unable to connect to a server", e);
+          }
+          catch (NonRemoteSessionException e) {
+            throw new QueryException("Error connecting to the local server", e);
+          }
+        }
+        assert session != null;
+        break;
+  
+      case 1:
+  
+        // Query must go to a particular server
+        databaseURI = (URI) databaseURISet.iterator().next();
+        assert databaseURI != null;
+        if (!databaseURI.equals(serverURI)) {
+          setServerURI(databaseURI);
+        }
+        assert databaseURI.equals(serverURI);
+        break;
+  
+      default:
+  
+        // Query must be distributed between multiple servers
+        assert databaseURISet.size() > 1;
+  
+        if (!databaseURISet.contains(serverURI)) {
+          // We're not even aimed at one of the servers involved in this query,
+          // so choose one arbitrarily and switch to it
+          databaseURI = (URI) databaseURISet.iterator().next();
+          assert databaseURI != null;
+          setServerURI(databaseURI);
+          assert databaseURI.equals(serverURI);
+        }
+  
+        // We're now connected to one of the servers involved in this query.
+        assert databaseURISet.contains(serverURI);
+        break;
+    }
+  }
+
+  /**
+   * Sets the option to enable the timing of commands.
+   *
+   * @param timeOption the option to enable the timing of commands
+   */
+  private void setTimeOption(boolean timeOption) {
+
+    this.timeOption = timeOption;
+  }
+
+  // getTimeOption()
+
+  /**
+   * Sets the time a command started.
+   *
+   * @param commandStartTime the time a command started
+   */
+  private void setCommandStartTime(long commandStartTime) {
+
+    this.commandStartTime = commandStartTime;
+  }
+
+  // getCommandStartTime()
+
+  /**
+   * Sets the results of the last query. Methods overriding <code>DepthFirstAdapter</code>
+   * are expected to set a result for successful queries, and <code>null</code>
+   * for failed ones.
+   *
+   * @param lastAnswer the results of the last command execution
+   */
+  private void setLastAnswer(Answer lastAnswer) {
+
+    this.lastAnswer = lastAnswer;
+  }
+
+  /**
+   * Insert a set of triples.  Calls the server if it can be done only on the
+   * server.
+   *
+   * @param tripleFactor a triple, model or query from the parser
+   * @throws QueryException if <code>tripleFactor</code> contains a query that
+   *      cannot be executed, or after evaluation contains no statements
+   * @throws URISyntaxException if <code>tripleFactor</code> contains a query or
+   *      a resource that that violates <a
+   *      href="http://www.isi.edu/in-notes/rfc2396.txt">RFC\uFFFD2396</a>
+   */
+  private void insertStatements(URI modelURI, PTripleFactor tripleFactor) throws
+      QueryException, URISyntaxException {
+
+    // validate tripleFactor parameter
+    if (tripleFactor == null) {
+
+      throw new IllegalArgumentException("Null \"tripleFactor\" parameter");
+    }
+
+    // log that we're finding statements
+    if (logger.isDebugEnabled()) {
+
+      logger.debug("Finding statements in expression " + tripleFactor);
+    }
+
+    // get the set of triples out of the factor
+    PSetOfTriples setOfTriples = null;
+
+    if (tripleFactor instanceof ABracedTripleFactor) {
+
+      setOfTriples = ((ABracedTripleFactor)tripleFactor).getSetOfTriples();
+    } else if (tripleFactor instanceof AUnbracedTripleFactor) {
+
+      setOfTriples = ((AUnbracedTripleFactor)tripleFactor).getSetOfTriples();
+    }
+
+    // drill down into the set of triples
+    if (setOfTriples instanceof AResourceSetOfTriples) {
+
+      // log that we've found a resource
+      if (logger.isDebugEnabled()) {
+
+        URI resourceURI = toURI(((AResourceSetOfTriples)setOfTriples).getResource());
+        logger.debug("Found resource " + resourceURI + "in triple factor");
+      }
+
+      // TODO: implement this once we can select all triples from a model
+      // we cannot currently handle inserting or deleting a complete model
+      // into/from another
+      throw new UnsupportedOperationException("Models cannot be inserted " +
+                                              "into or deleted from other models");
+    } else if (setOfTriples instanceof ASelectSetOfTriples) {
+
+      // build the query
+      Query query = this.buildQuery(((ASelectSetOfTriples)setOfTriples));
+
+      // log that we've created the query and will execute it
+      if (logger.isDebugEnabled()) {
+
+        logger.debug("Executing query " + query);
+      }
+
+      getSession().insert(modelURI, query);
+    } else if (setOfTriples instanceof ATripleSetOfTriples) {
+
+      Map<String,VariableNodeImpl> variableMap = new HashMap<String,VariableNodeImpl>();
+      Set<org.jrdf.graph.Triple> statements = getStatements((ATripleSetOfTriples)setOfTriples, variableMap);
+      getSession().insert(modelURI, statements);
+    }
+  }
+
+  /**
+   * Delete a set of triples.  Calls the server if it can be done only on the
+   * server.
+   *
+   * @param tripleFactor a triple, model or query from the parser
+   * @throws QueryException if <code>tripleFactor</code> contains a query that
+   *      cannot be executed, or after evaluation contains no statements
+   * @throws URISyntaxException if <code>tripleFactor</code> contains a query or
+   *      a resource that that violates <a
+   *      href="http://www.isi.edu/in-notes/rfc2396.txt">RFC\uFFFD2396</a>
+   */
+  private void deleteStatements(URI modelURI, PTripleFactor tripleFactor) throws
+      QueryException, URISyntaxException {
+
+    // validate tripleFactor parameter
+    if (tripleFactor == null) {
+
+      throw new IllegalArgumentException("Null \"tripleFactor\" parameter");
+    }
+
+    // log that we're finding statements
+    if (logger.isDebugEnabled()) {
+
+      logger.debug("Finding statements in expression " + tripleFactor);
+    }
+
+    // get the set of triples out of the factor
+    PSetOfTriples setOfTriples = null;
+
+    if (tripleFactor instanceof ABracedTripleFactor) {
+
+      setOfTriples = ( (ABracedTripleFactor) tripleFactor).getSetOfTriples();
+    } else if (tripleFactor instanceof AUnbracedTripleFactor) {
+
+      setOfTriples = ( (AUnbracedTripleFactor) tripleFactor).getSetOfTriples();
+    }
+
+    // drill down into the set of triples
+    if (setOfTriples instanceof AResourceSetOfTriples) {
+
+      // log that we've found a resource
+      if (logger.isDebugEnabled()) {
+
+        URI resourceURI = toURI(((AResourceSetOfTriples)setOfTriples).getResource());
+        logger.debug("Found resource " + resourceURI + "in triple factor");
+      }
+
+      // TODO: implement this once we can select all triples from a model
+      // we cannot currently handle inserting or deleting a complete model
+      // into/from another
+      throw new UnsupportedOperationException("Models cannot be inserted " +
+                                              "into or deleted from other models");
+    } else if (setOfTriples instanceof ASelectSetOfTriples) {
+
+      // build the query
+      Query query = this.buildQuery( ( (ASelectSetOfTriples) setOfTriples));
+
+      // log that we've created the query and will execute it
+      if (logger.isDebugEnabled()) {
+
+        logger.debug("Executing query " + query);
+      }
+
+      getSession().delete(modelURI, query);
+
+    } else if (setOfTriples instanceof ATripleSetOfTriples) {
+
+      Map<String,VariableNodeImpl> variableMap = new HashMap<String,VariableNodeImpl>();
+      Set<org.jrdf.graph.Triple> statements = getStatements((ATripleSetOfTriples)setOfTriples, variableMap);
+      if (variableMap.size() > 0) {
+        throw new QueryException("Cannot use variables when deleting statements");
+      }
+      getSession().delete(modelURI, statements);
+    }
+  }
+
+  /**
+   * Builds a set of {@link org.jrdf.graph.Triple}s from a
+   * {@link org.mulgara.query.Answer}.
+   *
+   * @param answer the results of a query
+   * @return a set of {@link org.jrdf.graph.Triple}s, suitable for use in
+   *      inserting or deleting data to or from a model
+   * @throws QueryException EXCEPTION TO DO
+   */
+  private Set getStatements(Answer answer) throws QueryException {
+
+    // validate answer parameter
+    if (answer == null) {
+
+      throw new IllegalArgumentException("Null \"answer\" parameter");
+    } // end if
+
+    // log that we're parsing an answer into a set of statements
+    if (logger.isDebugEnabled()) {
+
+      logger.debug("Parsing answer into set of statements");
+    }
+
+    try {
+      Set statements = new HashSet();
+      answer.beforeFirst();
+
+      while (answer.next()) {
+
+        if (! (answer.getObject(0) instanceof ObjectNode)) {
+
+          throw new QueryException("Subject is not a resource for [" +
+                                   answer.getObject(0) + " " +
+                                   answer.getObject(1) +
+                                   " " +
+                                   answer.getObject(2) + "]");
+        }
+
+        if (! (answer.getObject(1) instanceof URIReference)) {
+
+          throw new QueryException("Predicate is not a resource for [" +
+                                   answer.getObject(0) + " " +
+                                   answer.getObject(1) +
+                                   " " +
+                                   answer.getObject(2) + "]");
+        }
+
+        statements.add(new TripleImpl( (SubjectNode) answer.getObject(0),
+                                      (PredicateNode) answer.getObject(1),
+                                      (ObjectNode) answer.getObject(2)));
+      }
+
+      logger.debug("Parsed answer into " + statements.size());
+
+      return statements;
+    }
+    catch (TuplesException e) {
+      throw new QueryException("Couldn't parse answer into statements", e);
+    }
+  } // setStatements
+
+  /**
+   * Returns the option to enable the timing of commands.
+   *
+   * @return the option to enable the timing of commands
+   */
+  private boolean getTimeOption() {
+
+    return timeOption;
+  }
+
+  /**
+   * Return the time a command started.
+   *
+   * @return the time a command started
+   */
+  private long getCommandStartTime() {
+
+    return commandStartTime;
+  }
+
+  /**
+   * Constructs a {@link org.jrdf.graph.Node} from a {@link
+   * org.mulgara.itql.node.PTripleElement}.
+   *
+   * @param element dd
+   * @param variableMap a {@link Map} of variable names (as string) to
+   *   {@link VariableNodeImpl} that are used to contain all variables.
+   * @return dd
+   * @throws QueryException if <code>element</code> is a {@link
+   *   org.mulgara.itql.node.AResourceTripleElement} whose text contains a
+   *   <a href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">qualified
+   *   name</a> with a prefix not defined in the <code>aliasMap</code>
+   * @throws URISyntaxException if <code>element</code> is a {@link
+   *   org.mulgara.itql.node.AResourceTripleElement} whose text doesn't
+   *   conform to <a href="http://www.isi.edu/in-notes/rfc2396.txt">
+   *   RFC\uFFFD2396</a>
+   */
+  private org.jrdf.graph.Node toNode(PTripleElement element, Map<String,VariableNodeImpl> variableMap) throws
+      QueryException, URISyntaxException {
+
+    // validate the element parameter
+    if (element == null) {
+
+      throw new IllegalArgumentException("Null \"element\" parameter");
+    }
+
+    // end if
+    // log what we're doing
+    if (logger.isDebugEnabled()) {
+
+      logger.debug("Resolving " + element + "to a RDF node");
+    }
+
+    // create the node
+    org.jrdf.graph.Node node = null;
+
+    // get the node
+    if (element instanceof ALiteralTripleElement) {
+
+      // create a new literal with the given text
+      node = toLiteralImpl( ( (ALiteralTripleElement) element).getLiteral());
+    }
+    else if (element instanceof AResourceTripleElement) {
+
+      // create a new resource
+      node = new URIReferenceImpl(toURI(
+          ( (AResourceTripleElement) element).getResource()
+          ));
+    }
+    else if (element instanceof AVariableTripleElement) {
+
+      // get the variable
+      String variableName =
+          ( (AVariable) ( (AVariableTripleElement) element).getVariable()).
+          getIdentifier().getText();
+
+      // log what we're doing
+      if (logger.isDebugEnabled()) {
+
+        logger.debug("Resolved " + element + " to variable " + variableName);
+      }
+
+      if (variableMap.containsKey(variableName)) {
+
+        node = (VariableNodeImpl) variableMap.get(variableName);
+      }
+      else {
+
+        VariableNodeImpl variable = new VariableNodeImpl(variableName);
+        variableMap.put(variableName, variable);
+        node = variable;
+      }
+    } // end if
+
+    // return the node
+    return node;
+  }
+
+  /**
+   * Determines if the stream is compressed by inspecting the fileName extension.
+   *
+   * Returns a new "Compressed" stream if the file is compressed or the original
+   * InputStream if the file is not compressed.
+   *
+   * @param fileName String
+   * @param inputStream InputStream
+   * @throws IOException
+   * @return InputStream
+   */
+  private InputStream adjustForCompression(String fileName,
+      InputStream inputStream) throws IOException {
+
+    //validate
+    if (fileName == null) {
+      throw new IllegalArgumentException("File name is null");
+    }
+    if (inputStream == null) {
+      throw new IllegalArgumentException("InputStream is null");
+    }
+
+    InputStream stream = inputStream;
+
+    // Guess at transfer encoding (compression scheme) based on file extension
+    if (fileName.toLowerCase().endsWith(".gz")) {
+      // The file name ends with ".gz", so assume it's a gzip'ed file
+      stream = new GZIPInputStream(inputStream);
+    }
+    else if (fileName.toLowerCase().endsWith(".zip")) {
+      // The file name ends with ".zip", so assume it's a zip'ed file
+      stream = new ZipInputStream(inputStream);
+    }
+
+    assert stream != null;
+    return stream;
+  }
+
+  /**
+   * Adds a name/value pair to the alias map. This method will add associate a
+   * prefix for a target for subsequent commands, making commands like the
+   * following possible: <PRE>
+   * alias http://purl.org/dc/elements/1.1 as dc;
+   * select $title where $uri dc:title $title ;
+   * </PRE>
+   *
+   * @param aliasPrefix the alias that denotes the target
+   * @param aliasTarget the target associated with the prefix
+   */
+  private void addAliasPair(String aliasPrefix, URI aliasTarget) {
+
+    // validate the aliasPrefix parameter
+    if (aliasPrefix == null) throw new IllegalArgumentException("Null \"aliasPrefix\" " + "parameter");
+
+    // validate the aliasTarget parameter
+    if (aliasTarget == null) throw new IllegalArgumentException("Null \"aliasTarget\" " + "parameter");
+
+    // add the pair to the map
+    getAliasMap().put(aliasPrefix, aliasTarget);
+  }
+
+  /**
+   * Log the iTQL command to a specified file
+   *
+   * @param command PARAMETER TO DO
+   */
+  private void logItql(String command) {
+
+    // Has this session been constructed for logging.
+    // the constructor initialise this if
+    // system property itql.command.log is set
+    if (itqlLogFile == null) {
+
+      return;
+    }
+
+    try {
+      // has the log file been opened?
+      if (itqlLog == null) {
+        itqlLog = new PrintWriter(new FileWriter(itqlLogFile, true), true);
+      }
+
+      // append the command to the file
+      itqlLog.println(command);
+    }
+    catch (Exception ex) {
+      logger.error("Unable to log itql commands", ex);
+    }
+  }
+
+  /**
+   * Builds a HAVING compliant {@link org.mulgara.query.ConstraintExpression} object from a
+   * {@link org.mulgara.itql.node.PConstraintExpression}, using an <code>aliasMap</code>
+   * to resolve aliases.  To comply with a HAVING clause the predicate must be one of:
+   * mulgara:occurs mulgara:occursLessThan mulgara:occursMoreThan.
+   *
+   * @param expression a constraint expression from the parser
+   * @return RETURNED VALUE TO DO
+   * @throws QueryException if <code>rawConstraintExpression</code> does not
+   *      represent a valid query
+   * @throws URISyntaxException if the <code>rawConstraintExpression</code>
+   *      contains a resource whose text violates <a
+   *      href="http://www.isi.edu/in-notes/rfc2396.txt">RFC?2396</a>
+   */
+  ConstraintHaving buildHaving(PConstraintExpression expression)
+      throws QueryException, URISyntaxException {
+    ConstraintExpression hExpr = build(expression);
+
+    if (hExpr instanceof ConstraintOperation) {
+      throw new QueryException("Having currently supports only one constraint");
+    }
+
+    if (!checkHavingPredicates(hExpr)) {
+      throw new QueryException("Only \"occurs\" predicates can be used in a Having clause");
+    }
+    return (ConstraintHaving) hExpr;
+  }
+
+
+  /**
+   * Checks that all predicates in a constraint expression are valid Having predicates
+   * from {@link SpecialPredicates}.
+   *
+   * @param e The constraint expression to check.
+   * @return true if all constraints have special predicates.
+   */
+  private boolean checkHavingPredicates(ConstraintExpression e) {
+    if (e instanceof Constraint) {
+      return e instanceof ConstraintHaving;
+    } else if (e instanceof ConstraintOperation) {
+      // check all sub expressions
+      Iterator i = ((ConstraintOperation)e).getElements().iterator();
+      while (i.hasNext()) {
+        if (checkHavingPredicates((ConstraintExpression)i.next())) {
+          return false;
+        }
+      }
+      // all sub expressions returned true
+      return true;
+    } else {
+      // An unexpected type
+      return false;
+    }
+  }
+
+
+  /**
+   * Set the active server for a backup given either a server URI or
+   * a model URI.
+   *
+   * @param sourceURI URI
+   */
+
+  private void setBackupServer( URI sourceURI ) throws QueryException {
+
+    //Determine if a model or a server is being backed up.
+    if ( (sourceURI != null)
+      && (sourceURI.getFragment() != null)) {
+
+      // make a note that a model is being backed up
+      if (logger.isDebugEnabled()) {
+
+       logger.debug("Model Found. Backing up model " + sourceURI );
+      }
+
+      //remove fragment from the model URI
+      String fragment = sourceURI.getFragment();
+      String serverURI = sourceURI.toString().replaceAll("#" + fragment, "");
+
+      //create URI for the model's server
+       try {
+
+         URI uri = new URI(serverURI);
+
+         //get session for the model's server.
+         setServerURI(uri);
+
+         //update the session (required if this is the first query)
+         this.updateSession(new ModelResource(uri));
+
+       }
+       catch (URISyntaxException uriException) {
+
+        //this will be caught below
+        throw new QueryException("Could not connect to model's Server.",
+                                  uriException);
+       }
+    }
+    else {
+
+      // log that we're backing up a server
+      if (logger.isDebugEnabled()) {
+
+        logger.debug("Backing up server " + sourceURI );
+      }
+
+     //source is a server.
+     setServerURI(sourceURI);
+    }
+  }
+
+
+  /**
+   * Try to recognise a uri alias, and return the canonical form instead.
+   *
+   * @param uri The URI being checked.
+   * @return The updated URI.  May be the same as the uri parameter.
+   */
+  private URI getCanonicalUriAlias(URI uri) {
+    // only do this for remote protocols
+    if (!"rmi".equals(uri.getScheme()) && !"soap".equals(uri.getScheme())) {
+      return uri;
+    }
+    logger.debug("Checking for an alias on: " + uri);
+    // extract the host name
+    String host = uri.getHost();
+    if (host == null) {
+      return uri;
+    }
+    Set hostnames = getHostnameAliases();
+    // Check with a DNS server to see if this host is recognised
+    InetAddress addr = null;
+    try {
+      addr = InetAddress.getByName(host);
+    } catch (UnknownHostException uhe) {
+      // The host was unknown, so allow resolution to continue as before
+      return uri;
+    }
+    // check the various names against known aliases and the given name
+    if (
+        hostnames.contains(host) ||
+        hostnames.contains(addr.getHostName()) ||
+        hostnames.contains(addr.getCanonicalHostName()) ||
+        hostnames.contains(addr.getHostAddress())
+    ) {
+      // change the host name to one that is recognised
+      // use the system uri to find the local host name
+      URI serverURI = getServerURI();
+      if (serverURI == null) {
+        return uri;
+      }
+      String newHost = serverURI.getHost();
+      try {
+        return new URI(uri.getScheme(), newHost, uri.getPath(), uri.getFragment());
+      } catch (URISyntaxException e) { /* fall through */ }
+    }
+
+    // not found, so return nothing
+    return uri;
+  }
+
+
+  /**
+   * Method to ask the ServerInfo for the local server aliases.
+   * This will return an empty set if ServerInfo is not available -
+   * ie. being run on a host which has no local database, such an an iTQL client.
+   *
+   * @return The set of server aliases as strings
+   */
+  private static Set getHostnameAliases() {
+    Set names = (Set)getServerInfoProperty("HostnameAliases");
+    return (names == null) ? java.util.Collections.EMPTY_SET : names;
+  }
+
+
+  /**
+   * Method to ask the ServerInfo for the local server URI.
+   * This will return null if ServerInfo is not available -
+   * ie. being run on a host which has no local database, such an an iTQL client.
+   *
+   * @return The URI of the local server, or null if this is not a server.
+   */
+  private static URI getServerURI() {
+    return (URI)getServerInfoProperty("ServerURI");
+  }
+
+
+  /**
+   * Method to get the value of a property from the ServerInfo for the local database session.
+   * This will return null if ServerInfo is not available -
+   * ie. being run on a host which has no local database, such an an iTQL client.
+   *
+   * @param property The property to return, with the correct case.
+   * @return The object returned from the accessor method named, or null if ServerInfo is not available.
+   */
+  private static Object getServerInfoProperty(String property) {
+    Object o = null;
+    try {
+      Class rsf = Class.forName("org.mulgara.server.ServerInfo");
+      java.lang.reflect.Method getter = rsf.getMethod("get" + property, null);
+      o = getter.invoke(null, null);
+    } catch (Exception e) { /* no op */ }
+    return o;
+  }
+
+  private class Lexer2 extends Lexer {
+  
+    int commandCount = 0;
+    final LinkedList leftoverTokenList = new LinkedList();
+  
+    public Lexer2() {
+      super(null);
+    }
+  
+    public int getCommandCount() {
+      return commandCount;
+    }
+  
+    public void add(String command) throws LexerException, IOException {
+      Lexer lexer = new Lexer(new PushbackReader(new StringReader(command), 256));
+      Token t;
+      while (! ( (t = lexer.next()) instanceof EOF)) {
+        if (t instanceof TTerminator) {
+          t = new EOF();
+          commandCount++;
+        }
+        leftoverTokenList.add(t);
+      }
+    }
+  
+    public Token next() throws LexerException, IOException {
+      return leftoverTokenList.isEmpty() ? new EOF() : (Token) leftoverTokenList.removeFirst();
+    }
+  
+    public Token peek() throws LexerException, IOException {
+      return leftoverTokenList.isEmpty() ? new EOF() : (Token) leftoverTokenList.getFirst();
+    }
+  
+    public boolean nextCommand() {
+      if (commandCount == 0) {
+        return false;
+      }
+      else {
+        //assert commandCount > 0;
+        commandCount--;
+        return true;
+      }
+    }
+  }
+
+}

Added: branches/nw-interface/src/jar/itql/java/org/mulgara/itql/URIUtil.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/itql/URIUtil.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/itql/URIUtil.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -0,0 +1,51 @@
+/*
+ * 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.itql;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Map;
+
+/**
+ * A set of methods for managing common URI operations.
+ *
+ * @created 2007-08-09
+ * @author Paul Gearon
+ * @copyright &copy; 2007 <a href="mailto:pgearon at users.sourceforge.net">Paul Gearon</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class URIUtil {
+
+  /**
+   * Replace an alias in a URI, if one is recognized.
+   * @param uriString A string with the initial uri to check for aliases.
+   * @param aliasMap The map of known aliases to the associated URIs
+   * @return A new URI with the alias replaced, or the original if no alias is found.
+   */
+  public static URI convertToURI(String uriString, Map<String,URI> aliasMap) {
+    try {
+      URI uri = new URI(uriString);
+      if (uri.isOpaque()) {
+        // Attempt qname-to-URI substitution for aliased namespace prefixes
+        URI mapping = aliasMap.get(uri.getScheme());
+        if (mapping != null) {
+          uri = new URI(mapping + uri.getSchemeSpecificPart());
+        }
+      }
+      return uri;
+    } catch (URISyntaxException e) {
+      throw new Error("Bad URI syntax in resource: " + e);
+    }
+  }
+  
+}

Modified: branches/nw-interface/src/jar/itql/java/org/mulgara/itql/VariableBuilder.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/itql/VariableBuilder.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/itql/VariableBuilder.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -88,14 +88,14 @@
   private QueryException queryException = null;
 
   /**
-   * The list of variables
+   * The list of variables - these are mixed object types
    */
-  private List variableList;
+  private List<Object> variableList;
 
   /**
    * The iTQL interpreter
    */
-  private ItqlInterpreter interpreter;
+  private Interpreter interpreter;
 
   /**
    * Create a new builder.  Requires methods on the interpreter in order to
@@ -103,10 +103,10 @@
    *
    * @param newInterpreter the interpreter to use.
    */
-  public VariableBuilder(ItqlInterpreter newInterpreter,
+  public VariableBuilder(Interpreter newInterpreter,
       VariableFactory newVariableFactory) {
 
-    variableList = new ArrayList();
+    variableList = new ArrayList<Object>();
     interpreter = newInterpreter;
     variableFactory = newVariableFactory;
   }
@@ -209,10 +209,10 @@
    * @throws URISyntaxException if the variable contains a resource whose
    *   text violates <a href="http://www.isi.edu/in-notes/rfc2396.txt">RFC?2396</a>
    */
-  public List getVariableList() throws QueryException, URISyntaxException {
+  public List<Object> getVariableList() throws QueryException, URISyntaxException {
 
     try {
-      List tmpVariableList = new ArrayList(variableList);
+      List<Object> tmpVariableList = new ArrayList<Object>(variableList);
 
       if (uriException != null) {
         throw uriException;

Added: branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/ApplyRules.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/ApplyRules.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/ApplyRules.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -0,0 +1,91 @@
+/**
+ * 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.query.ast;
+
+import java.net.URI;
+
+/**
+ * Represents a command to apply rules to a set of data.
+ *
+ * @created Aug 10, 2007
+ * @author Paul Gearon
+ * @copyright &copy; 2007 <a href="mailto:pgearon at users.sourceforge.net">Paul Gearon</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class ApplyRules implements CommandAst {
+
+  /** The graph containing the rules to be run. */
+  private URI ruleGraph;
+  
+  /** The graph containing the data to apply the rules to. */
+  private URI baseGraph;
+  
+  /** The graph to put the rule productions into. */
+  private URI destGraph;
+  
+  /**
+   * Create a new rules command.
+   * @param ruleGraph The graph containing the rules to be run.
+   * @param baseGraph The graph containing the data to apply the rules to.
+   * @param destGraph The graph to put the rule productions into.
+   */
+  public ApplyRules(URI ruleGraph, URI baseGraph, URI destGraph) {
+    this.ruleGraph = ruleGraph;
+    this.baseGraph = baseGraph;
+    this.destGraph = destGraph;
+  }
+  
+  /**
+   * @return The URI of the graph containing rule productions.
+   */
+  public URI getServerURI() throws UnsupportedOperationException {
+    return destGraph;
+  }
+
+  /**
+   * Returns false to indicate that this is a server-side operation.
+   * @return Always <code>false</code>
+   */
+  public boolean isLocalOperation() {
+    return false;
+  }
+
+  /**
+   * Returns false to indicate that this operation is not tied to a UI.
+   * @return Always <code>false</code>
+   */
+  public boolean isUICommand() {
+    return false;
+  }
+
+  /**
+   * @return the ruleGraph
+   */
+  public URI getRuleGraph() {
+    return ruleGraph;
+  }
+
+  /**
+   * @return the baseGraph
+   */
+  public URI getBaseGraph() {
+    return baseGraph;
+  }
+
+  /**
+   * @return the destGraph
+   */
+  public URI getDestGraph() {
+    return destGraph;
+  }
+
+}

Added: branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/CommandAst.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/CommandAst.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/CommandAst.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -0,0 +1,46 @@
+/*
+ * 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.query.ast;
+
+import java.net.URI;
+
+/**
+ * A general Abstract Syntax Tree for TQL commands.
+ *
+ * @created 2007-08-09
+ * @author Paul Gearon
+ * @copyright &copy; 2007 <a href="mailto:pgearon at users.sourceforge.net">Paul Gearon</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public interface CommandAst {
+
+  /**
+   * Indicates if an AST element is an operation for a local client.
+   * @return <code>true</code> if the operation is only relevant to a client.
+   */
+  boolean isLocalOperation();
+  
+  /**
+   * Indicates if an AST represents a command for a user interface.
+   * @return <code>true</code> if the operation is only relevant to a user interface
+   */
+  boolean isUICommand();
+  
+  /**
+   * Gets the associated server for a non-local operation.
+   * @return the server URI if one can be determined,
+   *  or <code>null</code> if not a valid operation.
+   * @throws UnsupportedOperationException If this command is local only.
+   */
+  URI getServerURI() throws UnsupportedOperationException;
+}

Added: branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Commit.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Commit.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Commit.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -0,0 +1,55 @@
+/*
+ * 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.query.ast;
+
+import java.net.URI;
+
+
+/**
+ * An AST element for the COMMIT command.
+ *
+ * @created 2007-08-09
+ * @author Paul Gearon
+ * @copyright &copy; 2007 <a href="mailto:pgearon at users.sourceforge.net">Paul Gearon</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class Commit implements CommandAst {
+
+  /**
+   * Indicates that this operation may require network access.
+   * @return <code>false</code> as network access may be needed.
+   */
+  public boolean isLocalOperation() {
+    return false;
+  }
+
+
+  /**
+   * Indicates that this operation is not specific to a UI.
+   * @return <code>false</code> as operation is not specific to UIs.
+   */
+  public boolean isUICommand() {
+    return false;
+  }
+
+
+  /**
+   * Requests a server URI for this operation.  None available, as it
+   * operates on the local connection.
+   * @return <code>null</code>
+   */
+  public URI getServerURI() {
+    return null;
+  }
+
+}

Added: branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/CreateGraph.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/CreateGraph.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/CreateGraph.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -0,0 +1,76 @@
+/**
+ * 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.query.ast;
+
+import java.net.URI;
+
+/**
+ * Represents a command to create a new graph.
+ * @created Aug 10, 2007
+ * @author Paul Gearon
+ * @copyright &copy; 2007 <a href="mailto:pgearon at users.sourceforge.net">Paul Gearon</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class CreateGraph implements CommandAst {
+
+  /** The URI for the graph. */
+  private URI graphUri;
+  
+  /** The URI for the type of the graph. */
+  private URI type;
+  
+  public CreateGraph(URI graphUri, URI type) {
+    this.graphUri = graphUri;
+    this.type = type;
+  }
+  
+  /**
+   * Finds the server URI for the graph.
+   * @return The URI used to find the server.
+   */
+  public URI getServerURI() {
+    return graphUri;
+  }
+
+  /**
+   * Indicates that this operation is for a server.
+   * @return Always <code>false</code>
+   */
+  public boolean isLocalOperation() {
+    return false;
+  }
+
+  /**
+   * Indicates that this operation is not tied to the UI.
+   * @return Always <code>false</code>
+   */
+  public boolean isUICommand() {
+    return false;
+  }
+
+  /**
+   * Get the URI of the graph to create.
+   * @return the URI of the graph to create.
+   */
+  public URI getGraphUri() {
+    return graphUri;
+  }
+
+  /**
+   * Get the type of the graph to create.
+   * @return the type of the graph.
+   */
+  public URI getType() {
+    return type;
+  }
+
+}

Added: branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/DropGraph.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/DropGraph.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/DropGraph.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -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.query.ast;
+
+import java.net.URI;
+
+/**
+ * Represents a command to drop a graph.
+ * @created Aug 10, 2007
+ * @author Paul Gearon
+ * @copyright &copy; 2007 <a href="mailto:pgearon at users.sourceforge.net">Paul Gearon</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class DropGraph implements CommandAst {
+
+  /** The URI for the graph. */
+  private URI graphUri;
+  
+  public DropGraph(URI graphUri) {
+    this.graphUri = graphUri;
+  }
+  
+  /**
+   * Finds the server URI for the graph.
+   * @return The URI used to find the server.
+   */
+  public URI getServerURI() {
+    return graphUri;
+  }
+
+  /**
+   * Indicates that this operation is for a server.
+   * @return Always <code>false</code>
+   */
+  public boolean isLocalOperation() {
+    return false;
+  }
+
+  /**
+   * Indicates that this operation is not tied to the UI.
+   * @return Always <code>false</code>
+   */
+  public boolean isUICommand() {
+    return false;
+  }
+
+  /**
+   * Get the URI of the graph to drop.
+   * @return the URI of the graph to drop.
+   */
+  public URI getGraphUri() {
+    return graphUri;
+  }
+
+}

Added: branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Help.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Help.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Help.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -0,0 +1,47 @@
+/*
+ * 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.query.ast;
+
+import org.mulgara.itql.HelpPrinter;
+import org.mulgara.itql.node.PCommandPrefix;
+
+/**
+ * An AST element for the HELP command.
+ *
+ * @created 2007-08-09
+ * @author Paul Gearon
+ * @copyright &copy; 2007 <a href="mailto:pgearon at users.sourceforge.net">Paul Gearon</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class Help extends LocalAst {
+
+  private PCommandPrefix command;
+  
+  public Help(PCommandPrefix command) {
+    this.command = command;
+  }
+  
+  /**
+   * Indicates that this operation is for a UI.
+   * @return <code>true</code> as operation is for UI output only.
+   */
+  public boolean isUICommand() {
+    return true;
+  }
+
+  public String getOutput() {
+    // let the user know the help for the selected command
+    return HelpPrinter.getHelp(command);
+  }
+
+}

Added: branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/LocalAst.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/LocalAst.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/LocalAst.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -0,0 +1,30 @@
+/*
+ * 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.query.ast;
+
+import java.net.URI;
+
+public abstract class LocalAst implements CommandAst {
+
+  public boolean isLocalOperation() {
+    return true;
+  }
+
+  /**
+   * Gets the associated server for a non-local operation.
+   * @throws UnsupportedOperationException Always thrown for local commands.
+   */
+  public URI getServerURI() throws UnsupportedOperationException {
+    throw new UnsupportedOperationException("Server URI not available for local commands.");
+  }
+}

Added: branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Quit.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Quit.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Quit.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -0,0 +1,34 @@
+/*
+ * 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.query.ast;
+
+
+/**
+ * An AST element for the QUIT command.
+ *
+ * @created 2007-08-09
+ * @author Paul Gearon
+ * @copyright &copy; 2007 <a href="mailto:pgearon at users.sourceforge.net">Paul Gearon</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class Quit extends LocalAst {
+
+  /**
+   * Indicates that this operation is for a UI.
+   * @return <code>true</code> as operation is for UI output only.
+   */
+  public boolean isUICommand() {
+    return true;
+  }
+
+}

Added: branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Rollback.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Rollback.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/Rollback.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -0,0 +1,53 @@
+/*
+ * 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.query.ast;
+
+import java.net.URI;
+
+
+/**
+ * An AST element for the ROLLBACK command.
+ *
+ * @created 2007-08-09
+ * @author Paul Gearon
+ * @copyright &copy; 2007 <a href="mailto:pgearon at users.sourceforge.net">Paul Gearon</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class Rollback implements CommandAst {
+
+  /**
+   * Indicates that this operation may require network access.
+   * @return <code>false</code> as network access may be needed.
+   */
+  public boolean isLocalOperation() {
+    return false;
+  }
+
+  /**
+   * Indicates that this operation is not specific to a UI.
+   * @return <code>false</code> as operation is not specific to UIs.
+   */
+  public boolean isUICommand() {
+    return false;
+  }
+
+  /**
+   * Requests a server URI for this operation.  None available, as it
+   * operates on the local connection.
+   * @return <code>null</code>
+   */
+  public URI getServerURI() {
+    return null;
+  }
+
+}

Added: branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/SetUser.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/SetUser.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/query/ast/SetUser.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -0,0 +1,100 @@
+/*
+ * 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.query.ast;
+
+import java.net.URI;
+
+
+/**
+ * An AST element for the COMMIT command.
+ *
+ * @created 2007-08-09
+ * @author Paul Gearon
+ * @copyright &copy; 2007 <a href="mailto:pgearon at users.sourceforge.net">Paul Gearon</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class SetUser implements CommandAst {
+  
+  /** The user logging in. */
+  private String user;
+  
+  /** The password for the user, as provided in the UI. */
+  private String password;
+  
+  /** The security domain to log in to. */
+  private URI securityDomain;
+
+  /**
+   * Create a new SetUser command.
+   * @param user The user logging in.
+   * @param password The password for the user.
+   * @param securityDomain The domain to log in to.
+   */
+  public SetUser(String user, String password, URI securityDomain) {
+    this.user = user;
+    this.password = password;
+    this.securityDomain = securityDomain;
+  }
+  
+  /**
+   * Indicates that this operation may require network access.
+   * @return <code>false</code> as network access may be needed.
+   */
+  public boolean isLocalOperation() {
+    return false;
+  }
+
+
+  /**
+   * Indicates that this operation is not specific to a UI.
+   * @return <code>false</code> as operation is not specific to UIs.
+   */
+  public boolean isUICommand() {
+    return false;
+  }
+
+
+  /**
+   * Requests a server URI for this operation.  None available, as it
+   * operates on the local connection.
+   * @return <code>null</code>
+   */
+  public URI getServerURI() {
+    return null;
+  }
+
+  /**
+   * Retrieves the user name.
+   * @return the user
+   */
+  public String getUser() {
+    return user;
+  }
+
+  /**
+   * Retrieves the user password.
+   * @return the password
+   */
+  public String getPassword() {
+    return password;
+  }
+
+  /**
+   * Retrieves the URI of the security domain.
+   * @return the securityDomain
+   */
+  public URI getSecurityDomain() {
+    return securityDomain;
+  }
+
+}

Modified: branches/nw-interface/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphUnitTest.java
===================================================================
--- branches/nw-interface/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphUnitTest.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphUnitTest.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -305,7 +305,7 @@
    */
   private void createModel(URI modelURI) throws Exception {
 
-    this.session.createModel(modelURI, Session.MULGARA_MODEL_URI);
+    this.session.createModel(modelURI, Session.MULGARA_GRAPH_URI);
   }
 
   /**

Modified: branches/nw-interface/src/jar/jrdf/java/org/mulgara/jrdf/JRDFLocalGraphUnitTest.java
===================================================================
--- branches/nw-interface/src/jar/jrdf/java/org/mulgara/jrdf/JRDFLocalGraphUnitTest.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/jrdf/java/org/mulgara/jrdf/JRDFLocalGraphUnitTest.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -220,7 +220,7 @@
    */
   private void createModel(URI modelURI) throws Exception {
 
-    this.session.createModel(modelURI, Session.MULGARA_MODEL_URI);
+    this.session.createModel(modelURI, Session.MULGARA_GRAPH_URI);
   }
 
   /**

Modified: branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelExpression.java
===================================================================
--- branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelExpression.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelExpression.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -67,7 +67,7 @@
    *
    * @return a set containing the {@link URI}s of the databases
    */
-  public Set getDatabaseURIs();
+  public Set<URI> getDatabaseURIs();
 
   /**
    * Generate the WHERE constraint equivalent to this FROM constraint. This

Modified: branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelIntersection.java
===================================================================
--- branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelIntersection.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelIntersection.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -70,15 +70,7 @@
   }
 
   /**
-   * METHOD TO DO
-   *
-   * @param constraint PARAMETER TO DO
-   * @param transformation PARAMETER TO DO
-   * @param modelProperty PARAMETER TO DO
-   * @param systemModel PARAMETER TO DO
-   * @param variableFactory PARAMETER TO DO
-   * @return RETURNED VALUE TO DO
-   * @throws TransformationException EXCEPTION TO DO
+   * {@inheritDoc}
    */
   public ConstraintExpression toConstraintExpression(Constraint constraint,
 

Modified: branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelLiteral.java
===================================================================
--- branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelLiteral.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelLiteral.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -122,9 +122,10 @@
   /**
    * @return an empty {@link Set}
    */
-  public Set getDatabaseURIs() {
+  @SuppressWarnings("unchecked")
+  public Set<URI> getDatabaseURIs() {
 
-    return Collections.EMPTY_SET;
+    return (Set<URI>)Collections.EMPTY_SET;
   }
 
   //

Modified: branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelOperation.java
===================================================================
--- branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelOperation.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelOperation.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -28,6 +28,7 @@
 package org.mulgara.query;
 
 // Java 2 standard packages
+import java.net.URI;
 import java.util.*;
 
 /**
@@ -110,9 +111,9 @@
    *
    * @return The DatabaseURIs value
    */
-  public Set getDatabaseURIs() {
+  public Set<URI> getDatabaseURIs() {
 
-    Set databaseURIs = new HashSet();
+    Set<URI> databaseURIs = new HashSet<URI>();
     databaseURIs.addAll(lhs.getDatabaseURIs());
     databaseURIs.addAll(rhs.getDatabaseURIs());
 
@@ -144,15 +145,15 @@
   }
 
   /**
-   * METHOD TO DO
+   * Transform to an equivalent WHERE clause expression.
    *
-   * @param constraint PARAMETER TO DO
-   * @param transformation PARAMETER TO DO
+   * @param constraint The constraint to transform with this expression.
+   * @param transformation The transformation to apply to the constraint leaf nodes.
    * @param modelProperty PARAMETER TO DO
-   * @param systemModel PARAMETER TO DO
-   * @param variableFactory PARAMETER TO DO
-   * @return RETURNED VALUE TO DO
-   * @throws TransformationException EXCEPTION TO DO
+   * @param systemModel name of the system model
+   * @param variableFactory factory for building variables
+   * @return A {@link ConstraintExpression} that represents the transformed constraint.
+   * @throws TransformationException Unable to perform the transformation
    */
   public abstract ConstraintExpression toConstraintExpression(
       Constraint constraint,
@@ -164,6 +165,7 @@
       // #SYSTEM
       VariableFactory variableFactory) throws TransformationException;
 
+  
   /**
    * Transform the left and right hand sides of this operation.
    *
@@ -178,70 +180,63 @@
   }
 
   /**
-   * METHOD TO DO
+   * Compares this model expression to another object. Compares true if of the same
+   * expression type (intersection/partition/union) and operates on objects that also
+   * compare equal.
    *
-   * @param m PARAMETER TO DO
-   * @return RETURNED VALUE TO DO
+   * @param m The object to compare against.
+   * @return <code>true</code> if the objects are the same type,
+   *         and applied to the same operands 
    */
   public boolean equals(Object m) {
+    
+    if (!(m instanceof ModelOperation)) return false;
+    if ((m == null) || !m.getClass().equals(getClass())) return false;
+    if (m == this) return true;
 
-    if ( (m == null) || m.getClass().equals(getClass())) {
+    Class<?> type = m.getClass();
 
-      return false;
-    }
+    Set<ModelExpression> otherExpressions = new HashSet<ModelExpression>();
+    ((ModelOperation)m).flattenExpression(otherExpressions, type);
 
-    if (m == this) {
-
-      return true;
-    }
-
-    Class type = m.getClass();
-
-    Set otherExpressions = new HashSet();
-    ( (ModelOperation) m).flattenExpression(otherExpressions, type);
-
-    Set myExpressions = new HashSet();
+    Set<ModelExpression> myExpressions = new HashSet<ModelExpression>();
     flattenExpression(myExpressions, type);
 
     return myExpressions.equals(otherExpressions);
   }
 
   /**
-   * METHOD TO DO
+   * Creates a hash code, based on the child expressions and the current operation type.
    *
-   * @return RETURNED VALUE TO DO
+   * @return The hash code for this object.
    */
   public int hashCode() {
 
-    Set myExpressions = new HashSet();
+    Set<ModelExpression> myExpressions = new HashSet<ModelExpression>();
     flattenExpression(myExpressions, getClass());
 
     return (getClass().hashCode() * 7) + myExpressions.hashCode();
   }
 
   /**
-   * METHOD TO DO
+   * Traverse down the binary tree of the current object, and merge any nodes
+   * of the current type into a flattened set.
    *
-   * @param expressions PARAMETER TO DO
-   * @param type PARAMETER TO DO
+   * @param expressions The set to be built up containing all nodes being
+   *        operated on in the same way.
+   * @param type The class representing the operation type.
    */
-  private void flattenExpression(Set expressions, Class type) {
+  private void flattenExpression(Set<ModelExpression> expressions, Class<?> type) {
 
     if (lhs.getClass().equals(type)) {
-
-      ( (ModelOperation) lhs).flattenExpression(expressions, type);
-    }
-    else {
-
+      ((ModelOperation)lhs).flattenExpression(expressions, type);
+    } else {
       expressions.add(lhs);
     }
 
     if (rhs.getClass().equals(type)) {
-
-      ( (ModelOperation) rhs).flattenExpression(expressions, type);
-    }
-    else {
-
+      ((ModelOperation)rhs).flattenExpression(expressions, type);
+    } else {
       expressions.add(rhs);
     }
   }
@@ -252,20 +247,16 @@
   public Object clone() {
 
     try {
+      ModelOperation cloned = (ModelOperation)super.clone();
 
-      ModelOperation cloned = (ModelOperation) super.clone();
-
       // Copy database URIs.
-      cloned.lhs = (ModelExpression) lhs.clone();
-      cloned.rhs = (ModelExpression) rhs.clone();
+      cloned.lhs = (ModelExpression)lhs.clone();
+      cloned.rhs = (ModelExpression)rhs.clone();
 
       return cloned;
+    } catch (CloneNotSupportedException e) {
+      throw new RuntimeException("ModelOperation subclass " + getClass() + " not cloneable");
     }
-    catch (CloneNotSupportedException e) {
-      throw new RuntimeException(
-          "ModelOperation subclass " + getClass() + " not cloneable"
-          );
-    }
   }
 
 

Modified: branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelPartition.java
===================================================================
--- branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelPartition.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelPartition.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -83,15 +83,7 @@
   }
 
   /**
-   * METHOD TO DO
-   *
-   * @param constraint PARAMETER TO DO
-   * @param transformation PARAMETER TO DO
-   * @param modelProperty PARAMETER TO DO
-   * @param systemModel PARAMETER TO DO
-   * @param variableFactory PARAMETER TO DO
-   * @return RETURNED VALUE TO DO
-   * @throws TransformationException EXCEPTION TO DO
+   * {@inheritDoc}
    */
   public ConstraintExpression toConstraintExpression(Constraint constraint,
 

Modified: branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelResource.java
===================================================================
--- branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelResource.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelResource.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -107,7 +107,8 @@
    *   the server if this is a Java RMI or BEEP model, or the empty {@link Set}
    *   otherwise
    */
-  public Set getDatabaseURIs() {
+  @SuppressWarnings("unchecked")
+  public Set<URI> getDatabaseURIs() {
 
     try {
 
@@ -121,18 +122,13 @@
                                              uri.getPath(),
                                              null,
                                              null));
+      } else {
+        return (Set<URI>)Collections.EMPTY_SET;
       }
-      else {
-
-        return Collections.EMPTY_SET;
-      }
+    } catch (URISyntaxException e) {
+      throw new RuntimeException("Couldn't truncate model URI " + uri + " to obtain a database URI");
     }
-    catch (URISyntaxException e) {
 
-      throw new RuntimeException("Couldn't truncate model URI " + uri +
-          " to obtain a database URI");
-    }
-
   }
 
   //

Modified: branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelUnion.java
===================================================================
--- branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelUnion.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/query/java/org/mulgara/query/ModelUnion.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -70,15 +70,7 @@
   }
 
   /**
-   * METHOD TO DO
-   *
-   * @param constraint PARAMETER TO DO
-   * @param transformation PARAMETER TO DO
-   * @param modelProperty PARAMETER TO DO
-   * @param systemModel PARAMETER TO DO
-   * @param variableFactory PARAMETER TO DO
-   * @return RETURNED VALUE TO DO
-   * @throws TransformationException EXCEPTION TO DO
+   * {@inheritDoc}
    */
   public ConstraintExpression toConstraintExpression(Constraint constraint,
 

Modified: branches/nw-interface/src/jar/query/java/org/mulgara/query/Query.java
===================================================================
--- branches/nw-interface/src/jar/query/java/org/mulgara/query/Query.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/query/java/org/mulgara/query/Query.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -29,10 +29,12 @@
 
 // Java 2 standard packages;
 import java.io.*;
+import java.net.URI;
 import java.util.*;
 
 // Third party packages
 import org.apache.log4j.*;
+import org.mulgara.query.ast.CommandAst;
 
 /**
  * An ITQL query. This is a data structure used as an argument to the
@@ -55,7 +57,7 @@
  *
  * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
  */
-public class Query implements Cloneable, Serializable {
+public class Query implements Cloneable, Serializable, CommandAst {
 
  /**
   * Allow newer compiled version of the stub to operate when changes
@@ -516,4 +518,29 @@
     }
     out.defaultWriteObject();
   }
+
+  /**
+   * Operation can only be run by a server.
+   * @return <code>false</code> as this is AST for a server.
+   */
+  public boolean isLocalOperation() {
+    return false;
+  }
+
+  /**
+   * Operation is not restricted to a user interface.
+   * @return <code>false</code> as this operation has no effect on a UI.
+   */
+  public boolean isUICommand() {
+    return false;
+  }
+
+  /**
+   * Gets the associated server for a non-local operation.
+   * @return the server URI, or <code>null</code> if the data should be found locally.
+   */
+  public URI getServerURI() {
+    Set<URI> dbURIs = getModelExpression().getDatabaseURIs();
+    return dbURIs.isEmpty() ? null : dbURIs.iterator().next();
+  }
 }

Modified: branches/nw-interface/src/jar/query/java/org/mulgara/server/Session.java
===================================================================
--- branches/nw-interface/src/jar/query/java/org/mulgara/server/Session.java	2007-08-09 17:48:13 UTC (rev 346)
+++ branches/nw-interface/src/jar/query/java/org/mulgara/server/Session.java	2007-08-10 21:12:09 UTC (rev 347)
@@ -69,7 +69,7 @@
    * This constant can be passed to {@link #createModel} to indicate that a
    * normal model backed by a triple store is required.
    */
-  public final URI MULGARA_MODEL_URI = ConstantFactory.getMulgaraModelURI();
+  public final URI MULGARA_GRAPH_URI = URI.create(Mulgara.NAMESPACE + "Model");
 
   /**
    * Insert statements into a model.
@@ -177,7 +177,7 @@
 
   /**
    * Creates a new model of a given type.  The standard model type is
-   * {@link #MULGARA_MODEL_URI}.
+   * {@link #MULGARA_GRAPH_URI}.
    *
    * @param modelURI the {@link URI} of the new model
    * @param modelTypeURI the {@link URI} identifying the type of model to use
@@ -303,19 +303,4 @@
    */
   public void login(URI securityDomain, String username, char[] password);
 
-  /**
-   * This class is just a devious way to get static initialization for the
-   * {@link Session} interface.
-   */
-  abstract class ConstantFactory {
-
-    static URI getMulgaraModelURI() {
-      try {
-        return new URI(Mulgara.NAMESPACE + "Model");
-      }
-       catch (URISyntaxException e) {
-        throw new Error("Bad hardcoded URI");
-      }
-    }
-  }
 }




More information about the Mulgara-svn mailing list