[Mulgara-svn] r157 - in trunk: conf data jxdata/iTQL/data_types jxdata/iTQL/having_queries jxdata/iTQL/standard_queries jxdata/iTQL/transitive jxdata/iTQL/walk src/jar/jrdf/java/org/mulgara/jrdf src/jar/query/java/org/mulgara/query/rdf src/jar/resolver/java/org/mulgara/resolver src/jar/resolver-filesystem/java/org/mulgara/resolver/filesystem src/jar/resolver-gis/java/org/mulgara/resolver/gis src/jar/resolver-lucene/java/org/mulgara/resolver/lucene src/jar/resolver-memory/java/org/mulgara/resolver/memory src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype src/jar/resolver-prefix/java/org/mulgara/resolver/prefix src/jar/resolver-relational/java/org/mulgara/resolver/relational src/jar/resolver-spi/java/org/mulgara/content src/jar/resolver-spi/java/org/mulgara/resolver/spi src/jar/resolver-store/java/org/mulgara/resolver/store src/jar/resolver-test/java/org/mulgara/resolver/test src/jar/resolver-url/java/org/mulgara/resolver/url src/jar/resolver-view/java/org/mulgara/resolver/view src/jar/resolver-xsd/java/org/mulgara/resolver/xsd src/jar/server-rmi/java/org/mulgara/server/rmi
andrae at mulgara.org
andrae at mulgara.org
Wed Jan 3 21:32:44 UTC 2007
Author: andrae
Date: 2007-01-03 15:32:43 -0600 (Wed, 03 Jan 2007)
New Revision: 157
Added:
trunk/data/xatest-model1.rdf
trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/EnlistableResource.java
trunk/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java
trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/TransactionOperation.java
Removed:
trunk/src/jar/resolver/java/org/mulgara/resolver/AnswerDatabaseSession.java
Modified:
trunk/conf/log4j-mulgara.xml
trunk/jxdata/iTQL/data_types/queryResult34.txt
trunk/jxdata/iTQL/having_queries/queryResult10.txt
trunk/jxdata/iTQL/having_queries/queryResult15.txt
trunk/jxdata/iTQL/standard_queries/queryResult17.txt
trunk/jxdata/iTQL/standard_queries/queryResult18.txt
trunk/jxdata/iTQL/standard_queries/queryResult3.txt
trunk/jxdata/iTQL/transitive/result13.txt
trunk/jxdata/iTQL/transitive/result14.txt
trunk/jxdata/iTQL/walk/queryResult7.txt
trunk/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphElementFactory.java
trunk/src/jar/jrdf/java/org/mulgara/jrdf/LocalJRDFSession.java
trunk/src/jar/query/java/org/mulgara/query/rdf/VariableNodeImpl.java
trunk/src/jar/resolver-filesystem/java/org/mulgara/resolver/filesystem/FileSystemResolver.java
trunk/src/jar/resolver-gis/java/org/mulgara/resolver/gis/ReadOnlyGISResolver.java
trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneResolver.java
trunk/src/jar/resolver-memory/java/org/mulgara/resolver/memory/MemoryResolver.java
trunk/src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype/NodeTypeResolver.java
trunk/src/jar/resolver-prefix/java/org/mulgara/resolver/prefix/PrefixResolver.java
trunk/src/jar/resolver-relational/java/org/mulgara/resolver/relational/RelationalResolver.java
trunk/src/jar/resolver-spi/java/org/mulgara/content/ContentResolver.java
trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/LocalSession.java
trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/Resolver.java
trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java
trunk/src/jar/resolver-test/java/org/mulgara/resolver/test/TestResolver.java
trunk/src/jar/resolver-url/java/org/mulgara/resolver/url/URLResolver.java
trunk/src/jar/resolver-view/java/org/mulgara/resolver/view/ViewResolver.java
trunk/src/jar/resolver-xsd/java/org/mulgara/resolver/xsd/XSDResolver.java
trunk/src/jar/resolver/java/org/mulgara/resolver/AnswerOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/BasicDatabaseSessionUnitTest.java
trunk/src/jar/resolver/java/org/mulgara/resolver/CacheResolver.java
trunk/src/jar/resolver/java/org/mulgara/resolver/ConstraintOperations.java
trunk/src/jar/resolver/java/org/mulgara/resolver/CreateModelOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java
trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java
trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java
trunk/src/jar/resolver/java/org/mulgara/resolver/InternalResolver.java
trunk/src/jar/resolver/java/org/mulgara/resolver/LocalJRDFDatabaseSession.java
trunk/src/jar/resolver/java/org/mulgara/resolver/ModifyModelOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
trunk/src/jar/resolver/java/org/mulgara/resolver/OperationContext.java
trunk/src/jar/resolver/java/org/mulgara/resolver/QueryOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/RemoveModelOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/SetModelOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/StatusFormat.java
trunk/src/jar/resolver/java/org/mulgara/resolver/StringPoolSession.java
trunk/src/jar/resolver/java/org/mulgara/resolver/SubqueryAnswer.java
trunk/src/jar/resolver/java/org/mulgara/resolver/SubqueryAnswerUnitTest.java
trunk/src/jar/resolver/java/org/mulgara/resolver/TransactionalAnswer.java
trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/BlankNodeWrapperAnswer.java
Log:
merge -r 114:139 ../braches/xafix-impl
Merges versions 114 through 139 of xafix-impl into trunk.
This reflects the new transaction architecture work committed into HEAD.
The xafix-impl branch is now closed.
Modified: trunk/conf/log4j-mulgara.xml
===================================================================
--- trunk/conf/log4j-mulgara.xml 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/conf/log4j-mulgara.xml 2007-01-03 21:32:43 UTC (rev 157)
@@ -62,10 +62,8 @@
<category name="org.mulgara.content.rdfxml.Parser">
<priority value="INFO"/>
</category>
- -->
- <!--
<category name="org.mulgara.resolver.DatabaseSession">
- <priority value="debug"/>
+ <priority value="info"/>
</category>
-->
Copied: trunk/data/xatest-model1.rdf (from rev 139, branches/xafix-impl/data/xatest-model1.rdf)
Modified: trunk/jxdata/iTQL/data_types/queryResult34.txt
===================================================================
--- trunk/jxdata/iTQL/data_types/queryResult34.txt 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/jxdata/iTQL/data_types/queryResult34.txt 2007-01-03 21:32:43 UTC (rev 157)
@@ -1,6 +1,6 @@
ItqlInterpreter error - org.mulgara.query.QueryException: Could not commit insert
Caused by: (QueryException) Could not commit insert
-Caused by: (QueryException) javax.transaction.RollbackException: null
+Caused by: (QueryException) org.mulgara.resolver.MulgaraTransactionException: Failed transaction finalised. (ROLLBACK)
Caused by: (QueryException) org.mulgara.resolver.spi.ResolverException: Unable to read input statements
Caused by: (QueryException) org.mulgara.query.TuplesException: Failed to localize node
Caused by: (QueryException) org.mulgara.resolver.spi.LocalizeException: Unable to localize "<test>test escape char</foo>"^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral> - Couldn't convert Node to SPObject
Modified: trunk/jxdata/iTQL/having_queries/queryResult10.txt
===================================================================
--- trunk/jxdata/iTQL/having_queries/queryResult10.txt 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/jxdata/iTQL/having_queries/queryResult10.txt 2007-01-03 21:32:43 UTC (rev 157)
@@ -1,5 +1,5 @@
-ItqlInterpreter error - org.mulgara.query.QueryException: Error ending previous query
-Caused by: (QueryException) Error ending previous query
-Caused by: (QueryException) javax.transaction.RollbackException: null
+ItqlInterpreter error - org.mulgara.query.QueryException: Query failed
+Caused by: (QueryException) Query failed
+Caused by: (QueryException) org.mulgara.resolver.MulgaraTransactionException: Failed transaction finalised. (ROLLBACK)
Caused by: (QueryException) Failed to resolve query
Caused by: (QueryException) org.mulgara.query.TuplesException: No such variable $v in tuples [$s, $k0] (class org.mulgara.resolver.AppendAggregateTuples)
Modified: trunk/jxdata/iTQL/having_queries/queryResult15.txt
===================================================================
--- trunk/jxdata/iTQL/having_queries/queryResult15.txt 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/jxdata/iTQL/having_queries/queryResult15.txt 2007-01-03 21:32:43 UTC (rev 157)
@@ -1,5 +1,5 @@
-ItqlInterpreter error - org.mulgara.query.QueryException: Error ending previous query
-Caused by: (QueryException) Error ending previous query
-Caused by: (QueryException) javax.transaction.RollbackException: null
+ItqlInterpreter error - org.mulgara.query.QueryException: Query failed
+Caused by: (QueryException) Query failed
+Caused by: (QueryException) org.mulgara.resolver.MulgaraTransactionException: Failed transaction finalised. (ROLLBACK)
Caused by: (QueryException) Failed to resolve query
Caused by: (QueryException) org.mulgara.query.TuplesException: No such variable $k0 in tuples [$p, $v, $s] (class org.mulgara.resolver.AppendAggregateTuples)
Modified: trunk/jxdata/iTQL/standard_queries/queryResult17.txt
===================================================================
--- trunk/jxdata/iTQL/standard_queries/queryResult17.txt 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/jxdata/iTQL/standard_queries/queryResult17.txt 2007-01-03 21:32:43 UTC (rev 157)
@@ -1,4 +1,4 @@
ItqlInterpreter error - org.mulgara.query.QueryException: Could not commit insert
Caused by: (QueryException) Could not commit insert
-Caused by: (QueryException) javax.transaction.RollbackException: null
+Caused by: (QueryException) org.mulgara.resolver.MulgaraTransactionException: Failed transaction finalised. (ROLLBACK)
Caused by: (QueryException) rmi://localhost/server1#nomodelexistswiththisname is not a Model
Modified: trunk/jxdata/iTQL/standard_queries/queryResult18.txt
===================================================================
--- trunk/jxdata/iTQL/standard_queries/queryResult18.txt 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/jxdata/iTQL/standard_queries/queryResult18.txt 2007-01-03 21:32:43 UTC (rev 157)
@@ -1,5 +1,5 @@
-ItqlInterpreter error - org.mulgara.query.QueryException: Error ending previous query
-Caused by: (QueryException) Error ending previous query
-Caused by: (QueryException) javax.transaction.RollbackException: null
+ItqlInterpreter error - org.mulgara.query.QueryException: Query failed
+Caused by: (QueryException) Query failed
+Caused by: (QueryException) org.mulgara.resolver.MulgaraTransactionException: Failed transaction finalised. (ROLLBACK)
Caused by: (QueryException) Error resolving [$s $p $o $_from] from mailto:foo at bar.com
Caused by: (QueryException) Unable to extract hostname from: mailto:foo at bar.com
Modified: trunk/jxdata/iTQL/standard_queries/queryResult3.txt
===================================================================
--- trunk/jxdata/iTQL/standard_queries/queryResult3.txt 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/jxdata/iTQL/standard_queries/queryResult3.txt 2007-01-03 21:32:43 UTC (rev 157)
@@ -1,5 +1,5 @@
-ItqlInterpreter error - org.mulgara.query.QueryException: Error ending previous query
-Caused by: (QueryException) Error ending previous query
-Caused by: (QueryException) javax.transaction.RollbackException: null
+ItqlInterpreter error - org.mulgara.query.QueryException: Query failed
+Caused by: (QueryException) Query failed
+Caused by: (QueryException) org.mulgara.resolver.MulgaraTransactionException: Failed transaction finalised. (ROLLBACK)
Caused by: (QueryException) Error resolving [$pmid http://mulgara.org/mulgara/Document#subject "Birds" $_from] from @server@#badmodel
Caused by: (QueryException) @server@#badmodel is not a Model
Modified: trunk/jxdata/iTQL/transitive/result13.txt
===================================================================
--- trunk/jxdata/iTQL/transitive/result13.txt 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/jxdata/iTQL/transitive/result13.txt 2007-01-03 21:32:43 UTC (rev 157)
@@ -1,4 +1,4 @@
-ItqlInterpreter error - org.mulgara.query.QueryException: Error ending previous query
-Caused by: (QueryException) Error ending previous query
-Caused by: (QueryException) javax.transaction.RollbackException: null
+ItqlInterpreter error - org.mulgara.query.QueryException: Query failed
+Caused by: (QueryException) Query failed
+Caused by: (QueryException) org.mulgara.resolver.MulgaraTransactionException: Failed transaction finalised. (ROLLBACK)
Caused by: (QueryException) Predicate in transitive function, $p, currently must be bound to a value.
Modified: trunk/jxdata/iTQL/transitive/result14.txt
===================================================================
--- trunk/jxdata/iTQL/transitive/result14.txt 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/jxdata/iTQL/transitive/result14.txt 2007-01-03 21:32:43 UTC (rev 157)
@@ -1,4 +1,4 @@
-ItqlInterpreter error - org.mulgara.query.QueryException: Error ending previous query
-Caused by: (QueryException) Error ending previous query
-Caused by: (QueryException) javax.transaction.RollbackException: null
+ItqlInterpreter error - org.mulgara.query.QueryException: Query failed
+Caused by: (QueryException) Query failed
+Caused by: (QueryException) org.mulgara.resolver.MulgaraTransactionException: Failed transaction finalised. (ROLLBACK)
Caused by: (QueryException) Predicate in transitive function, $p, currently must be bound to a value.
Modified: trunk/jxdata/iTQL/walk/queryResult7.txt
===================================================================
--- trunk/jxdata/iTQL/walk/queryResult7.txt 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/jxdata/iTQL/walk/queryResult7.txt 2007-01-03 21:32:43 UTC (rev 157)
@@ -1,6 +1,8 @@
ItqlInterpreter error - org.mulgara.query.QueryException: Error getting information for answer
Caused by: (QueryException) Error getting information for answer
+Caused by: (QueryException) org.mulgara.query.TuplesException: Transaction error
+Caused by: (QueryException) org.mulgara.resolver.MulgaraTransactionException: Transaction already in rollback
+Caused by: (QueryException) org.mulgara.resolver.MulgaraTransactionException: Failed transaction finalised. (ROLLBACK)
Caused by: (QueryException) org.mulgara.query.TuplesException: Couldn't evaluate aggregate
Caused by: (QueryException) Failed to resolve subquery
-Caused by: (QueryException) Failure ending previous query
Caused by: (QueryException) The subject: $head and the object: $n are invalid, one must be a variable and the other a fixed value around a predicate.
Modified: trunk/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphElementFactory.java
===================================================================
--- trunk/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphElementFactory.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphElementFactory.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -63,11 +63,10 @@
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
public class JRDFGraphElementFactory implements GraphElementFactory {
-
/**
* Logger. This is named after the class.
*/
- private final static Logger logger =
+ private static final Logger logger =
Logger.getLogger(JRDFGraphElementFactory.class.getName());
/**
@@ -88,65 +87,19 @@
* Returns a new BlankNode.
*
* @return BlankNode
- * @throws GraphElementFactoryException
*/
- public BlankNode createResource() throws GraphElementFactoryException {
- try {
-
- // Check to see if we're in a transaction. If not create a new
- // transaction and perform the operation.
- try {
- jrdfSession.resumeTransactionalBlock();
- }
- catch (IllegalStateException ise) {
- jrdfSession.startTransactionalOperation(true);
-
- try {
- return createBlankNode();
- }
- catch (Throwable e) {
- jrdfSession.rollbackTransactionalBlock(e);
- }
- finally {
- jrdfSession.finishTransactionalOperation("Could not commit insert");
- }
- }
-
- // If no exception was thrown then we have resumed the transaction.
- try {
- return createBlankNode();
- }
- catch (Throwable e) {
- jrdfSession.rollbackTransactionalBlock(e);
- }
- finally {
- try {
- jrdfSession.suspendTransactionalBlock();
- }
- catch (Throwable e) {
- jrdfSession.rollbackTransactionalBlock(e);
- }
- }
- }
- catch (QueryException e) {
- throw new GraphElementFactoryException(e);
- }
- // This should never happen
- throw new GraphElementFactoryException("Failed to create blank node");
+ public BlankNode createResource() {
+ return createBlankNode();
}
/**
- * Create a new blank node - assume current transaction and valid
- * ResolverSession.
+ * Create a new blank node .
*
* @return a newly minted blank node.
- * @throws LocalizeException if there was a failure in localizing the blank
- * node.
*/
- public BlankNode createBlankNode() throws LocalizeException {
- BlankNode tmpBlankNode = new BlankNodeImpl();
- jrdfSession.getResolverSession().localizePersistent(tmpBlankNode);
- return tmpBlankNode;
+ public BlankNode createBlankNode() {
+ BlankNode node = new BlankNodeImpl();
+ return node;
}
/**
Modified: trunk/src/jar/jrdf/java/org/mulgara/jrdf/LocalJRDFSession.java
===================================================================
--- trunk/src/jar/jrdf/java/org/mulgara/jrdf/LocalJRDFSession.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/jrdf/java/org/mulgara/jrdf/LocalJRDFSession.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -49,6 +49,6 @@
*
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
-public interface LocalJRDFSession extends LocalSession, JRDFSession {
+public interface LocalJRDFSession extends JRDFSession {
}
Modified: trunk/src/jar/query/java/org/mulgara/query/rdf/VariableNodeImpl.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/query/rdf/VariableNodeImpl.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/query/java/org/mulgara/query/rdf/VariableNodeImpl.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -75,11 +75,6 @@
private final String variableName;
/**
- * The unique blank node mapping.
- */
- private BlankNodeImpl blankNode = null;
-
- /**
* Create a new variableNode.
*
* @param newVariableName the variable name to set.
@@ -100,26 +95,6 @@
}
/**
- * Sets the blank node for variable.
- *
- * @param newBlankNode the blank node for the variable.
- */
- public void setBlankNode(final BlankNodeImpl newBlankNode) {
-
- blankNode = newBlankNode;
- }
-
- /**
- * Returns the current blank node.
- *
- * @return the current blank node.
- */
- public BlankNodeImpl getBlankNode() {
-
- return blankNode;
- }
-
- /**
* Return itself - variables are immutable.
*
* @return a copy.
@@ -180,6 +155,6 @@
*/
public String toString() {
- return "_variable " + variableName + " :_node" + blankNode;
+ return "_variable " + variableName;
}
}
Added: trunk/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -0,0 +1,1061 @@
+/*
+ * 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):
+ * All tests in this file (c) Netymon Pty Ltd 2006 All rights reserved.
+ *
+ * [NOTE: The text of this Exhibit A may differ slightly from the text
+ * of the notices in the Source Code files of the Original Code. You
+ * should use the text of this Exhibit A rather than the text found in the
+ * Original Code Source Code for Your Modifications.]
+ *
+ */
+
+package org.mulgara.resolver;
+
+// Java 2 standard packages
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.*;
+
+// Third party packages
+import junit.framework.*; // JUnit
+import org.apache.log4j.Logger; // Log4J
+import org.jrdf.vocabulary.RDF; // JRDF
+import org.jrdf.graph.SubjectNode; // JRDF
+import org.jrdf.graph.PredicateNode; // JRDF
+import org.jrdf.graph.ObjectNode; // JRDF
+
+// Locally written packages
+import org.mulgara.query.*;
+import org.mulgara.query.rdf.Mulgara;
+import org.mulgara.query.rdf.URIReferenceImpl;
+import org.mulgara.query.rdf.TripleImpl;
+import org.mulgara.server.Session;
+import org.mulgara.store.StoreException;
+import org.mulgara.store.nodepool.NodePool;
+import org.mulgara.store.stringpool.StringPool;
+import org.mulgara.util.FileUtil;
+
+/**
+* Test case for {@link DatabaseSession}.
+*
+* @created 2006-11-20
+* @author <a href="mailto:andrae at netymon.com">Andrae Muys</a>
+* @company <a href="mailto:mail at netymon.com">Netymon Pty Ltd</a>
+* @copyright © 2004 <a href="http://www.PIsoftware.com/">Plugged In
+* Software Pty Ltd</a>
+* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
+*/
+public class AdvDatabaseSessionUnitTest extends TestCase
+{
+ /** Logger. */
+ private static Logger logger =
+ Logger.getLogger(AdvDatabaseSessionUnitTest.class.getName());
+
+ private static final URI databaseURI;
+
+ private static final URI systemModelURI;
+
+ private static final URI modelURI;
+ private static final URI model2URI;
+ private static final URI model3URI;
+
+ static {
+ try {
+ databaseURI = new URI("local:database");
+ systemModelURI = new URI("local:database#");
+ modelURI = new URI("local:database#model");
+ model2URI = new URI("local:database#model2");
+ model3URI = new URI("local:database#model3");
+ } catch (URISyntaxException e) {
+ throw new Error("Bad hardcoded URI", e);
+ }
+ }
+
+ private static Database database = null;
+
+ public AdvDatabaseSessionUnitTest(String name)
+ {
+ super(name);
+ }
+
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite();
+ suite.addTest(new AdvDatabaseSessionUnitTest("testSetModel"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testBasicQuery"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testConcurrentQuery"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testSubqueryQuery"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testConcurrentSubqueryQuery"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testConcurrentReadWrite"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testExplicitBasicQuery"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testExplicitIsolationQuery"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testExplicitRollbackIsolationQuery"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testExplicitCommitIsolationQuery"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testDatabaseDelete"));
+
+ return suite;
+ }
+
+ /**
+ * Create test objects.
+ */
+ public void setUp() throws Exception {
+ if (database == null) {
+ // Create the persistence directory
+ File persistenceDirectory =
+ new File(new File(System.getProperty("cvs.root")), "testDatabase");
+ if (persistenceDirectory.isDirectory()) {
+ if (!FileUtil.deleteDirectory(persistenceDirectory)) {
+ throw new RuntimeException(
+ "Unable to remove old directory " + persistenceDirectory
+ );
+ }
+ }
+ if (!persistenceDirectory.mkdirs()) {
+ throw new Exception("Unable to create directory "+persistenceDirectory);
+ }
+
+ // Define the the node pool factory
+ String nodePoolFactoryClassName =
+ "org.mulgara.store.nodepool.xa.XANodePoolFactory";
+
+ // Define the string pool factory
+ String stringPoolFactoryClassName =
+ "org.mulgara.store.stringpool.xa.XAStringPoolFactory";
+
+ String tempNodePoolFactoryClassName =
+ "org.mulgara.store.nodepool.memory.MemoryNodePoolFactory";
+
+ // Define the string pool factory
+ String tempStringPoolFactoryClassName =
+ "org.mulgara.store.stringpool.memory.MemoryStringPoolFactory";
+
+ // Define the resolver factory used to manage system models
+ String systemResolverFactoryClassName =
+ "org.mulgara.resolver.store.StatementStoreResolverFactory";
+
+ // Define the resolver factory used to manage system models
+ String tempResolverFactoryClassName =
+ "org.mulgara.resolver.memory.MemoryResolverFactory";
+
+ String ruleLoaderFactoryClassName =
+ "org.mulgara.rules.RuleLoaderFactory";
+
+ // Create a database which keeps its system models on the Java heap
+ database = new Database(
+ databaseURI,
+ persistenceDirectory,
+ null, // no security domain
+ new JotmTransactionManagerFactory(),
+ 0, // default transaction timeout
+ nodePoolFactoryClassName, // persistent
+ new File(persistenceDirectory, "xaNodePool"),
+ stringPoolFactoryClassName, // persistent
+ new File(persistenceDirectory, "xaStringPool"),
+ systemResolverFactoryClassName, // persistent
+ new File(persistenceDirectory, "xaStatementStore"),
+ tempNodePoolFactoryClassName, // temporary nodes
+ null, // no dir for temp nodes
+ tempStringPoolFactoryClassName, // temporary strings
+ null, // no dir for temp strings
+ tempResolverFactoryClassName, // temporary models
+ null, // no dir for temp models
+ "", // no rule loader
+ "org.mulgara.content.rdfxml.RDFXMLContentHandler");
+
+ database.addResolverFactory("org.mulgara.resolver.url.URLResolverFactory", null);
+ }
+ }
+
+
+ /**
+ * The teardown method for JUnit
+ */
+ public void tearDown()
+ {
+ }
+
+ //
+ // Test cases
+ //
+
+ /**
+ * Test the {@link DatabaseSession#setModel} method.
+ */
+ public void testSetModel() throws URISyntaxException
+ {
+ logger.info("testSetModel");
+ URI fileURI = new File("data/xatest-model1.rdf").toURI();
+
+ try {
+ // Load some test data
+ Session session = database.newSession();
+ try {
+ session.createModel(modelURI, null);
+ session.setModel(modelURI, new ModelResource(fileURI));
+ } finally {
+ session.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+
+ public void testBasicQuery() throws URISyntaxException {
+ logger.info("Testing basicQuery");
+
+ try {
+ // Load some test data
+ Session session = database.newSession();
+ try {
+ Variable subjectVariable = new Variable("subject");
+ Variable predicateVariable = new Variable("predicate");
+ Variable objectVariable = new Variable("object");
+
+ List selectList = new ArrayList(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ // Evaluate the query
+ Answer answer = session.query(new Query(
+ selectList, // SELECT
+ new ModelResource(modelURI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Arrays.asList(new Order[] { // ORDER BY
+ new Order(subjectVariable, true),
+ new Order(predicateVariable, true),
+ new Order(objectVariable, true)
+ }),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+ String[][] results = {
+ { "test:s01", "test:p01", "test:o01" },
+ { "test:s01", "test:p02", "test:o01" },
+ { "test:s01", "test:p02", "test:o02" },
+ { "test:s01", "test:p03", "test:o02" },
+ { "test:s02", "test:p03", "test:o02" },
+ { "test:s02", "test:p04", "test:o02" },
+ { "test:s02", "test:p04", "test:o03" },
+ { "test:s02", "test:p05", "test:o03" },
+ { "test:s03", "test:p01", "test:o01" },
+ { "test:s03", "test:p05", "test:o03" },
+ { "test:s03", "test:p06", "test:o01" },
+ { "test:s03", "test:p06", "test:o03" },
+ };
+ compareResults(results, answer);
+ answer.close();
+ } finally {
+ session.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+
+ public void testConcurrentQuery() throws URISyntaxException {
+ logger.info("Testing concurrentQuery");
+
+ try {
+ // Load some test data
+ Session session = database.newSession();
+ try {
+ Variable subjectVariable = new Variable("subject");
+ Variable predicateVariable = new Variable("predicate");
+ Variable objectVariable = new Variable("object");
+
+ List selectList = new ArrayList(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ // Evaluate the query
+ Answer answer1 = session.query(new Query(
+ selectList, // SELECT
+ new ModelResource(modelURI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Collections.singletonList( // ORDER BY
+ new Order(subjectVariable, true)
+ ),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+
+ Answer answer2 = session.query(new Query(
+ selectList, // SELECT
+ new ModelResource(modelURI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Collections.singletonList( // ORDER BY
+ new Order(subjectVariable, true)
+ ),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+
+ compareResults(answer1, answer2);
+
+ answer1.close();
+ answer2.close();
+ } finally {
+ session.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+
+ public void testSubqueryQuery() throws URISyntaxException {
+ logger.info("Testing subqueryQuery");
+
+ try {
+ // Load some test data
+ Session session = database.newSession();
+ try {
+ Variable subjectVariable = new Variable("subject");
+ Variable predicateVariable = new Variable("predicate");
+ Variable objectVariable = new Variable("object");
+
+ List selectList = new ArrayList(3);
+ selectList.add(subjectVariable);
+ selectList.add(new Subquery(new Variable("k0"), new Query(
+ Collections.singletonList(objectVariable),
+ new ModelResource(modelURI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Collections.singletonList( // ORDER BY
+ new Order(objectVariable, true)
+ ),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ )));
+
+
+ // Evaluate the query
+ Answer answer = session.query(new Query(
+ selectList, // SELECT
+ new ModelResource(modelURI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ new URIReferenceImpl(new URI("test:p03")),
+ objectVariable),
+ null, // HAVING
+ Collections.singletonList( // ORDER BY
+ new Order(subjectVariable, true)
+ ),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+
+ answer.beforeFirst();
+
+ assertTrue(answer.next());
+ assertEquals(new URIReferenceImpl(new URI("test:s01")),
+ answer.getObject(0));
+ Answer sub1 = (Answer)answer.getObject(1);
+ compareResults(new String[][] { new String[] { "test:o01" },
+ new String[] { "test:o02" } }, sub1);
+ sub1.close();
+
+ assertTrue(answer.next());
+ assertEquals(new URIReferenceImpl(new URI("test:s02")),
+ answer.getObject(0));
+ Answer sub2 = (Answer)answer.getObject(1);
+ compareResults(new String[][] { new String[] { "test:o02" },
+ new String[] { "test:o03" } }, sub2);
+ // Leave sub2 open.
+
+ assertFalse(answer.next());
+ answer.close();
+ sub2.close();
+ } finally {
+ session.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+
+ public void testConcurrentSubqueryQuery() throws URISyntaxException {
+ logger.info("Testing concurrentSubqueryQuery");
+
+ try {
+ // Load some test data
+ Session session = database.newSession();
+ try {
+ Variable subjectVariable = new Variable("subject");
+ Variable predicateVariable = new Variable("predicate");
+ Variable objectVariable = new Variable("object");
+
+ List selectList = new ArrayList(3);
+ selectList.add(subjectVariable);
+ selectList.add(new Subquery(new Variable("k0"), new Query(
+ Collections.singletonList(objectVariable),
+ new ModelResource(modelURI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Collections.singletonList( // ORDER BY
+ new Order(objectVariable, true)
+ ),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ )));
+
+
+ // Evaluate the query
+ Answer answer = session.query(new Query(
+ selectList, // SELECT
+ new ModelResource(modelURI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ new URIReferenceImpl(new URI("test:p03")),
+ objectVariable),
+ null, // HAVING
+ Collections.singletonList( // ORDER BY
+ new Order(subjectVariable, true)
+ ),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+
+ answer.beforeFirst();
+
+ assertTrue(answer.next());
+ assertEquals(new URIReferenceImpl(new URI("test:s01")),
+ answer.getObject(0));
+ Answer sub1 = (Answer)answer.getObject(1);
+ assertTrue(answer.next());
+ assertEquals(new URIReferenceImpl(new URI("test:s02")),
+ answer.getObject(0));
+ Answer sub2 = (Answer)answer.getObject(1);
+ assertFalse(answer.next());
+
+ assertEquals(1, sub1.getNumberOfVariables());
+ assertEquals(1, sub2.getNumberOfVariables());
+ sub1.beforeFirst();
+ sub2.beforeFirst();
+ assertTrue(sub1.next());
+ assertTrue(sub2.next());
+ assertEquals(new URIReferenceImpl(new URI("test:o01")), sub1.getObject(0));
+ assertEquals(new URIReferenceImpl(new URI("test:o02")), sub2.getObject(0));
+ assertTrue(sub1.next());
+ assertTrue(sub2.next());
+ assertEquals(new URIReferenceImpl(new URI("test:o02")), sub1.getObject(0));
+ assertEquals(new URIReferenceImpl(new URI("test:o03")), sub2.getObject(0));
+ assertFalse(sub1.next());
+ assertFalse(sub2.next());
+
+ answer.close();
+ } finally {
+ session.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+
+ /**
+ * Note: What this test does is a really bad idea - there is no
+ * isolation provided as each operation is within its own
+ * transaction. It does however provide a good test.
+ */
+ public void testConcurrentReadWrite() throws URISyntaxException {
+ logger.info("Testing concurrentReadWrite");
+
+ try {
+ Session session = database.newSession();
+
+ session.createModel(model2URI, null);
+
+ try {
+ Variable subjectVariable = new Variable("subject");
+ Variable predicateVariable = new Variable("predicate");
+ Variable objectVariable = new Variable("object");
+
+ List selectList = new ArrayList(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ // Evaluate the query
+ Answer answer = session.query(new Query(
+ selectList, // SELECT
+ new ModelResource(modelURI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Arrays.asList(new Order[] { // ORDER BY
+ new Order(subjectVariable, true),
+ new Order(predicateVariable, true),
+ new Order(objectVariable, true)
+ }),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+
+ answer.beforeFirst();
+ while (answer.next()) {
+ session.insert(model2URI, Collections.singleton(new TripleImpl(
+ (SubjectNode)answer.getObject(0),
+ (PredicateNode)answer.getObject(1),
+ (ObjectNode)answer.getObject(2))));
+ }
+ answer.close();
+
+ Answer answer2 = session.query(new Query(
+ selectList, // SELECT
+ new ModelResource(model2URI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Arrays.asList(new Order[] { // ORDER BY
+ new Order(subjectVariable, true),
+ new Order(predicateVariable, true),
+ new Order(objectVariable, true)
+ }),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+ String[][] results = {
+ { "test:s01", "test:p01", "test:o01" },
+ { "test:s01", "test:p02", "test:o01" },
+ { "test:s01", "test:p02", "test:o02" },
+ { "test:s01", "test:p03", "test:o02" },
+ { "test:s02", "test:p03", "test:o02" },
+ { "test:s02", "test:p04", "test:o02" },
+ { "test:s02", "test:p04", "test:o03" },
+ { "test:s02", "test:p05", "test:o03" },
+ { "test:s03", "test:p01", "test:o01" },
+ { "test:s03", "test:p05", "test:o03" },
+ { "test:s03", "test:p06", "test:o01" },
+ { "test:s03", "test:p06", "test:o03" },
+ };
+ compareResults(results, answer2);
+ answer2.close();
+
+ session.removeModel(model2URI);
+ } finally {
+ session.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+
+ public void testExplicitBasicQuery() throws URISyntaxException {
+ logger.info("Testing basicQuery");
+
+ try {
+ // Load some test data
+ Session session = database.newSession();
+ try {
+ session.setAutoCommit(false);
+ Variable subjectVariable = new Variable("subject");
+ Variable predicateVariable = new Variable("predicate");
+ Variable objectVariable = new Variable("object");
+
+ List selectList = new ArrayList(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ // Evaluate the query
+ Answer answer = session.query(new Query(
+ selectList, // SELECT
+ new ModelResource(modelURI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Arrays.asList(new Order[] { // ORDER BY
+ new Order(subjectVariable, true),
+ new Order(predicateVariable, true),
+ new Order(objectVariable, true)
+ }),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+ String[][] results = {
+ { "test:s01", "test:p01", "test:o01" },
+ { "test:s01", "test:p02", "test:o01" },
+ { "test:s01", "test:p02", "test:o02" },
+ { "test:s01", "test:p03", "test:o02" },
+ { "test:s02", "test:p03", "test:o02" },
+ { "test:s02", "test:p04", "test:o02" },
+ { "test:s02", "test:p04", "test:o03" },
+ { "test:s02", "test:p05", "test:o03" },
+ { "test:s03", "test:p01", "test:o01" },
+ { "test:s03", "test:p05", "test:o03" },
+ { "test:s03", "test:p06", "test:o01" },
+ { "test:s03", "test:p06", "test:o03" },
+ };
+ compareResults(results, answer);
+
+ session.setAutoCommit(true);
+
+ // Should throw an Exception here as commit should close answer
+ boolean thrown = false;;
+ try {
+ answer.beforeFirst();
+ } catch (TuplesException et) {
+ thrown = true;
+ } finally {
+ assertTrue("Answer failed to throw exception, should be closed by commit",
+ thrown);
+ }
+ } finally {
+ session.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+
+ public void testExplicitIsolationQuery() throws URISyntaxException
+ {
+ logger.info("testExplicitIsolationQuery");
+ URI fileURI = new File("data/xatest-model1.rdf").toURI();
+
+ try {
+ Session session1 = database.newSession();
+ try {
+ Session session2 = database.newSession();
+ try {
+ session1.createModel(model3URI, null);
+ session1.setAutoCommit(false);
+ session1.setModel(model3URI, new ModelResource(fileURI));
+
+ Variable subjectVariable = new Variable("subject");
+ Variable predicateVariable = new Variable("predicate");
+ Variable objectVariable = new Variable("object");
+
+ List selectList = new ArrayList(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ // Evaluate the query
+ Answer answer = session2.query(new Query(
+ selectList, // SELECT
+ new ModelResource(model3URI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Arrays.asList(new Order[] { // ORDER BY
+ new Order(subjectVariable, true),
+ new Order(predicateVariable, true),
+ new Order(objectVariable, true)
+ }),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+
+ session1.setAutoCommit(true);
+
+ selectList = new ArrayList(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ // Evaluate the query
+ answer = session2.query(new Query(
+ selectList, // SELECT
+ new ModelResource(model3URI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Arrays.asList(new Order[] { // ORDER BY
+ new Order(subjectVariable, true),
+ new Order(predicateVariable, true),
+ new Order(objectVariable, true)
+ }),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+
+ String[][] results = {
+ { "test:s01", "test:p01", "test:o01" },
+ { "test:s01", "test:p02", "test:o01" },
+ { "test:s01", "test:p02", "test:o02" },
+ { "test:s01", "test:p03", "test:o02" },
+ { "test:s02", "test:p03", "test:o02" },
+ { "test:s02", "test:p04", "test:o02" },
+ { "test:s02", "test:p04", "test:o03" },
+ { "test:s02", "test:p05", "test:o03" },
+ { "test:s03", "test:p01", "test:o01" },
+ { "test:s03", "test:p05", "test:o03" },
+ { "test:s03", "test:p06", "test:o01" },
+ { "test:s03", "test:p06", "test:o03" },
+ };
+ compareResults(results, answer);
+ answer.close();
+
+ session1.removeModel(model3URI);
+ } finally {
+ session2.close();
+ }
+ } finally {
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+
+ public void testExplicitRollbackIsolationQuery() throws URISyntaxException
+ {
+ logger.info("testExplicitRollbackIsolationQuery");
+ URI fileURI = new File("data/xatest-model1.rdf").toURI();
+
+ try {
+ Session session1 = database.newSession();
+ try {
+ Session session2 = database.newSession();
+ try {
+ session1.createModel(model3URI, null);
+ session1.setAutoCommit(false);
+ session1.setModel(model3URI, new ModelResource(fileURI));
+
+ Variable subjectVariable = new Variable("subject");
+ Variable predicateVariable = new Variable("predicate");
+ Variable objectVariable = new Variable("object");
+
+ List selectList = new ArrayList(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ // Evaluate the query
+ Answer answer = session2.query(new Query(
+ selectList, // SELECT
+ new ModelResource(model3URI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Arrays.asList(new Order[] { // ORDER BY
+ new Order(subjectVariable, true),
+ new Order(predicateVariable, true),
+ new Order(objectVariable, true)
+ }),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+
+ session1.rollback();
+ session1.setAutoCommit(true);
+
+ selectList = new ArrayList(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ // Evaluate the query
+ answer = session2.query(new Query(
+ selectList, // SELECT
+ new ModelResource(model3URI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Arrays.asList(new Order[] { // ORDER BY
+ new Order(subjectVariable, true),
+ new Order(predicateVariable, true),
+ new Order(objectVariable, true)
+ }),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+ } finally {
+ session2.close();
+ }
+ } finally {
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+
+ public void testExplicitCommitIsolationQuery() throws URISyntaxException
+ {
+ logger.info("testExplicitCommitIsolationQuery");
+ URI fileURI = new File("data/xatest-model1.rdf").toURI();
+
+ try {
+ Session session1 = database.newSession();
+ try {
+ Session session2 = database.newSession();
+ try {
+ session1.createModel(model3URI, null);
+ session1.setAutoCommit(false);
+ session1.setModel(model3URI, new ModelResource(fileURI));
+
+ Variable subjectVariable = new Variable("subject");
+ Variable predicateVariable = new Variable("predicate");
+ Variable objectVariable = new Variable("object");
+
+ List selectList = new ArrayList(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ // Evaluate the query
+ Answer answer = session2.query(new Query(
+ selectList, // SELECT
+ new ModelResource(model3URI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Arrays.asList(new Order[] { // ORDER BY
+ new Order(subjectVariable, true),
+ new Order(predicateVariable, true),
+ new Order(objectVariable, true)
+ }),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+
+ session1.commit();
+
+ selectList = new ArrayList(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ // Evaluate the query
+ answer = session2.query(new Query(
+ selectList, // SELECT
+ new ModelResource(model3URI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Arrays.asList(new Order[] { // ORDER BY
+ new Order(subjectVariable, true),
+ new Order(predicateVariable, true),
+ new Order(objectVariable, true)
+ }),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+
+ String[][] results = {
+ { "test:s01", "test:p01", "test:o01" },
+ { "test:s01", "test:p02", "test:o01" },
+ { "test:s01", "test:p02", "test:o02" },
+ { "test:s01", "test:p03", "test:o02" },
+ { "test:s02", "test:p03", "test:o02" },
+ { "test:s02", "test:p04", "test:o02" },
+ { "test:s02", "test:p04", "test:o03" },
+ { "test:s02", "test:p05", "test:o03" },
+ { "test:s03", "test:p01", "test:o01" },
+ { "test:s03", "test:p05", "test:o03" },
+ { "test:s03", "test:p06", "test:o01" },
+ { "test:s03", "test:p06", "test:o03" },
+ };
+ compareResults(results, answer);
+ answer.close();
+
+ session1.removeModel(model3URI);
+ session1.createModel(model3URI, null);
+
+ selectList = new ArrayList(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ // Evaluate the query
+ answer = session2.query(new Query(
+ selectList, // SELECT
+ new ModelResource(model3URI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Arrays.asList(new Order[] { // ORDER BY
+ new Order(subjectVariable, true),
+ new Order(predicateVariable, true),
+ new Order(objectVariable, true)
+ }),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+
+ results = new String[][] {
+ { "test:s01", "test:p01", "test:o01" },
+ { "test:s01", "test:p02", "test:o01" },
+ { "test:s01", "test:p02", "test:o02" },
+ { "test:s01", "test:p03", "test:o02" },
+ { "test:s02", "test:p03", "test:o02" },
+ { "test:s02", "test:p04", "test:o02" },
+ { "test:s02", "test:p04", "test:o03" },
+ { "test:s02", "test:p05", "test:o03" },
+ { "test:s03", "test:p01", "test:o01" },
+ { "test:s03", "test:p05", "test:o03" },
+ { "test:s03", "test:p06", "test:o01" },
+ { "test:s03", "test:p06", "test:o03" },
+ };
+ compareResults(results, answer);
+ answer.close();
+
+ session1.setAutoCommit(true);
+
+ selectList = new ArrayList(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ // Evaluate the query
+ answer = session2.query(new Query(
+ selectList, // SELECT
+ new ModelResource(model3URI), // FROM
+ new ConstraintImpl(subjectVariable, // WHERE
+ predicateVariable,
+ objectVariable),
+ null, // HAVING
+ Arrays.asList(new Order[] { // ORDER BY
+ new Order(subjectVariable, true),
+ new Order(predicateVariable, true),
+ new Order(objectVariable, true)
+ }),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+ } finally {
+ session2.close();
+ }
+ } finally {
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+
+ public void testDatabaseDelete() {
+ database.delete();
+ database = null;
+ }
+
+ //
+ // Internal methods
+ //
+
+ private void compareResults(String[][] expected, Answer answer) throws Exception {
+ answer.beforeFirst();
+ for (int i = 0; i < expected.length; i++) {
+ assertTrue("Answer short at row " + i, answer.next());
+ assertEquals(expected[i].length, answer.getNumberOfVariables());
+ for (int j = 0; j < expected[i].length; j++) {
+ URIReferenceImpl uri = new URIReferenceImpl(
+ new URI(expected[i][j]));
+ assertEquals(uri, answer.getObject(j));
+ }
+ }
+ assertFalse(answer.next());
+ }
+
+ private void compareResults(Answer answer1, Answer answer2) throws Exception {
+ answer1.beforeFirst();
+ answer2.beforeFirst();
+ assertEquals(answer1.getNumberOfVariables(), answer2.getNumberOfVariables());
+ while (answer1.next()) {
+ assertTrue(answer2.next());
+ for (int i = 0; i < answer1.getNumberOfVariables(); i++) {
+ assertEquals(answer1.getObject(i), answer2.getObject(i));
+ }
+ }
+ assertFalse(answer2.next());
+ }
+
+ /**
+ * Fail with an unexpected exception
+ */
+ private void fail(Throwable throwable)
+ {
+ StringWriter stringWriter = new StringWriter();
+ throwable.printStackTrace(new PrintWriter(stringWriter));
+ fail(stringWriter.toString());
+ }
+}
Deleted: trunk/src/jar/resolver/java/org/mulgara/resolver/AnswerDatabaseSession.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/AnswerDatabaseSession.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/AnswerDatabaseSession.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -1,77 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is the Kowari Metadata Store.
- *
- * The Initial Developer of the Original Code is Plugged In Software Pty
- * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
- * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
- * Plugged In Software Pty Ltd. All Rights Reserved.
- *
- * Contributor(s): N/A.
- *
- * [NOTE: The text of this Exhibit A may differ slightly from the text
- * of the notices in the Source Code files of the Original Code. You
- * should use the text of this Exhibit A rather than the text found in the
- * Original Code Source Code for Your Modifications.]
- *
- */
-
-package org.mulgara.resolver;
-
-// Local packages
-import org.mulgara.query.*;
-
-/**
- * Defines the extra requirements of {@link Answer}s upon
- * {@link DatabaseSession}.
- *
- * @created 2004-10-02
- *
- * @author Andrew Newman
- *
- * @version $Revision: 1.8 $
- *
- * @modified $Date: 2005/01/05 04:58:23 $ by $Author: newmana $
- *
- * @maintenanceAuthor $Author: newmana $
- *
- * @copyright ©2004 <a href="http://www.tucanatech.com/">Tucana
- * Technology, Inc</a>
- *
- * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
- */
-public interface AnswerDatabaseSession {
-
- /**
- * Performs a query within an existing transaction.
- *
- * @param query the query to perform.
- * @return a non-<code>null</code> answer to the <var>query</var>
- * @throws QueryException if <var>query</var> can't be answered
- */
- public Answer innerQuery(Query query) throws QueryException;
-
- /**
- * Answers are registered so that the session can ensure that they are closed.
- *
- * @param answer the answer to register with this session.
- */
- public void registerAnswer(SubqueryAnswer answer);
-
- /**
- * Answers are deregistered to indicate that they have closed themselves.
- *
- * @param answer the answer to deregister.
- * @throws QueryException if the transactional block for this answer fails.
- */
- public void deregisterAnswer(SubqueryAnswer answer) throws QueryException;
-}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/AnswerOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/AnswerOperation.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/AnswerOperation.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -21,12 +21,13 @@
public abstract class AnswerOperation {
// Should use enum here.
+ public static final int VOID = 0;
public static final int OBJECT = 1;
public static final int INT = 2;
public static final int LONG = 3;
public static final int BOOLEAN = 3;
- protected int returnType;
+ protected int returnType = VOID;
protected Object object;
protected int integer;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/BasicDatabaseSessionUnitTest.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/BasicDatabaseSessionUnitTest.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/BasicDatabaseSessionUnitTest.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -195,7 +195,7 @@
* of the system model in the newly-created {@link Database}.
*/
public void testQuery1() {
- logger.debug("Testing testQuery1");
+ logger.info("TestQuery1");
try {
// Test querying the system model (#)
Session session = database.newSession();
@@ -225,6 +225,7 @@
new UnconstrainedAnswer() // GIVEN
)));
+
// Compose the expected result of the query
Answer expectedAnswer = new ArrayAnswer(
new Variable[] { subjectVariable, predicateVariable, objectVariable },
@@ -250,7 +251,7 @@
*/
public void testSetModel() throws URISyntaxException
{
- logger.debug("Testing testSetModel");
+ logger.info("testSetModel");
URI fileURI = new File("data/dc.rdfs").toURI();
URI modelURI = new URI("local:database#model");
@@ -278,7 +279,7 @@
*/
public void testQuery2() throws URISyntaxException {
- logger.debug("Testing testQuery2");
+ logger.info("Testing testQuery2");
URI dcFileURI = new File("data/dc.rdfs").toURI();
URI rdfsFileURI = new File("data/rdfs.rdfs").toURI();
Added: trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -0,0 +1,96 @@
+package org.mulgara.resolver;
+
+// Java 2 standard packages
+
+// Java 2 enterprise packages
+
+// Third party packages
+import org.apache.log4j.Logger;
+
+// Local packages
+import org.mulgara.query.rdf.URIReferenceImpl;
+import org.mulgara.resolver.spi.DatabaseMetadata;
+import org.mulgara.resolver.spi.ResolverSessionFactory;
+import org.mulgara.resolver.spi.SingletonStatements;
+import org.mulgara.resolver.spi.SystemResolver;
+
+class BootstrapOperation implements Operation
+{
+ /** Logger */
+ private static final Logger logger =
+ Logger.getLogger(BootstrapOperation.class.getName());
+
+ /**
+ * The URI of the model to be created.
+ */
+ private final DatabaseMetadataImpl databaseMetadata;
+
+ private long result;
+
+ BootstrapOperation(DatabaseMetadataImpl databaseMetadata) {
+ if (databaseMetadata == null) {
+ throw new IllegalArgumentException("BootstrapSystemModel - databaseMetadata null ");
+ }
+
+ this.databaseMetadata = databaseMetadata;
+ this.result = -1; // Return invalid node by default.
+ }
+
+ public void execute(OperationContext operationContext,
+ SystemResolver systemResolver,
+ ResolverSessionFactory resolverSessionFactory,
+ DatabaseMetadata metadata) throws Exception {
+ // Find the local node identifying the model
+ long model = systemResolver.localizePersistent(
+ new URIReferenceImpl(databaseMetadata.getSystemModelURI()));
+ long rdfType = systemResolver.localizePersistent(
+ new URIReferenceImpl(databaseMetadata.getRdfTypeURI()));
+ long modelType = systemResolver.localizePersistent(
+ new URIReferenceImpl(databaseMetadata.getSystemModelTypeURI()));
+
+ // Use the session to create the model
+ systemResolver.modifyModel(model, new SingletonStatements(model, rdfType,
+ modelType), true);
+ databaseMetadata.initializeSystemNodes(model, rdfType, modelType);
+
+ long preSubject = systemResolver.localizePersistent(
+ new URIReferenceImpl(databaseMetadata.getPreallocationSubjectURI()));
+ long prePredicate = systemResolver.localizePersistent(
+ new URIReferenceImpl(databaseMetadata.getPreallocationPredicateURI()));
+ long preModel = systemResolver.localizePersistent(
+ new URIReferenceImpl(databaseMetadata.getPreallocationModelURI()));
+
+ // Every node cached by DatabaseMetadata must be preallocated
+ systemResolver.modifyModel(preModel,
+ new SingletonStatements(preSubject, prePredicate, model),
+ true);
+ systemResolver.modifyModel(preModel,
+ new SingletonStatements(preSubject, prePredicate, rdfType),
+ true);
+ systemResolver.modifyModel(preModel,
+ new SingletonStatements(preSubject, prePredicate, modelType),
+ true);
+ systemResolver.modifyModel(preModel,
+ new SingletonStatements(preSubject, prePredicate, preSubject),
+ true);
+ systemResolver.modifyModel(preModel,
+ new SingletonStatements(preSubject, prePredicate, prePredicate),
+ true);
+ systemResolver.modifyModel(preModel,
+ new SingletonStatements(preSubject, prePredicate, preModel),
+ true);
+
+ databaseMetadata.initializePreallocationNodes(preSubject, prePredicate, preModel);
+
+ result = model;
+ }
+
+ public boolean isWriteOperation()
+ {
+ return true;
+ }
+
+ public long getResult() {
+ return result;
+ }
+}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/CacheResolver.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/CacheResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/CacheResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -225,4 +225,6 @@
return temporaryResolver;
}
+
+ public void abort() {}
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/ConstraintOperations.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/ConstraintOperations.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/ConstraintOperations.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -41,7 +41,6 @@
// Local packages
import org.mulgara.query.*;
-import org.mulgara.query.rdf.BlankNodeImpl;
import org.mulgara.query.rdf.LiteralImpl;
import org.mulgara.query.rdf.URIReferenceImpl;
import org.mulgara.resolver.spi.ConstraintBindingHandler;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/CreateModelOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/CreateModelOperation.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/CreateModelOperation.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -212,8 +212,7 @@
// PREVIOUSLY WITHIN TRANSACTION
// Obtain an appropriate resolver bound to this session
- Resolver resolver =
- operationContext.obtainResolver(resolverFactory, systemResolver);
+ Resolver resolver = operationContext.obtainResolver(resolverFactory);
assert resolver != null;
// Find the local node identifying the model
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -253,10 +253,12 @@
private final TransactionManagerFactory transactionManagerFactory;
/**
- * JTS transaction manager used to distribute transactions over multiple
- * resolvers.
+ * The internal transaction manager.
+ *
+ * This class is a singleton with respect to a database instance.
+ * Passed to new DatabaseSession's.
*/
- private final TransactionManager transactionManager;
+ private final MulgaraTransactionManager transactionManager;
/** The unique {@link URI} naming this database. */
private final URI uri;
@@ -510,17 +512,9 @@
assert this.contentHandlers != null;
// FIXME: Migrate this code inside StringPoolSession. Pass config to StringPoolSession.
- this.transactionManager = transactionManagerFactory.newTransactionManager();
+ this.transactionManager = new MulgaraTransactionManager(transactionManagerFactory);
- // Set the transaction timeout to an hour
- try {
- transactionManager.setTransactionTimeout(transactionTimeout);
- }
- catch (SystemException e) {
- logger.warn(
- "Unable to set transaction timeout to " + transactionTimeout + "s", e
- );
- }
+ transactionManager.setTransactionTimeout(transactionTimeout);
// Enable resolver initialization
if (logger.isDebugEnabled()) {
@@ -676,6 +670,7 @@
logger.debug("Added system resolver " + systemResolverFactoryClassName);
}
+
URI systemModelURI = new URI(uri.getScheme(), uri.getSchemeSpecificPart(), "");
metadata =
new DatabaseMetadataImpl(uri,
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -34,6 +34,7 @@
import java.net.URISyntaxException;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -67,6 +68,8 @@
import org.mulgara.resolver.spi.SymbolicTransformation;
import org.mulgara.resolver.spi.SymbolicTransformationContext;
import org.mulgara.resolver.spi.SystemResolver;
+import org.mulgara.resolver.spi.SystemResolverFactory;
+import org.mulgara.resolver.spi.TuplesWrapperStatements;
import org.mulgara.resolver.view.ViewMarker;
import org.mulgara.resolver.view.SessionView;
import org.mulgara.store.nodepool.NodePool;
@@ -86,8 +89,7 @@
* Technology, Inc</a>
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
-class DatabaseOperationContext implements OperationContext, SessionView,
-AnswerDatabaseSession, SymbolicTransformationContext
+class DatabaseOperationContext implements OperationContext, SessionView, SymbolicTransformationContext
{
/**
* Logger.
@@ -124,13 +126,19 @@
* localized type of the model.
*
* This is populated by {@link #findModelTypeURI} and cleared by
- * {@link #clearSystemModelCache}.
+ * clear()
*/
private final Map systemModelCacheMap = new WeakHashMap();
+ /** Resolver used for accessing the system model (<code>#</code>). */
+ protected SystemResolverFactory systemResolverFactory;
+ protected SystemResolver systemResolver;
+
+ /** The transaction associated with these operations */
+ private MulgaraTransaction transaction;
+
// Immutable properties of the containing DatabaseSession
private final Set cachedResolverFactorySet;
- private final DatabaseSession databaseSession;
private final Map enlistedResolverMap;
private final Map externalResolverFactoryMap;
private final Map internalResolverFactoryMap;
@@ -138,63 +146,48 @@
private final List securityAdapterList;
private final URI temporaryModelTypeURI;
private final ResolverFactory temporaryResolverFactory;
- private final TransactionManager transactionManager;
- private final Set outstandingAnswers;
/** Symbolic transformations this instance should apply. */
- private final List symbolicTransformationList;
+ private final List symbolicTransformationList;
+ private final boolean isWriting;
- //
- // Constructor
- //
+ private WeakHashMap answers; // Used as a set, all values are null. Java doesn't provide a WeakHashSet.
- /**
- * Sole constructor.
- */
- DatabaseOperationContext(Set cachedModelSet,
- Set cachedResolverFactorySet,
- Set changedCachedModelSet,
- DatabaseSession databaseSession,
- Map enlistedResolverMap,
- Map externalResolverFactoryMap,
- Map internalResolverFactoryMap,
- DatabaseMetadata metadata,
- List securityAdapterList,
- URI temporaryModelTypeURI,
- ResolverFactory temporaryResolverFactory,
- TransactionManager transactionManager,
- Set outstandingAnswers,
- List symbolicTransformationList)
+ DatabaseOperationContext(Set cachedResolverFactorySet,
+ Map externalResolverFactoryMap,
+ Map internalResolverFactoryMap,
+ DatabaseMetadata metadata,
+ List securityAdapterList,
+ URI temporaryModelTypeURI,
+ ResolverFactory temporaryResolverFactory,
+ List symbolicTransformationList,
+ SystemResolverFactory systemResolverFactory,
+ boolean isWriting)
{
- assert cachedModelSet != null;
assert cachedResolverFactorySet != null;
- assert changedCachedModelSet != null;
- assert databaseSession != null;
- assert enlistedResolverMap != null;
assert externalResolverFactoryMap != null;
assert internalResolverFactoryMap != null;
assert metadata != null;
assert securityAdapterList != null;
assert temporaryModelTypeURI != null;
assert temporaryResolverFactory != null;
- assert transactionManager != null;
+ assert symbolicTransformationList != null;
+ assert systemResolverFactory != null;
- // Initialize fields
- this.cachedModelSet = cachedModelSet;
this.cachedResolverFactorySet = cachedResolverFactorySet;
- this.changedCachedModelSet = changedCachedModelSet;
- this.databaseSession = databaseSession;
- this.enlistedResolverMap = enlistedResolverMap;
this.externalResolverFactoryMap = externalResolverFactoryMap;
this.internalResolverFactoryMap = internalResolverFactoryMap;
this.metadata = metadata;
this.securityAdapterList = securityAdapterList;
this.temporaryModelTypeURI = temporaryModelTypeURI;
this.temporaryResolverFactory = temporaryResolverFactory;
- this.transactionManager = transactionManager;
- // Note this is only temporary - we will be eliminating outstandingAnswers
- // before the end of the transaction fix.
- this.outstandingAnswers = outstandingAnswers;
this.symbolicTransformationList = symbolicTransformationList;
+ this.isWriting = isWriting;
+ this.systemResolverFactory = systemResolverFactory;
+
+ this.cachedModelSet = new HashSet();
+ this.changedCachedModelSet = new HashSet();
+ this.enlistedResolverMap = new HashMap();
+ this.answers = new WeakHashMap();
}
//
@@ -223,11 +216,10 @@
throw new QueryException("Unsupported model type for model " + model); }
return internalResolverFactory;
- }
- else {
+ } else {
// This might be an external model or an aliased internal model.
// get the model URI
- Node modelNode = databaseSession.getSystemResolver().globalize(model);
+ Node modelNode = systemResolver.globalize(model);
if (!(modelNode instanceof URIReference)) {
throw new QueryException(modelNode.toString() + " is not a valid Model");
}
@@ -236,7 +228,7 @@
// check if this is really a reference to a local model, using a different server name
Node aliasedNode = getCanonicalAlias(modelURI);
if (aliasedNode != null) {
- long aliasedModel = databaseSession.getSystemResolver().localize(aliasedNode);
+ long aliasedModel = systemResolver.localize(aliasedNode);
return findModelResolverFactory(aliasedModel);
}
@@ -271,8 +263,7 @@
throw new QueryException(modelNode.toString() + " is not a Model");
}
}
- }
- catch (URISyntaxException use) {
+ } catch (URISyntaxException use) {
throw new QueryException("Internal error. Model URI cannot be manipulated.");
}
@@ -300,20 +291,73 @@
temporaryModelTypeURI,
cachedModelSet,
changedCachedModelSet);
- }
- else {
+ } else {
return resolverFactory;
}
}
- }
- catch (GlobalizeException eg) {
+ } catch (GlobalizeException eg) {
throw new QueryException("Unable to globalize modeltype", eg);
- }
- catch (LocalizeException el) {
+ } catch (LocalizeException el) {
throw new QueryException("Unable to localize model", el);
}
}
+ /**
+ * Find a cached resolver factory for write back.
+ *
+ * @return a completely unwrapped resolver factory
+ */
+ // TODO: Common code with findModelResolverFactory should be consolidated.
+ private ResolverFactory findResolverFactory(long model) throws QueryException
+ {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Finding raw resolver factory for model " + model);
+ }
+
+ try {
+ // get the model URI
+ Node modelNode = systemResolver.globalize(model);
+ if (!(modelNode instanceof URIReference)) {
+ throw new QueryException(modelNode.toString() + " is not a valid Model");
+ }
+ URI modelURI = ((URIReference)modelNode).getURI();
+
+ // test the model URI against the current server
+ try {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Comparing " + metadata.getURI().toString() + " to "
+ + (new URI(modelURI.getScheme(), modelURI.getSchemeSpecificPart(), null)).toString());
+ }
+ if (metadata.getURI().equals(
+ new URI(modelURI.getScheme(), modelURI.getSchemeSpecificPart(), null))) {
+ // should be on the current server, but was not found here
+ throw new QueryException(modelNode.toString() + " is not a Model");
+ }
+ } catch (URISyntaxException use) {
+ throw new QueryException("Internal error. Model URI cannot be manipulated.");
+ }
+
+ // This is not a local model, get the protocol
+ String modelProtocol = findProtocol(model);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Model " + model + " protocol is " + modelProtocol);
+ }
+
+ // find the factory for this protocol
+ ResolverFactory resolverFactory =
+ (ResolverFactory) externalResolverFactoryMap.get(modelProtocol);
+ if (resolverFactory == null) {
+ throw new QueryException(
+ "Unsupported protocol for destination model (" +
+ modelProtocol + ", " + model + " : '" + modelProtocol + "')");
+ }
+
+ return resolverFactory;
+ } catch (GlobalizeException eg) {
+ throw new QueryException("Unable to globalize modeltype", eg);
+ }
+ }
+
public ResolverFactory findModelTypeResolverFactory(URI modelTypeURI)
throws QueryException
{
@@ -325,8 +369,7 @@
return securityAdapterList;
}
- public Resolver obtainResolver(ResolverFactory resolverFactory,
- SystemResolver systemResolver)
+ public Resolver obtainResolver(ResolverFactory resolverFactory)
throws QueryException
{
ResolverSession session;
@@ -338,9 +381,7 @@
}
try {
- resolver = resolverFactory.newResolver(databaseSession.isWriting(),
- systemResolver,
- systemResolver);
+ resolver = resolverFactory.newResolver(isWriting, systemResolver, systemResolver);
// FIXME: This is a kludge. This should be done using a query rewriting
// hook in the ResolverFactory interface. This hook is also
@@ -350,15 +391,23 @@
if (resolver instanceof ViewMarker) {
((ViewMarker) resolver).setSession(this);
}
- }
- catch (ResolverFactoryException e) {
+ } catch (ResolverFactoryException e) {
throw new QueryException("Unable to obtain resolver", e);
}
+
assert resolver != null;
+ try {
+ transaction.enlist(resolver);
+ } catch (Exception e) {
+ logger.warn("Failed to enlist resolver, aborting resolver");
+ resolver.abort();
+ throw new QueryException("Unable to enlist " + resolver + " into transaction", e);
+ }
+
enlistedResolverMap.put(resolverFactory, resolver);
- return enlistResolver(resolver);
+ return resolver;
}
@@ -371,7 +420,7 @@
public long getCanonicalModel(long model) {
// globalize to a URI
try {
- Node modelNode = databaseSession.getSystemResolver().globalize(model);
+ Node modelNode = systemResolver.globalize(model);
if (!(modelNode instanceof URIReference)) {
logger.warn(modelNode.toString() + " is not a valid Model");
return model;
@@ -381,7 +430,7 @@
// check if this is really a reference to a local model, using a different server name
Node aliasedNode = getCanonicalAlias(modelURI);
if (aliasedNode != null) {
- return databaseSession.getSystemResolver().localize(aliasedNode);
+ return systemResolver.localize(aliasedNode);
}
} catch (Exception e) {
// unable to get a canonical form, so leave this model alone
@@ -399,7 +448,7 @@
if (logger.isDebugEnabled()) {
logger.debug("Finding modelTypeURI for " + modelURI);
}
- long rawModel = databaseSession.getSystemResolver().localize(new URIReferenceImpl(modelURI));
+ long rawModel = systemResolver.localize(new URIReferenceImpl(modelURI));
long canModel = getCanonicalModel(rawModel);
URI modelTypeURI = findModelTypeURI(canModel);
@@ -417,66 +466,10 @@
}
//
- // Methods used only by DatabaseSession
- //
-
- /**
- * Remove all the cached entries resulting from calls to
- * {@link #findModelTypeURI}.
- *
- * This needs to be called at the end of transactions by
- * {@link DatabaseSession} because the system model may change thereafter.
- */
- void clearSystemModelCache()
- {
- systemModelCacheMap.clear();
- }
-
- //
// Internal methods
//
/**
- * @param resolver a resolver to enlist into the current transaction
- * @throws QueryException if the <var>resolver</var> can't be enlisted
- */
- Resolver enlistResolver(Resolver resolver) throws QueryException
- {
- // Obtain the transaction over the current thread
- Transaction transaction;
- try {
- transaction = transactionManager.getTransaction();
- }
- catch (Exception e) {
- throw new QueryException("Unable to obtain transaction", e);
- }
- if (transaction == null) {
- if (databaseSession.getTransaction() != null) {
- logger.error("Transaction suspended and not resumed when enlisting resolver");
- }
- else {
- logger.error("Not in Transaction when enlisting resolver");
- }
- throw new QueryException("Failed to find transaction when enlisting resolver");
- }
-
- // Enlist the resolver into the transaction
- XAResource xaResource = resolver.getXAResource();
- if (logger.isDebugEnabled()) {
- logger.debug("Enlisting " + resolver);
- }
-
- try {
- transaction.enlistResource(xaResource);
- }
- catch (Exception e) {
- throw new QueryException("Unable to enlist " + resolver + " into transaction", e);
- }
-
- return resolver;
- }
-
- /**
* Find the type of a model.
*
* @param model the local node of a model
@@ -507,7 +500,7 @@
new LocalNode(metadata.getRdfTypeNode()),
modelTypeVariable,
new LocalNode(metadata.getSystemModelNode()));
- Resolution resolution = databaseSession.getSystemResolver().resolve(modelConstraint);
+ Resolution resolution = systemResolver.resolve(modelConstraint);
assert resolution != null;
// Check the solution and extract the model type (if any) from it
@@ -521,25 +514,22 @@
throw new QueryException("Model " + model +
" has more than one type!");
}
- Node modelNode = databaseSession.getSystemResolver().globalize(modelType);
+ Node modelNode = systemResolver.globalize(modelType);
assert modelNode instanceof URIReferenceImpl;
modelTypeURI = ((URIReferenceImpl) modelNode).getURI();
systemModelCacheMap.put(modelLocalNode, modelTypeURI);
+
return modelTypeURI;
- }
- else {
+ } else {
return null;
}
- }
- catch (TuplesException e) {
+ } catch (TuplesException e) {
throw new QueryException("Unable to determine model type of " + model, e);
- }
- finally {
+ } finally {
if ( resolution != null ) {
try {
resolution.close();
- }
- catch (TuplesException e) {
+ } catch (TuplesException e) {
logger.warn("Unable to close find model type resolution to model " + model, e);
}
}
@@ -552,11 +542,11 @@
* @throws QueryException if the <var>node</var> can't be globalized or
* isn't a URI reference
*/
- /*private*/ String findProtocol(long n) throws QueryException
+ private String findProtocol(long n) throws QueryException
{
try {
// Globalize the node
- Node node = (Node) databaseSession.getSystemResolver().globalize(n);
+ Node node = (Node) systemResolver.globalize(n);
if (!(node instanceof URIReference)) {
throw new QueryException(node + " is not a URI reference");
}
@@ -565,8 +555,7 @@
}
// Return the protocol
return ((URIReference) node).getURI().getScheme();
- }
- catch (GlobalizeException e) {
+ } catch (GlobalizeException e) {
throw new QueryException("Unable to globalize node " + n, e);
}
}
@@ -602,11 +591,9 @@
return null;
}
// check the various names against known aliases
- if (
- metadata.getHostnameAliases().contains(addr.getHostName()) ||
+ if (metadata.getHostnameAliases().contains(addr.getHostName()) ||
metadata.getHostnameAliases().contains(addr.getCanonicalHostName()) ||
- metadata.getHostnameAliases().contains(addr.getHostAddress())
- ) {
+ metadata.getHostnameAliases().contains(addr.getHostAddress())) {
// change the host name to one that is recognised
return getLocalURI(modelURI);
}
@@ -630,6 +617,7 @@
try {
URI newModelURI = new URI(uri.getScheme(), newHost, uri.getPath(), uri.getFragment());
logger.debug("Changing model URI from " + uri + " to " + newModelURI);
+
return new URIReferenceImpl(newModelURI);
} catch (URISyntaxException e) {
throw new QueryException("Internal error. Model URI cannot be manipulated.");
@@ -661,8 +649,6 @@
throw new IllegalArgumentException("Null \"constraint\" parameter");
}
- SystemResolver systemResolver = databaseSession.getSystemResolver();
-
ConstraintElement modelElem = constraint.getModel();
if (modelElem instanceof Variable) {
return resolveVariableModel(constraint);
@@ -701,8 +687,7 @@
}
// Evaluate the constraint
- Tuples result = obtainResolver(
- findModelResolverFactory(realModel), systemResolver).resolve(constraint);
+ Tuples result = obtainResolver(findModelResolverFactory(realModel)).resolve(constraint);
assert result != null;
return result;
@@ -731,8 +716,6 @@
assert constraint != null;
assert constraint.getElement(3) instanceof Variable;
- SystemResolver systemResolver = databaseSession.getSystemResolver();
-
Tuples tuples = TuplesOperations.empty();
// This is the alternate code we'd use if we were to consult external
@@ -747,7 +730,7 @@
assert resolverFactory != null;
// Resolve the constraint
- Resolver resolver = obtainResolver(resolverFactory, systemResolver);
+ Resolver resolver = obtainResolver(resolverFactory);
if (logger.isDebugEnabled()) {
logger.debug("Resolving " + constraint + " against " + resolver);
}
@@ -786,74 +769,7 @@
return tuples;
}
- public Answer innerQuery(Query query) throws QueryException {
- // Validate "query" parameter
- if (query == null) {
- throw new IllegalArgumentException("Null \"query\" parameter");
- }
-
- if (logger.isInfoEnabled()) {
- logger.info("Query: " + query);
- }
-
- boolean resumed = databaseSession.ensureTransactionResumed();
- SystemResolver systemResolver = databaseSession.getSystemResolver();
-
- Answer result = null;
- try {
- result = doQuery(systemResolver, query);
- } catch (Throwable th) {
- try {
- logger.warn("Inner Query failed", th);
- databaseSession.rollbackTransactionalBlock(th);
- } finally {
- databaseSession.endPreviousQueryTransaction();
- logger.error("Inner Query should have thrown exception", th);
- throw new IllegalStateException(
- "Inner Query should have thrown exception");
- }
- }
-
- try {
- if (resumed) {
- databaseSession.suspendTransactionalBlock();
- }
-
- return result;
- } catch (Throwable th) {
- databaseSession.endPreviousQueryTransaction();
- logger.error("Failed to suspend Transaction", th);
- throw new QueryException("Failed to suspend Transaction");
- }
- }
-
- public void registerAnswer(SubqueryAnswer answer) {
- if (logger.isDebugEnabled()) {
- logger.debug("registering Answer: " + System.identityHashCode(answer));
- }
- outstandingAnswers.add(answer);
- }
-
- public void deregisterAnswer(SubqueryAnswer answer) throws QueryException {
- if (logger.isDebugEnabled()) {
- logger.debug("deregistering Answer: " + System.identityHashCode(answer));
- }
-
- if (!outstandingAnswers.contains(answer)) {
- logger.info("Stale answer being closed");
- } else {
- outstandingAnswers.remove(answer);
- if (databaseSession.autoCommit && outstandingAnswers.isEmpty()) {
- if (databaseSession.getTransaction() != null) {
- databaseSession.resumeTransactionalBlock();
- }
- databaseSession.endTransactionalBlock("Could not commit query");
- }
- }
- }
-
Tuples innerCount(LocalQuery localQuery) throws QueryException {
- // Validate "query" parameter
if (localQuery == null) {
throw new IllegalArgumentException("Null \"query\" parameter");
}
@@ -861,43 +777,21 @@
if (logger.isInfoEnabled()) {
logger.info("Inner Count: " + localQuery);
}
-
- boolean resumed = databaseSession.ensureTransactionResumed();
- SystemResolver systemResolver = databaseSession.getSystemResolver();
-
- Tuples result = null;
try {
LocalQuery lq = (LocalQuery)localQuery.clone();
transform(lq);
- result = lq.resolve();
+ Tuples result = lq.resolve();
lq.close();
- } catch (Throwable th) {
- try {
- logger.warn("Inner Query failed", th);
- databaseSession.rollbackTransactionalBlock(th);
- } finally {
- databaseSession.endPreviousQueryTransaction();
- logger.error("Inner Query should have thrown exception", th);
- throw new IllegalStateException(
- "Inner Query should have thrown exception");
- }
- }
- try {
- if (resumed) {
- databaseSession.suspendTransactionalBlock();
- }
-
return result;
- } catch (Throwable th) {
- databaseSession.endPreviousQueryTransaction();
- logger.error("Failed to suspend Transaction", th);
- throw new QueryException("Failed to suspend Transaction");
+ } catch (QueryException eq) {
+ throw eq;
+ } catch (Exception e) {
+ throw new QueryException("Failed to evaluate count", e);
}
}
- protected void doModify(SystemResolver systemResolver, URI modelURI,
- Statements statements, boolean insert) throws Throwable {
+ protected void doModify(URI modelURI, Statements statements, boolean insert) throws Throwable {
long model = systemResolver.localize(new URIReferenceImpl(modelURI));
model = getCanonicalModel(model);
@@ -917,7 +811,7 @@
}
// Obtain a resolver for the destination model type
- Resolver resolver = obtainResolver(findModelResolverFactory(model), systemResolver);
+ Resolver resolver = obtainResolver(findModelResolverFactory(model));
assert resolver != null;
if (logger.isDebugEnabled()) {
@@ -931,7 +825,7 @@
}
}
- public Answer doQuery(SystemResolver systemResolver, Query query) throws Exception
+ public Answer doQuery(Query query) throws Exception
{
Answer result;
@@ -941,13 +835,11 @@
// Complete the numerical phase of resolution
Tuples tuples = localQuery.resolve();
- result = new SubqueryAnswer(this, systemResolver, tuples, query.getVariableList());
+ result = new TransactionalAnswer(transaction, new SubqueryAnswer(this, systemResolver, tuples, query.getVariableList()));
+ answers.put(result, null);
tuples.close();
localQuery.close();
- if (logger.isDebugEnabled()) {
- logger.debug("Answer rows = " + result.getRowCount());
- }
return result;
}
@@ -984,4 +876,95 @@
mutableLocalQueryImpl.close();
}
+ void clear() throws QueryException {
+ try {
+ Iterator i = answers.keySet().iterator();
+ while (i.hasNext()) {
+ ((TransactionalAnswer)i.next()).sessionClose();
+ }
+ answers.clear();
+ } catch (TuplesException et) {
+ throw new QueryException("Error force-closing answers", et);
+ }
+
+ clearCache();
+ systemResolver = null;
+ systemModelCacheMap.clear();
+ enlistedResolverMap.clear();
+ }
+
+ public SystemResolver getSystemResolver() {
+ return systemResolver;
+ }
+
+
+ /**
+ * Clear the cache of temporary models.
+ */
+ private void clearCache() {
+ // Clear the temporary models
+ if (!cachedModelSet.isEmpty()) {
+ try {
+ Resolver temporaryResolver =
+ temporaryResolverFactory.newResolver(true, systemResolver, systemResolver);
+ for (Iterator i = cachedModelSet.iterator(); i.hasNext();) {
+ LocalNode modelLocalNode = (LocalNode) i.next();
+ long model = modelLocalNode.getValue();
+
+ if (changedCachedModelSet.contains(modelLocalNode)) {
+ // Write back the modifications to the original model
+ try {
+ Resolver resolver =
+ findResolverFactory(model).newResolver(true, systemResolver, systemResolver);
+ Variable s = new Variable("s");
+ Variable p = new Variable("p");
+ Variable o = new Variable("o");
+ resolver.modifyModel(model,
+ new TuplesWrapperStatements(temporaryResolver.resolve(
+ new ConstraintImpl(s, p, o, modelLocalNode)), s, p, o),
+ true // insert the content
+ );
+ } catch (Exception e) {
+ logger.error("Failed to write back cached model " + model +
+ " after transaction", e);
+ }
+ changedCachedModelSet.remove(modelLocalNode);
+ }
+
+ // Remove the cached model
+ try {
+ temporaryResolver.removeModel(model);
+ } catch (Exception e) {
+ logger.error("Failed to clear cached model " + model + " after transaction", e);
+ }
+ i.remove();
+ }
+ } catch (Exception e) {
+ logger.error("Failed to clear cached models after transaction", e);
+ }
+ }
+ }
+
+ public void abort() {
+ Iterator i = enlistedResolverMap.values().iterator();
+ while (i.hasNext()) {
+ ((Resolver)i.next()).abort();
+ }
+ try {
+ this.clear();
+ } catch (QueryException eq) {
+ throw new IllegalStateException("Error aborting OperationContext", eq);
+ }
+ }
+
+ public void initiate(MulgaraTransaction transaction) throws QueryException {
+ try {
+ this.transaction = transaction;
+ this.systemResolver = systemResolverFactory.newResolver(isWriting);
+ transaction.enlist(systemResolver);
+ } catch (Exception e) {
+ throw new QueryException("Unable to enlist systemResolver:" +
+ systemResolver + " into transaction", e);
+ }
+ }
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -39,9 +39,6 @@
// Java 2 enterprise packages
import javax.transaction.RollbackException;
import javax.transaction.Status;
-import javax.transaction.SystemException;
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
// Third party packages
import org.apache.log4j.Logger;
@@ -78,7 +75,7 @@
*
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
-class DatabaseSession implements Session, LocalSession {
+class DatabaseSession implements Session {
public static final boolean ASSERT_STATEMENTS = true;
public static final boolean DENY_STATEMENTS = false;
@@ -86,37 +83,14 @@
private static final Logger logger =
Logger.getLogger(DatabaseSession.class.getName());
- private static DatabaseSession writeSession = null;
- private boolean writing;
-
/**
- * The models from external resolvers which have been cached as temporary
- * models.
- *
- * Every model in this set can be manipulated by resolvers from the
- * {@link #temporaryResolverFactory}.
- */
- private final Set cachedModelSet = new HashSet();
-
- /**
* Resolver factories that should be have access to their models cached.
*
* This field is read-only.
*/
private final Set cachedResolverFactorySet;
- /**
- * The models from external resolvers which have been cached as temporary
- * models and modified.
- *
- * Every model in this set can be manipulated by resolvers from the
- * {@link #temporaryResolverFactory}.
- */
- private final Set changedCachedModelSet = new HashSet();
-
- /**
- * The list of all registered {@link ResolverFactory} instances.
- */
+ /** The list of all registered {@link ResolverFactory} instances. */
private final List resolverFactoryList;
/**
@@ -133,8 +107,6 @@
private final DatabaseMetadata metadata;
- private final DatabaseOperationContext operationContext;
-
/** Security adapters this instance should enforce. */
private final List securityAdapterList;
@@ -147,66 +119,23 @@
/** Factory used to obtain the SystemResolver */
private final SystemResolverFactory systemResolverFactory;
- /** Resolver used for accessing the system model (<code>#</code>). */
- protected SystemResolver systemResolver;
-
/** Factory used to obtain the SystemResolver */
private final ResolverFactory temporaryResolverFactory;
/** Source of transactions. */
- private final TransactionManager transactionManager;
+ private final MulgaraTransactionManager transactionManager;
- /** Session transaction */
- private Transaction transaction;
-
/** The name of the rule loader to use */
private String ruleLoaderClassName;
/** A fallback rule loader */
private static final String DUMMY_RULE_LOADER = "org.mulgara.rules.DummyRuleLoader";
- private int opState;
- private static final int UNINIT = 0;
- private static final int BEGIN = 1;
- private static final int RESUME = 2;
- private static final int FINISH = 3;
- private static final String[] opStates = {
- "UNINIT", "BEGIN", "RESUME", "FINISH", };
-
- private final Map enlistedResolverMap;
-
- private Set outstandingAnswers;
-
- /**
- * Whether each method call of the {@link Session} interface should
- * implicitly have a transaction created for it and be performed within that
- * transaction.
- *
- * This defaults to <code>true</code> until modified by the
- * {@link #setAutoCommit} method.
- */
- boolean autoCommit = true;
- private boolean inFailedTransaction = false;
-
- /**
- * If a transaction is marked for rollback by the
- * {@link #rollbackTransactionalBlock} method, this field holds the exception
- * that caused the rollback so that the {@link #endTransactionalBlock} method
- * can add it as the cause of the {@link RollbackException} it will
- * subsequently throw.
- */
- private Throwable rollbackCause = null;
-
- private boolean explicitRollback = false;
-
- /**
- * The registered {@link ContentHandler} instances.
- */
+ /** The registered {@link ContentHandler} instances. */
private ContentHandlerManager contentHandlers;
- //
- // Constructor
- //
+ /** The temporary model type-URI. */
+ private final URI temporaryModelTypeURI;
/**
* Construct a database session.
@@ -241,7 +170,7 @@
* external models
* @throws IllegalArgumentException if any argument is <code>null</code>
*/
- DatabaseSession(TransactionManager transactionManager,
+ DatabaseSession(MulgaraTransactionManager transactionManager,
List securityAdapterList,
List symbolicTransformationList,
ResolverSessionFactory resolverSessionFactory,
@@ -264,43 +193,35 @@
// Validate parameters
if (transactionManager == null) {
- throw new IllegalArgumentException("Null \"transactionManager\" parameter");
+ throw new IllegalArgumentException("Null 'transactionManager' parameter");
} else if (securityAdapterList == null) {
- throw new IllegalArgumentException("Null \"securityAdapterList\" parameter");
+ throw new IllegalArgumentException("Null 'securityAdapterList' parameter");
} else if (symbolicTransformationList == null) {
- throw new IllegalArgumentException("Null \"symbolicTransformationList\" parameter");
+ throw new IllegalArgumentException("Null 'symbolicTransformationList' parameter");
} else if (resolverSessionFactory == null) {
- throw new IllegalArgumentException("Null \"resolverSessionFactory\" parameter");
+ throw new IllegalArgumentException("Null 'resolverSessionFactory' parameter");
} else if (systemResolverFactory == null) {
- throw new IllegalArgumentException("Null \"systemResolverFactory\" parameter");
+ throw new IllegalArgumentException("Null 'systemResolverFactory' parameter");
} else if (temporaryResolverFactory == null) {
- throw new IllegalArgumentException("Null \"temporaryResolverFactory\" parameter");
+ throw new IllegalArgumentException("Null 'temporaryResolverFactory' parameter");
} else if (resolverFactoryList == null) {
- throw new IllegalArgumentException("Null \"resolverFactoryList\" parameter");
+ throw new IllegalArgumentException("Null 'resolverFactoryList' parameter");
} else if (externalResolverFactoryMap == null) {
- throw new IllegalArgumentException("Null \"externalResolverFactoryMap\" parameter");
+ throw new IllegalArgumentException("Null 'externalResolverFactoryMap' parameter");
} else if (internalResolverFactoryMap == null) {
- throw new IllegalArgumentException("Null \"internalResolverFactoryMap\" parameter");
+ throw new IllegalArgumentException("Null 'internalResolverFactoryMap' parameter");
} else if (contentHandlers == null) {
- throw new IllegalArgumentException("Null \"contentHandlers\" parameter");
+ throw new IllegalArgumentException("Null 'contentHandlers' parameter");
} else if (metadata == null) {
- throw new IllegalArgumentException("Null \"metadata\" parameter");
+ throw new IllegalArgumentException("Null 'metadata' parameter");
+ } else if (cachedResolverFactorySet == null) {
+ throw new IllegalArgumentException("Null 'cachedResolverFactorySet' parameter");
+ } else if (temporaryModelTypeURI == null) {
+ throw new IllegalArgumentException("Null 'temporaryModelTypeURI' parameter");
} else if (ruleLoaderClassName == null) {
ruleLoaderClassName = DUMMY_RULE_LOADER;
}
- if (cachedResolverFactorySet == null) {
- throw new IllegalArgumentException(
- "Null \"cachedResolverFactorySet\" parameter"
- );
- }
-
- if (temporaryModelTypeURI == null) {
- throw new IllegalArgumentException(
- "Null \"temporaryModelTypeURI\" parameter"
- );
- }
-
// Initialize fields
this.transactionManager = transactionManager;
this.securityAdapterList = securityAdapterList;
@@ -314,46 +235,22 @@
this.metadata = metadata;
this.contentHandlers = contentHandlers;
this.cachedResolverFactorySet = cachedResolverFactorySet;
+ this.temporaryModelTypeURI = temporaryModelTypeURI;
this.ruleLoaderClassName = ruleLoaderClassName;
- this.outstandingAnswers = new HashSet();
- this.transaction = null;
- this.enlistedResolverMap = new HashMap();
- this.opState = FINISH;
- this.operationContext = new DatabaseOperationContext(
- cachedModelSet,
- cachedResolverFactorySet,
- changedCachedModelSet,
- this,
- enlistedResolverMap,
- externalResolverFactoryMap,
- internalResolverFactoryMap,
- metadata,
- securityAdapterList,
- temporaryModelTypeURI,
- temporaryResolverFactory,
- transactionManager,
- outstandingAnswers,
- symbolicTransformationList
- );
-
if (logger.isDebugEnabled()) {
logger.debug("Constructed DatabaseSession");
}
// Set the transaction timeout to an hour
- try {
- transactionManager.setTransactionTimeout(3600);
- } catch (SystemException e) {
- logger.warn("Unable to set transaction timeout to 3600s", e);
- }
+ transactionManager.setTransactionTimeout(3600);
}
/**
* Non-rule version of the constructor. Accepts all parameters except ruleLoaderClassName.
*/
- DatabaseSession(TransactionManager transactionManager,
+ DatabaseSession(MulgaraTransactionManager transactionManager,
List securityAdapterList,
List symbolicTransformationList,
ResolverSessionFactory resolverSessionFactory,
@@ -379,68 +276,15 @@
/**
* Used by Database *only* to bootstrap the system model on DB startup.
*/
- long bootstrapSystemModel(DatabaseMetadataImpl metadata) throws
- QueryException {
+ long bootstrapSystemModel(DatabaseMetadataImpl metadata) throws QueryException {
logger.info("Bootstrapping System Model");
- // Validate parameters
- if (metadata == null) {
- throw new IllegalArgumentException("metadata null");
- }
- // Create the model
- systemResolver = beginTransactionalBlock(true);
- try {
- // Find the local node identifying the model
- long model = systemResolver.localizePersistent(
- new URIReferenceImpl(metadata.getSystemModelURI()));
- long rdfType = systemResolver.localizePersistent(
- new URIReferenceImpl(metadata.getRdfTypeURI()));
- long modelType = systemResolver.localizePersistent(
- new URIReferenceImpl(metadata.getSystemModelTypeURI()));
+ BootstrapOperation operation = new BootstrapOperation(metadata);
+ execute(operation, "Failed to bootstrap system-model");
- // Use the session to create the model
- systemResolver.modifyModel(model, new SingletonStatements(model, rdfType,
- modelType), true);
- metadata.initializeSystemNodes(model, rdfType, modelType);
+ systemResolverFactory.setDatabaseMetadata(metadata);
- long preSubject = systemResolver.localizePersistent(
- new URIReferenceImpl(metadata.getPreallocationSubjectURI()));
- long prePredicate = systemResolver.localizePersistent(
- new URIReferenceImpl(metadata.getPreallocationPredicateURI()));
- long preModel = systemResolver.localizePersistent(
- new URIReferenceImpl(metadata.getPreallocationModelURI()));
-
- // Every node cached by DatabaseMetadata must be preallocated
- systemResolver.modifyModel(preModel,
- new SingletonStatements(preSubject, prePredicate, model),
- true);
- systemResolver.modifyModel(preModel,
- new SingletonStatements(preSubject, prePredicate, rdfType),
- true);
- systemResolver.modifyModel(preModel,
- new SingletonStatements(preSubject, prePredicate, modelType),
- true);
- systemResolver.modifyModel(preModel,
- new SingletonStatements(preSubject, prePredicate, preSubject),
- true);
- systemResolver.modifyModel(preModel,
- new SingletonStatements(preSubject, prePredicate, prePredicate),
- true);
- systemResolver.modifyModel(preModel,
- new SingletonStatements(preSubject, prePredicate, preModel),
- true);
-
- metadata.initializePreallocationNodes(preSubject, prePredicate, preModel);
-
- systemResolverFactory.setDatabaseMetadata(metadata);
-
- return model;
- } catch (Throwable e) {
- rollbackTransactionalBlock(e);
- return -1; // Should be discarded by exception in endTransactionalBlock.
- } finally {
- endTransactionalBlock("Could not commit system model bootstrap");
- }
+ return operation.getResult();
}
/**
@@ -540,14 +384,12 @@
logger.info("QUERY: " + query);
}
- // Evaluate the query
QueryOperation queryOperation = new QueryOperation(query, this);
- executeQuery(queryOperation);
+ execute(queryOperation, "Query failed");
return queryOperation.getAnswer();
}
public List query(List queryList) throws QueryException {
-
if (logger.isInfoEnabled()) {
StringBuffer log = new StringBuffer("QUERYING LIST: ");
for (int i = 0; i < queryList.size(); i++) {
@@ -557,7 +399,7 @@
}
QueryOperation queryOperation = new QueryOperation(queryList, this);
- executeQuery(queryOperation);
+ execute(queryOperation, "Failed list query");
return queryOperation.getAnswerList();
}
@@ -576,9 +418,8 @@
if (logger.isInfoEnabled()) {
logger.info("REMOVE MODEL: " + modelURI);
}
- // Validate "modelURI" parameter
if (modelURI == null) {
- throw new IllegalArgumentException("Null \"modelURI\" parameter");
+ throw new IllegalArgumentException("Null 'modelURI' parameter");
}
execute(new RemoveModelOperation(modelURI), "Unable to remove " + modelURI);
@@ -624,8 +465,7 @@
// Validate parameters
if (destinationModelURI == null) {
throw new IllegalArgumentException("Null 'destinationModelURI' parameter");
- }
- if (modelExpression == null) {
+ } else if (modelExpression == null) {
throw new IllegalArgumentException("Null 'modelExpression' parameter");
}
@@ -680,99 +520,39 @@
public void setAutoCommit(boolean autoCommit) throws QueryException {
if (logger.isInfoEnabled()) {
- logger.info("setAutoCommit(" + autoCommit + ") called with autoCommit = " + this.autoCommit);
+ logger.info("setAutoCommit(" + autoCommit + ") called.");
}
-
- if (!this.autoCommit && autoCommit) { // Turning autoCommit on
- try {
- resumeTransactionalBlock();
- } finally {
- this.autoCommit = true;
- this.inFailedTransaction = false;
- endTransactionalBlock("Extended transaction failed");
- }
- } else if (this.autoCommit && !autoCommit) { // Turning autoCommit off
- if (this.transaction != null) {
- resumeTransactionalBlock();
- endPreviousQueryTransaction();
- }
- systemResolver = beginTransactionalBlock(true);
- try {
- suspendTransactionalBlock();
- } catch (Throwable th) {
- logger.error("Failed to suspend transaction", th);
- rollbackTransactionalBlock(th);
- endTransactionalBlock("Could set auto Commit off");
- }
- this.autoCommit = false;
- } else if (this.inFailedTransaction) { // Reset after failed autoCommit off based transaction.
- this.inFailedTransaction = false;
- } else { // Leaving autoCommit the same
- if (logger.isInfoEnabled()) {
- logger.info("Invalid call to setAutoCommit(" + autoCommit + ") called with autoCommit = " + this.autoCommit);
- }
+ try {
+ transactionManager.setAutoCommit(this, autoCommit);
+ } catch (MulgaraTransactionException em) {
+ throw new QueryException("Error setting autocommit", em);
}
}
public void commit() throws QueryException {
logger.info("Committing transaction");
- if (!autoCommit) {
- synchronized (DatabaseSession.class) {
- setAutoCommit(true);
- setAutoCommit(false);
- }
+ try {
+ transactionManager.commit(this);
+ } catch (MulgaraTransactionException em) {
+ throw new QueryException("Error performing commit", em);
}
}
public void rollback() throws QueryException {
logger.info("Rollback transaction");
- if (autoCommit) {
- throw new QueryException(
- "Attempt to rollback transaction outside transaction");
- }
- resumeTransactionalBlock();
try {
- explicitRollback = true;
- rollbackTransactionalBlock(new QueryException(
- "Explicit rollback requested on session"));
- } catch (Throwable th) {
- logger.error("Failed to rollback transaction", th);
- throw new QueryException("Rollback failed", th);
- } finally {
- synchronized (DatabaseSession.class) {
- try {
- endTransactionalBlock("Rollback failed, ending transaction");
- } catch (Throwable th) {
- throw new QueryException("Rollback failed", th);
- }
- setAutoCommit(false);
- }
+ transactionManager.rollback(this);
+ } catch (MulgaraTransactionException em) {
+ throw new QueryException("Error performing rollback", em);
}
}
public void close() throws QueryException {
logger.info("Closing session");
- if (!autoCommit) {
- logger.warn("Closing session while holding write-lock");
-
- try {
- resumeTransactionalBlock();
- } catch (Throwable th) {
- releaseWriteLock();
- throw new QueryException("Error while resuming transaction in close", th);
- }
-
- try {
- rollbackTransactionalBlock(
- new QueryException("Attempt to close session whilst in transaction"));
- } finally {
- endTransactionalBlock("Failed to release write-lock in close");
- }
- } else {
- if (this.transaction != null) {
- resumeTransactionalBlock();
- endPreviousQueryTransaction();
- }
+ try {
+ transactionManager.terminateCurrentTransactions(this);
+ } catch (MulgaraTransactionException em) {
+ throw new QueryException("Error closing session. Forced close required", em);
}
}
@@ -785,10 +565,6 @@
logger.debug("Login of " + user + " to " + securityDomain);
}
- /*
- execute(new LoginOperation(securityDomain, user, password),
- "Unable to login " + user + " to " + securityDomain);
- */
if (securityDomain.equals(metadata.getSecurityDomainURI())) {
// Propagate the login event to the security adapters
for (Iterator i = securityAdapterList.iterator(); i.hasNext();) {
@@ -797,482 +573,7 @@
}
}
- //
- // Transaction control methods. Implements LocalSession.
- //
-
/**
- * Start's or resumes a transaction for an operation.
- *
- * Using start/finish TransactionalOperation ensures properly matched pairs of
- * begin/end and suspend/resume.
- */
- public void startTransactionalOperation(boolean needsWrite) throws
- QueryException {
- logger.info("Starting Transactional Operation");
- if (opState != FINISH) {
- throw new IllegalArgumentException(
- "Attempt to start transactional operation during: " +
- opStates[opState]);
- }
- if (autoCommit) {
- if (this.transaction != null) {
- resumeTransactionalBlock();
- endPreviousQueryTransaction();
- }
- beginTransactionalBlock(needsWrite);
- logger.info("BEGIN new transaction.");
- opState = BEGIN;
- } else {
- resumeTransactionalBlock();
- logger.info("RESUME old transaction.");
- opState = RESUME;
- }
- }
-
- /**
- * Mark the current transaction for rollback due to an exception.
- *
- * This records the exception which caused the rollback in the
- * {@link #rollbackCause} field.
- */
- public void rollbackTransactionalBlock(Throwable throwable) throws
- QueryException {
- logger.info("Rollback Transactional Block");
- assert throwable != null;
-
- try {
- if (logger.isDebugEnabled()) {
- logger.debug("Marking transaction for rollback", throwable);
- }
- transactionManager.setRollbackOnly();
- } catch (Throwable e) {
- logger.error("Needed to mark transaction for rollback", throwable);
- logger.error("Unable to mark transaction for rollback", e);
- throw new QueryException("Unable to mark transaction for rollback", e);
- }
-
- rollbackCause = throwable;
- }
-
- /**
- * Ends's or suspends a transaction for an operation.
- *
- * Using start/finish TransactionalOperation ensures properly matched pairs of
- * begin/end and suspend/resume.
- */
- public void finishTransactionalOperation(String errorString) throws
- QueryException {
- logger.info("Finishing Transactional Operation");
- if (logger.isDebugEnabled()) {
- logger.debug("opState = " + opStates[opState]);
- logger.debug("autoCommit = " + autoCommit);
- }
- if (opState == FINISH) {
- throw new IllegalArgumentException(
- "Attempt to finish transactional operation during: " + opStates[opState]);
- }
- if (autoCommit) {
- try {
- endTransactionalBlock(errorString);
- } finally {
- logger.info("FINISH(end) implicit transaction.");
- opState = FINISH;
- }
- } else {
- try {
- suspendTransactionalBlock();
- } catch (Throwable th) {
- logger.error("Failed to suspend transaction", th);
- try {
- rollbackTransactionalBlock(new QueryException("Failed to suspend transaction"));
- } finally {
- endTransactionalBlock("Failed to suspend transaction at end of operation");
- }
- } finally {
- logger.info("FINISH(suspend) explicit transaction.");
- opState = FINISH;
- }
- }
- }
-
- /**
- * Resumes the previously suspended transaction from the current session.
- *
- * @throws QueryException Must be called outside the try/catch(Throwable) block
- * protecting the transaction.
- */
- public void resumeTransactionalBlock() throws QueryException {
- logger.info("Resume Transactional Block");
- if (transaction == null) {
- throw new IllegalStateException("Attempt to resume unsuspended transaction");
- } else if (inFailedTransaction == true) {
- throw new IllegalStateException("Transaction already failed, set autocommit true to reset");
- }
-
- try {
- transactionManager.resume(this.transaction);
- this.transaction = null;
- } catch (Exception e) {
- logger.error("Resume failed", e);
- throw new QueryException("Failed to resume transaction", e);
- }
- }
-
- /**
- * Suspends current transaction, storing it in session for latter resumption.
- *
- * @throws Throwable Must be called inside the try/catch(Throwable) block
- * protecting the transaction.
- */
- public void suspendTransactionalBlock() throws Throwable {
- logger.info("Suspend Transactional Block");
- if (transaction != null) {
- throw new IllegalStateException(
- "Attempt to suspend unresumed transaction.");
- }
- if (logger.isInfoEnabled()) {
- logger.info(
- "Suspend Transactional Block autocommit=" + autoCommit +
- " transaction status=" + StatusFormat.formatStatus(transactionManager)
- );
- }
-
- int status = transactionManager.getStatus();
- if (!autoCommit &&
- (status == Status.STATUS_MARKED_ROLLBACK ||
- status == Status.STATUS_ROLLEDBACK ||
- status == Status.STATUS_ROLLING_BACK)) {
- inFailedTransaction = true;
- throw new QueryException("Transaction marked for rollback");
- }
-
- this.transaction = transactionManager.suspend();
- }
-
- public ResolverSession getResolverSession() {
- return systemResolver;
- }
-
- //
- // Internal Transactional Methods. Not exposed via the interface.
- //
-
- /**
- * Mark the beginning of a transactional block.
- *
- * This begins a transaction if {@link #autoCommit} is <code>true</code>.
- *
- * @throws QueryException if a transaction needed to be begun and couldn't be
- */
- private SystemResolver beginTransactionalBlock(boolean allowWrites) throws
- QueryException {
- if (logger.isInfoEnabled()) {
- logger.info("Beginning transactional block: autocommit = " + autoCommit);
- }
-
- // Start the transaction
- if (inFailedTransaction == true) {
- throw new IllegalStateException("Transaction already failed, set autocommit true to reset");
- } else if (!enlistedResolverMap.isEmpty()) {
- throw new QueryException("Stale resolvers found in enlistedResolverMap");
- }
-
-
- if (allowWrites) {
- try {
- obtainWriteLock();
- } catch (InterruptedException ei) {
- throw new QueryException("Unable to obtain write lock", ei);
- }
- }
-
- try {
- transactionManager.begin();
- if (systemResolver != null) {
- throw new QueryException("beginning nested transaction");
- }
- systemResolver = systemResolverFactory.newResolver(allowWrites);
- return (SystemResolver) operationContext.enlistResolver(systemResolver);
- } catch (Exception e) {
- throw new QueryException("Unable to begin transaction", e);
- }
- }
-
- /**
- * Mark the end of a transactional block.
- *
- * This commits the current transaction if {@link #autoCommit} is
- * <code>true</code>.
- *
- * @throws QueryException if a transaction needed to be committed and
- * couldn't be
- */
- void endTransactionalBlock(String failureMessage) throws QueryException {
- if (logger.isInfoEnabled()) {
- logger.info(
- "End Transactional Block autocommit=" + autoCommit +
- " transaction status=" + StatusFormat.formatStatus(transactionManager)
- );
- }
-
- try {
- // Commit the transaction
- if (rollbackCause == null) {
- transactionManager.commit();
- } else {
- try {
- transactionManager.commit();
- } catch (RollbackException e) {
- // Sneakily reinsert the exception recorded earlier by the
- // rollbackTransactionalBlock method. Without this feature, it's
- // very difficult to determine why a rollback occurred.
- e.initCause(rollbackCause);
- throw e;
- } finally {
- rollbackCause = null;
- }
- }
- } catch (Exception e) {
- if (!explicitRollback) {
- throw new QueryException(failureMessage, e);
- }
- } finally {
- releaseWriteLock();
- enlistedResolverMap.clear();
- outstandingAnswers.clear();
- clearCache();
- operationContext.clearSystemModelCache();
-
- systemResolver = null;
- explicitRollback = false;
- autoCommit = true;
- }
- }
-
- void endPreviousQueryTransaction() throws QueryException {
- logger.debug("Clearing previous transaction");
-
- // Save the exception.
- Throwable tmpThrowable = rollbackCause;
-
- Set answers = new HashSet(outstandingAnswers);
- Iterator i = answers.iterator();
- while (i.hasNext()) {
- try {
- SubqueryAnswer s = (SubqueryAnswer) i.next();
- operationContext.deregisterAnswer(s);
- //Do not close tuples - for Jena and JRDF.
- //s.close();
- } catch (Throwable th) {
- logger.debug("Failed to close preexisting answer", th);
- }
- }
-
- // If by closing the answer we have called endTransactionalBlock then
- // throw the saved exception.
- if ((rollbackCause == null) && (tmpThrowable != null) &&
- (systemResolver == null)) {
- throw new QueryException("Failure ending previous query", tmpThrowable);
- }
-
- try {
- if (!outstandingAnswers.isEmpty()) {
- throw new QueryException("Failed to clear preexisting transaction");
- }
- if (this.transaction != null) {
- throw new QueryException("Failed to void suspended transaction");
- }
- if (transactionManager.getTransaction() != null) {
- throw new QueryException("Failed to end transaction");
- }
- } catch (QueryException eq) {
- endTransactionalBlock("Error ending previous query");
- throw eq;
- } catch (Throwable th) {
- endTransactionalBlock("Error ending previous query");
- throw new QueryException("Failure ending previous query", th);
- }
- }
-
- private void obtainWriteLock() throws InterruptedException {
- logger.info("Trying to obtain write lock. ");
- synchronized (DatabaseSession.class) {
- if (DatabaseSession.writeSession == this) {
- return;
- }
- while (DatabaseSession.writeSession != null) {
- DatabaseSession.class.wait();
- }
- DatabaseSession.writeSession = this;
- this.writing = true;
- logger.info("Obtained write lock. ");
- }
- }
-
- private void releaseWriteLock() {
- synchronized (DatabaseSession.class) {
- if (DatabaseSession.writeSession == this) {
- logger.info("Releasing write lock");
- DatabaseSession.writeSession = null;
- this.writing = false;
- DatabaseSession.class.notifyAll();
- }
- }
- }
-
- //
- // Internal support methods.
- //
-
- /**
- * Clear the cache of temporary models.
- */
- private void clearCache()
- {
- // Clear the temporary models
- if (!cachedModelSet.isEmpty()) {
- try {
- Resolver temporaryResolver =
- temporaryResolverFactory.newResolver(true,
- systemResolver,
- systemResolver);
- for (Iterator i = cachedModelSet.iterator(); i.hasNext();) {
- LocalNode modelLocalNode = (LocalNode) i.next();
- long model = modelLocalNode.getValue();
-
- if (changedCachedModelSet.contains(modelLocalNode)) {
- // Write back the modifications to the original model
- try {
- Resolver resolver =
- findResolverFactory(model).newResolver(true,
- systemResolver,
- systemResolver);
- Variable s = new Variable("s"),
- p = new Variable("p"),
- o = new Variable("o");
- resolver.modifyModel(
- model,
- new TuplesWrapperStatements(
- temporaryResolver.resolve(
- new ConstraintImpl(s, p, o, modelLocalNode)
- ),
- s, p, o
- ),
- true // insert the content
- );
- }
- catch (Exception e) {
- logger.error("Failed to write back cached model " + model +
- " after transaction", e);
- }
- changedCachedModelSet.remove(modelLocalNode);
- }
-
- // Remove the cached model
- try {
- temporaryResolver.removeModel(model);
- }
- catch (Exception e) {
- logger.error(
- "Failed to clear cached model " + model + " after transaction",
- e
- );
- }
- i.remove();
- }
- }
- catch (Exception e) {
- logger.error("Failed to clear cached models after transaction", e);
- }
- }
- }
-
- /**
- * Find a cached resolver factory for write back.
- *
- * @return a completely unwrapped resolver factory
- */
- // TODO: Common code with DatabaseOperationContent.findModelResolverFactory
- // should be consolidated.
- private ResolverFactory findResolverFactory(long model) throws QueryException
- {
- if (logger.isDebugEnabled()) {
- logger.debug("Finding raw resolver factory for model " + model);
- }
-
- try {
- // get the model URI
- Node modelNode = systemResolver.globalize(model);
- if (!(modelNode instanceof URIReference)) {
- throw new QueryException(modelNode.toString() + " is not a valid Model");
- }
- URI modelURI = ((URIReference)modelNode).getURI();
-
- // test the model URI against the current server
- try {
- if (logger.isDebugEnabled()) {
- logger.debug("Comparing " + metadata.getURI().toString() + " to " + (new URI(modelURI.getScheme(),
- modelURI.getSchemeSpecificPart(), null)).toString());
- }
- if (metadata.getURI().equals(new URI(modelURI.getScheme(), modelURI.getSchemeSpecificPart(), null))) {
- // should be on the current server, but was not found here
- throw new QueryException(modelNode.toString() + " is not a Model");
- }
- }
- catch (URISyntaxException use) {
- throw new QueryException("Internal error. Model URI cannot be manipulated.");
- }
-
- // This is not a local model, get the protocol
- String modelProtocol = operationContext.findProtocol(model);
- if (logger.isDebugEnabled()) {
- logger.debug("Model " + model + " protocol is " + modelProtocol);
- }
-
- // find the factory for this protocol
- ResolverFactory resolverFactory =
- (ResolverFactory) externalResolverFactoryMap.get(modelProtocol);
- if (resolverFactory == null) {
- throw new QueryException(
- "Unsupported protocol for destination model (" +
- modelProtocol + ", " + model + " : '" + modelProtocol + "')");
- }
-
- return resolverFactory;
- }
- catch (GlobalizeException eg) {
- throw new QueryException("Unable to globalize modeltype", eg);
- }
- }
-
- //
- // Private accessors intended only for DatabaseOperationContext
- //
-
- SystemResolver getSystemResolver() {
- return systemResolver;
- }
-
- Transaction getTransaction() {
- return transaction;
- }
-
- boolean isWriting() {
- return writing;
- }
-
- boolean ensureTransactionResumed() throws QueryException {
- if (this.transaction != null) {
- resumeTransactionalBlock();
- return true;
- } else {
- return false;
- }
- }
-
-
- /**
* Backup all the data on the specified server to a URI or an output stream.
* The database is not changed by this method.
*
@@ -1283,13 +584,11 @@
* @param destinationURI Option URI of the file to backup into.
* @throws QueryException if the backup cannot be completed.
*/
- private synchronized void backup(OutputStream outputStream,
- URI serverURI,
- URI destinationURI) throws QueryException {
+ private synchronized void backup(OutputStream outputStream, URI serverURI, URI destinationURI)
+ throws QueryException {
execute(
new BackupOperation(outputStream, serverURI, destinationURI),
- "Unable to backup to " + destinationURI
- );
+ "Unable to backup to " + destinationURI);
}
//
@@ -1322,75 +621,31 @@
* Execute an {@link Operation}.
*
* @param operation the {@link Operation} to execute
- * @param failureMessage text to appear as the exception message if the
- * <var>operation</var> fails
* @throws QueryException if the <var>operation</var> fails
*/
- private void execute(Operation operation, String failureMessage)
- throws QueryException
+ private void execute(Operation operation, String errorString) throws QueryException
{
- assert operation != null;
-
- startTransactionalOperation(operation.isWriteOperation());
-
- assert systemResolver != null;
try {
- operation.execute(operationContext, systemResolver, resolverSessionFactory, metadata);
- } catch (Throwable e) {
- rollbackTransactionalBlock(e);
- } finally {
- finishTransactionalOperation(failureMessage);
+ MulgaraTransaction transaction =
+ transactionManager.getTransaction(this, operation.isWriteOperation());
+ transaction.execute(operation, resolverSessionFactory, metadata);
+ } catch (MulgaraTransactionException em) {
+ logger.info("Error executing operation: " + errorString, em);
+ throw new QueryException(errorString, em);
}
}
- /**
- * Execute an {@link Operation}.
- *
- * @param operation the {@link Operation} to execute
- * @throws QueryException if the <var>operation</var> fails
- */
- private void executeQuery(Operation operation) throws QueryException
- {
- /*
- * Transaction semantics:
- * AC && Suspended -> R clr E B . S
- * AC && !Suspended -> B . S
- * !AC -> R clr . S
- */
- if (autoCommit) {
- if (this.transaction != null) {
- resumeTransactionalBlock();
- endPreviousQueryTransaction();
- }
- beginTransactionalBlock(operation.isWriteOperation());
- }
- else {
- resumeTransactionalBlock();
- }
-
- try {
- operation.execute(operationContext,
- systemResolver,
- resolverSessionFactory,
- metadata);
- }
- catch (Throwable th) {
- try {
- logger.warn("Query failed", th);
- rollbackTransactionalBlock(th);
- } finally {
- endPreviousQueryTransaction();
- throw new QueryException("Failed to rollback failed transaction", th);
- }
- }
-
- try {
- suspendTransactionalBlock();
- } catch (Throwable th) {
- endPreviousQueryTransaction();
- logger.error("Query should have thrown exception", th);
- throw new IllegalStateException("Query should have thrown exception");
- }
+ public DatabaseOperationContext newOperationContext(boolean writing) throws QueryException {
+ return new DatabaseOperationContext(
+ cachedResolverFactorySet,
+ externalResolverFactoryMap,
+ internalResolverFactoryMap,
+ metadata,
+ securityAdapterList,
+ temporaryModelTypeURI,
+ temporaryResolverFactory,
+ symbolicTransformationList,
+ systemResolverFactory,
+ writing);
}
-
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/InternalResolver.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/InternalResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/InternalResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -289,4 +289,8 @@
new SingletonStatements(model, rdfType, modelType),
present);
}
+
+ public void abort() {
+ resolver.abort();
+ }
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/LocalJRDFDatabaseSession.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/LocalJRDFDatabaseSession.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/LocalJRDFDatabaseSession.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -122,7 +122,7 @@
* external models
* @throws IllegalArgumentException if any argument is <code>null</code>
*/
- LocalJRDFDatabaseSession(TransactionManager transactionManager,
+ LocalJRDFDatabaseSession(MulgaraTransactionManager transactionManager,
List securityAdapterList, List symbolicTransformationList,
ResolverSessionFactory resolverSessionFactory,
SystemResolverFactory systemResolverFactory,
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/ModifyModelOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/ModifyModelOperation.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/ModifyModelOperation.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -199,7 +199,7 @@
else {
assert query != null;
- Answer answer = operationContext.doQuery(systemResolver, query);
+ Answer answer = operationContext.doQuery(query);
Variable[] vars = answer.getVariables();
assert vars.length == 3;
statements = new TuplesWrapperStatements(
@@ -211,6 +211,7 @@
doModify(operationContext, systemResolver, modelURI, statements, insert);
}
+
protected void doModify(OperationContext operationContext,
SystemResolver systemResolver,
URI modelURI,
@@ -239,9 +240,7 @@
// Obtain a resolver for the destination model type
Resolver resolver = operationContext.obtainResolver(
- operationContext.findModelResolverFactory(model),
- systemResolver
- );
+ operationContext.findModelResolverFactory(model));
assert resolver != null;
if (logger.isDebugEnabled()) {
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -27,10 +27,11 @@
// Local packages
import org.mulgara.resolver.spi.DatabaseMetadata;
-import org.mulgara.resolver.spi.Resolver;
+import org.mulgara.resolver.spi.EnlistableResource;
import org.mulgara.resolver.spi.ResolverSessionFactory;
import org.mulgara.query.TuplesException;
+import org.mulgara.query.QueryException;
/**
* Responsible for the javax.transaction.Transaction object.
@@ -52,11 +53,11 @@
*
* @maintenanceAuthor $Author: $
*
- * @company <A href="mailto:mail at netymon.com">Netymon Pty Ltd</A>
+ * @company <a href="mailto:mail at netymon.com">Netymon Pty Ltd</a>
*
* @copyright ©2006 <a href="http://www.netymon.com/">Netymon Pty Ltd</a>
*
- * @licence Open Software License v3.0</a>
+ * @licence Open Software License v3.0
*/
public class MulgaraTransaction {
/** Logger. */
@@ -64,7 +65,7 @@
Logger.getLogger(MulgaraTransaction.class.getName());
private MulgaraTransactionManager manager;
- private OperationContext context;
+ private DatabaseOperationContext context;
private Transaction transaction;
private Thread currentThread;
@@ -79,179 +80,384 @@
private int rollback;
private Throwable rollbackCause;
- public MulgaraTransaction(MulgaraTransactionManager manager, OperationContext context) {
- this.manager = manager;
- this.context = context;
+ public MulgaraTransaction(MulgaraTransactionManager manager, DatabaseOperationContext context)
+ throws Exception {
+ report("Creating Transaction");
+ try {
+ if (manager == null) {
+ throw new IllegalArgumentException("Manager null in MulgaraTransaction");
+ } else if (context == null) {
+ throw new IllegalArgumentException("OperationContext null in MulgaraTransaction");
+ }
+ this.manager = manager;
+ this.context = context;
-// FIXME: MTMgr will be null until operational.
-// this.transaction = manager.transactionStart(this);
- inuse = 1; // Note: This implies implict activation as a part of construction.
- using = 0;
+ inuse = 0;
+ using = 0;
- rollback = NO_ROLLBACK;
- rollbackCause = null;
+ rollback = NO_ROLLBACK;
+ rollbackCause = null;
+ } finally {
+ report("Created Transaction");
+ }
+ }
-// FIXME: need this added to context. Sets up and enlists the system-resolver.
-// context.initiate();
-// FIXME: need this added to context. Allows context to cleanup caches at end of transaction.
-// this.transaction.enlistResource(context.getXAResource());
- }
+ synchronized void activate() throws MulgaraTransactionException {
+ report("Activating Transaction");
+ try {
+ if (rollback != NO_ROLLBACK) {
+ throw new MulgaraTransactionException("Attempt to activate failed transaction");
+ }
- // FIXME: Not yet certain I have the error handling right here.
- // Need to clarify semantics and ensure the error conditions are
- // properly handled.
- private synchronized void activate() throws MulgaraTransactionException {
- if (currentThread == null) {
- currentThread = Thread.currentThread();
- } else if (!currentThread.equals(Thread.currentThread())) {
- throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
- }
+ if (currentThread == null) {
+ currentThread = Thread.currentThread();
+ } else if (!currentThread.equals(Thread.currentThread())) {
+ throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ }
+
+ if (manager == null) {
+ errorReport("Attempt to activate terminated transaction");
+ throw new MulgaraTransactionException("Attempt to activate terminated transaction");
+ }
- if (inuse == 0) {
- try {
- manager.transactionResumed(this);
- } catch (Throwable th) {
- logger.warn("Error resuming transaction: ", th);
- failTransaction();
- throw new MulgaraTransactionException("Error resuming transaction", th);
+ if (inuse == 0) {
+ if (transaction == null) {
+ startTransaction();
+ } else {
+ resumeTransaction();
+ }
}
+
+ inuse++;
+
+ checkActivated();
+ } finally {
+ report("Activated transaction");
}
-
- inuse++;
}
-
- // FIXME: Not yet certain I have the error handling right here.
- // Need to clarify semantics and ensure the error conditions are
- // properly handled.
private synchronized void deactivate() throws MulgaraTransactionException {
+ report("Deactivating transaction");
+ try {
+ if (rollback == NO_ROLLBACK) {
+ checkActivated();
+ } // rollback'd transactions are cleaned up on the final deactivation.
- inuse--;
+ inuse--;
- if (inuse < 0) {
- throw implicitRollback(
- new MulgaraTransactionException("Mismatched activate/deactivate. inuse < 0: " + inuse));
- }
-
- if (inuse == 0) {
- if (using == 0) {
- // END TRANSACTION HERE. But commit might fail.
- manager.transactionComplete(this);
- } else {
- // What happens if suspend fails?
- // Rollback and terminate transaction.
- // JTA isn't entirely unambiguous as to the long-term stability of the original
- // transaction object - can suspend return a new object?
- this.transaction = manager.transactionSuspended(this);
+ if (inuse == 0) {
+ if (using == 0) {
+ terminateTransaction();
+ } else {
+ suspendTransaction();
+ }
+ currentThread = null;
}
- currentThread = null;
+ } finally {
+ report("Deactivated Transaction");
}
}
- // Do I want to check for currentThread here? Do I want a seperate check() method to
- // cover precondition checks against currentThread?
- void reference() {
- using++;
+ // Note: The transaction is often not activated when these are called.
+ // This occurs when setting autocommit, as this creates and
+ // references a transaction object that won't be started/activated
+ // until it is first used.
+ void reference() throws MulgaraTransactionException {
+ report("Referencing Transaction");
+ try {
+ using++;
+ } finally {
+ report("Referenced Transaction");
+ }
}
void dereference() throws MulgaraTransactionException {
- using--;
- if (using < 0) {
- throw implicitRollback(new MulgaraTransactionException("ERROR: Transaction dereferenced more times than referenced!"));
+ report("Dereferencing Transaction");
+ try {
+ if (using < 1) {
+ throw implicitRollback(new MulgaraTransactionException(
+ "Reference Failure. Dereferencing while using < 1: " + using));
+ }
+ using--;
+ } finally {
+ report("Dereferenced Transaction");
}
}
void execute(Operation operation,
ResolverSessionFactory resolverSessionFactory, // FIXME: We shouldn't need this. - only used for backup and restore operations.
DatabaseMetadata metadata) throws MulgaraTransactionException {
- activate();
+ report("Executing Operation");
try {
-// FIXME: Need to migrate systemResolver to context for this to work.
-// operation.execute(context,
-// context.getSystemResolver(),
-// resolverSessionFactory,
-// metadata);
- } catch (Throwable th) {
- throw implicitRollback(th);
+ activate();
+ try {
+ operation.execute(context,
+ context.getSystemResolver(),
+ resolverSessionFactory,
+ metadata);
+ } catch (Throwable th) {
+ throw implicitRollback(th);
+ } finally {
+ deactivate();
+ }
} finally {
- deactivate();
+ report("Executed Operation");
}
}
- /** Should rename this 'wrap' */
AnswerOperationResult execute(AnswerOperation ao) throws TuplesException {
-// FIXME: activate/deactivate won't work until we have MTMgr operational.
-// activate();
+ debugReport("Executing AnswerOperation");
try {
- ao.execute();
- return ao.getResult();
- } catch (Throwable th) {
- throw new TuplesException("Error accessing Answer", th);
-// throw implicitRollback(th);
+ activate();
+ try {
+ ao.execute();
+ return ao.getResult();
+ } catch (Throwable th) {
+ throw implicitRollback(th);
+ } finally {
+ deactivate();
+ }
+ } catch (MulgaraTransactionException em) {
+ throw new TuplesException("Transaction error", em);
} finally {
-// deactivate();
+ debugReport("Executed AnswerOperation");
}
}
- private MulgaraTransactionException implicitRollback(Throwable cause) throws MulgaraTransactionException {
- rollback = IMPLICIT_ROLLBACK;
- rollbackCause = cause;
- failTransaction();
- return new MulgaraTransactionException("Transaction Rolledback", cause);
+ void execute(TransactionOperation to) throws MulgaraTransactionException {
+ report("Executing TransactionOperation");
+ try {
+ activate();
+ try {
+ to.execute();
+ } catch (Throwable th) {
+ throw implicitRollback(th);
+ } finally {
+ deactivate();
+ }
+ } finally {
+ report("Executed TransactionOperation");
+ }
}
+
+ MulgaraTransactionException implicitRollback(Throwable cause) throws MulgaraTransactionException {
+ report("Implicit Rollback triggered");
+
+ if (rollback == IMPLICIT_ROLLBACK) {
+ logger.warn("Cascading error, transaction already rolled back", cause);
+ logger.warn("Cascade error, expected initial cause", rollbackCause);
+
+ return new MulgaraTransactionException("Transaction already in rollback", cause);
+ }
+
+ try {
+ checkActivated();
+ rollback = IMPLICIT_ROLLBACK;
+ rollbackCause = cause;
+ failTransaction();
+ return new MulgaraTransactionException("Transaction in Rollback", cause);
+ } catch (Throwable th) {
+ abortTransaction("Failed to rollback normally", th);
+ throw new MulgaraTransactionException("Abort failed to throw exception", th);
+ }
+ }
+
/**
- * Note: I think this is the only one that matters.
+ * Rollback the transaction.
+ * We don't throw an exception here when transaction fails - this is expected,
+ * after all we requested it.
*/
- protected void explicitRollback() throws MulgaraTransactionException {
- rollback = EXPLICIT_ROLLBACK;
- // We don't throw an exception here when transaction fails - this is expected,
- // after all we requested it.
+ public void explicitRollback() throws MulgaraTransactionException {
+ try {
+ checkActivated();
+ failTransaction();
+ rollback = EXPLICIT_ROLLBACK;
+ } catch (Throwable th) {
+ abortTransaction("Explicit rollback failed", th);
+ }
}
- private void terminateTransaction() throws MulgaraTransactionException {
+ private void startTransaction() throws MulgaraTransactionException {
+ report("Initiating transaction");
+ transaction = manager.transactionStart(this);
+ try {
+ context.initiate(this);
+ } catch (Throwable th) {
+ throw implicitRollback(th);
+ }
}
- private void failTransaction() throws MulgaraTransactionException {
- // We need to handle the whole fact this is an error, but the core operation is rollback.
+ private void resumeTransaction() throws MulgaraTransactionException {
+ report("Resuming transaction");
try {
- transaction.rollback();
- } catch (SystemException es) {
- throw new MulgaraTransactionException("Failed to Rollback", es);
+ manager.transactionResumed(this, transaction);
+ } catch (Throwable th) {
+ abortTransaction("Failed to resume transaction", th);
}
}
- private void finalizeTransaction() throws MulgaraTransactionException {
- // We need a whole load of error handling here, but the core operation is commit.
+ private void suspendTransaction() throws MulgaraTransactionException {
+ report("Suspending Transaction");
try {
- transaction.commit();
- } catch (Exception e) {
- throw new MulgaraTransactionException("Error while trying to commit", e);
+ if (rollback == NO_ROLLBACK) {
+ this.transaction = manager.transactionSuspended(this);
+ } else {
+ terminateTransaction();
+ }
+ } catch (Throwable th) {
+ throw implicitRollback(th);
} finally {
- manager.transactionComplete(this);
+ report("Finished suspending transaction");
}
}
+ private void terminateTransaction() throws MulgaraTransactionException {
+ report("Terminating Transaction: " + rollback);
+// errorReport("Terminating Transaction: " + rollback);
+ try {
+ switch (rollback) {
+ case NO_ROLLBACK:
+ report("Completing Transaction");
+ try {
+ transaction.commit();
+ transaction = null;
+ } catch (Throwable th) {
+ implicitRollback(th);
+ terminateTransaction();
+ }
+ break;
+ case IMPLICIT_ROLLBACK:
+ report("Completing Implicitly Failed Transaction");
+ // Check that transaction is cleaned up.
+ throw new MulgaraTransactionException(
+ "Failed transaction finalised. (ROLLBACK)", rollbackCause);
+ case EXPLICIT_ROLLBACK:
+ report("Completing explicitly failed transaction (ROLLBACK)");
+ // Check that transaction is cleaned up.
+ break;
+ }
+ } finally {
+ try {
+ try {
+ context.clear();
+ } catch (QueryException eq) {
+ throw new MulgaraTransactionException("Error clearing context", eq);
+ }
+ } finally {
+ try {
+ manager.transactionComplete(this);
+ } finally {
+ manager = null;
+ inuse = 0;
+ using = 0;
+ report("Terminated transaction");
+ }
+ }
+ }
+ }
+
+ private void failTransaction() throws Throwable {
+ transaction.rollback();
+ manager.transactionFailed(this);
+ context.clear();
+ }
+
+ void abortTransaction(String errorMessage, Throwable th) throws MulgaraTransactionException {
+ // We need to notify the manager here - this is serious, we
+ // can't rollback normally if we can't resume! The call to
+ // context.abort() is an escape hatch we use to abort the
+ // current phase behind the scenes.
+ logger.error(errorMessage + " - Aborting", th);
+ try {
+ manager.transactionAborted(this);
+ } finally {
+ context.abort();
+ }
+ throw new MulgaraTransactionException(errorMessage + " - Aborting", th);
+ }
+
//
// Note that OperationContext needs to be decoupled from DatabaseSession, so that it is
// recreated for each operation - it also needs to provide an XAResource of it's own for
// enlisting in the transaction to clean-up caches and the like.
//
- public void enlistResolver(Resolver resolver) throws MulgaraTransactionException {
+ public void enlist(EnlistableResource enlistable) throws MulgaraTransactionException {
try {
- XAResource resource = resolver.getXAResource();
- transaction.enlistResource(resource);
+ transaction.enlistResource(enlistable.getXAResource());
} catch (Exception e) {
throw new MulgaraTransactionException("Error enlisting resolver", e);
}
}
+ //
+ // Should only be visible to MulgaraTransactionManager.
+ //
+
/**
- * Should only be visible to MulgaraTransactionManager.
+ * Force transaction to a conclusion.
+ * If we can't activate or commit, then rollback and terminate.
+ * This is called by the manager to indicate that it needs this transaction to
+ * be finished NOW, one way or another.
*/
- protected Transaction getTransaction() {
- return transaction;
+ void completeTransaction() throws MulgaraTransactionException {
+ try {
+ activate();
+ } catch (Throwable th) {
+ implicitRollback(th); // let terminate throw this exception if required.
+ } finally {
+ terminateTransaction();
+ }
+ // We don't need to deactivate - this method is *only* for use by the
+ // MulgaraTransactionManager!
}
+
+ protected void finalize() {
+ report("GC-finalize");
+ if (inuse != 0 || using != 0) {
+ errorReport("Referernce counting error in transaction");
+ }
+ if (manager != null || transaction != null) {
+ errorReport("Transaction not terminated properly");
+ }
+ }
+
+ //
+ // Used internally
+ //
+
+ private void checkActivated() throws MulgaraTransactionException {
+ if (currentThread == null) {
+ throw new MulgaraTransactionException("Transaction failed activation check");
+ } else if (!currentThread.equals(Thread.currentThread())) {
+ throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ } else if (inuse < 1) {
+ throw implicitRollback(
+ new MulgaraTransactionException("Mismatched activate/deactivate. inuse < 1: " + inuse));
+ } else if (using < 0) {
+ throw implicitRollback(
+ new MulgaraTransactionException("Reference Failure. using < 0: " + using));
+ }
+ }
+
+ private void report(String desc) {
+ if (logger.isInfoEnabled()) {
+ logger.info(desc + ": " + System.identityHashCode(this) +
+ ", inuse=" + inuse + ", using=" + using);
+ }
+ }
+
+ private void debugReport(String desc) {
+ if (logger.isDebugEnabled()) {
+ logger.debug(desc + ": " + System.identityHashCode(this) +
+ ", inuse=" + inuse + ", using=" + using);
+ }
+ }
+
+ private void errorReport(String desc) {
+ logger.error(desc + ": " + System.identityHashCode(this) +
+ ", inuse=" + inuse + ", using=" + using, new Throwable());
+ }
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -19,7 +19,11 @@
// Java2 packages
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.Map;
+import java.util.Set;
+import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAResource;
@@ -29,6 +33,7 @@
// Local packages
import org.mulgara.server.Session;
+import org.mulgara.transaction.TransactionManagerFactory;
/**
* Manages transactions within Mulgara.
@@ -68,24 +73,37 @@
private Session currentWritingSession;
private MulgaraTransaction userTransaction;
- /** Map from session to transaction for all 'write' transactions that have been rolledback. */
- private Map failedSessions;
+ /** Set of sessions whose transactions have been rolledback.*/
+ private Set failedSessions;
- /** Map from thread to associated transaction. */
+ /**
+ * Map from transaction to initiating session.
+ * FIXME: This is only required for checking while we wait for 1-N.
+ * Remove once 1-N is implemented.
+ */
+ private Map sessions;
+
+ /**
+ * Map from initiating session to set of transactions.
+ * Used to clean-up transactions upon session close.
+ */
+ private Map transactions;
+
+ /** Map of threads to active transactions. */
private Map activeTransactions;
private TransactionManager transactionManager;
- private Object writeLockMutex;
-
- public MulgaraTransactionManager(TransactionManager transactionManager) {
+ public MulgaraTransactionManager(TransactionManagerFactory transactionManagerFactory) {
this.currentWritingSession = null;
this.userTransaction = null;
- this.failedSessions = new HashMap();
+ this.failedSessions = new HashSet();
+ this.sessions = new HashMap();
+ this.transactions = new HashMap();
+ this.activeTransactions = new HashMap();
- this.transactionManager = transactionManager;
- this.writeLockMutex = new Object();
+ this.transactionManager = transactionManagerFactory.newTransactionManager();
}
/**
@@ -99,50 +117,67 @@
* </ul>
*/
public synchronized MulgaraTransaction getTransaction(DatabaseSession session, boolean write) throws MulgaraTransactionException {
+
if (session == currentWritingSession) {
return userTransaction;
}
- if (write) {
- obtainWriteLock(session);
- }
+ try {
+ MulgaraTransaction transaction = write ?
+ obtainWriteLock(session) :
+ new MulgaraTransaction(this, session.newOperationContext(false));
+ sessions.put(transaction, session);
-// FIXME: Need to finish 1-N DS-OC and provide this method - should really be newOperationContext.
-// return new MulgaraTransaction(this, session.getOperationContext());
- return new MulgaraTransaction(this, null);
- }
-
-
- public synchronized MulgaraTransaction getTransaction()
- throws MulgaraTransactionException {
- MulgaraTransaction transaction = (MulgaraTransaction)activeTransactions.get(Thread.currentThread());
- if (transaction != null) {
return transaction;
- } else {
- throw new MulgaraTransactionException("No transaction assoicated with current thread");
+ } catch (MulgaraTransactionException em) {
+ throw em;
+ } catch (Exception e) {
+ throw new MulgaraTransactionException("Error creating transaction", e);
}
}
- private synchronized void obtainWriteLock(Session session)
+
+ private synchronized MulgaraTransaction obtainWriteLock(DatabaseSession session)
throws MulgaraTransactionException {
while (currentWritingSession != null) {
try {
- writeLockMutex.wait();
+ this.wait();
} catch (InterruptedException ei) {
throw new MulgaraTransactionException("Interrupted while waiting for write lock", ei);
}
}
- currentWritingSession = session;
+
+ try {
+ currentWritingSession = session;
+ userTransaction = new MulgaraTransaction(this, session.newOperationContext(true));
+ return userTransaction;
+ } catch (MulgaraTransactionException em) {
+ releaseWriteLock();
+ throw em;
+ } catch (Throwable th) {
+ releaseWriteLock();
+ throw new MulgaraTransactionException("Error while obtaining write-lock", th);
+ }
}
private synchronized void releaseWriteLock() {
+ // Calling this method multiple times is safe as the lock cannot be obtained
+ // between calls as this method is private, and all calling methods are
+ // synchronized.
currentWritingSession = null;
userTransaction = null;
- writeLockMutex.notify();
+ this.notify();
}
- public synchronized void commit(Session session) throws MulgaraTransactionException {
+ public synchronized void commit(DatabaseSession session) throws MulgaraTransactionException {
+ if (failedSessions.contains(session)) {
+ throw new MulgaraTransactionException("Attempting to commit failed exception");
+ } else if (session != currentWritingSession) {
+ throw new MulgaraTransactionException(
+ "Attempting to commit while not the current writing transaction");
+ }
+
setAutoCommit(session, true);
setAutoCommit(session, false);
}
@@ -153,64 +188,115 @@
* This
* This needs to be distinguished from an implicit rollback triggered by failure.
*/
- public synchronized void rollback(Session session) throws MulgaraTransactionException {
+ public synchronized void rollback(DatabaseSession session) throws MulgaraTransactionException {
if (session == currentWritingSession) {
try {
- userTransaction.explicitRollback();
- finalizeTransaction();
+ userTransaction.execute(new TransactionOperation() {
+ public void execute() throws MulgaraTransactionException {
+ userTransaction.explicitRollback();
+ }
+ });
+ if (userTransaction != null) {
+ // transaction referenced by something - need to explicitly end it.
+ userTransaction.completeTransaction();
+ }
} finally {
- failedSessions.put(currentWritingSession, userTransaction);
- userTransaction = null;
- currentWritingSession = null;
+ failedSessions.add(currentWritingSession);
releaseWriteLock();
+ setAutoCommit(session, false);
}
+ } else if (failedSessions.contains(session)) {
+ failedSessions.remove(session);
+ setAutoCommit(session, false);
} else {
- // We have a problem - rollback called on session that doesn't have a transaction active.
+ throw new MulgaraTransactionException(
+ "Attempt to rollback while not in the current writing transaction");
}
}
- public synchronized void setAutoCommit(Session session, boolean autoCommit)
+ public synchronized void setAutoCommit(DatabaseSession session, boolean autoCommit)
throws MulgaraTransactionException {
- if (session == currentWritingSession && failedSessions.containsKey(session)) {
- // CRITICAL ERROR - transaction failed, but we did not finalise it.
+ if (session == currentWritingSession && failedSessions.contains(session)) {
+ userTransaction.abortTransaction("Session failed and transaction not finalized",
+ new MulgaraTransactionException("Failed Session in setAutoCommit"));
}
- if (session == currentWritingSession || failedSessions.containsKey(session)) {
+ if (session == currentWritingSession || failedSessions.contains(session)) {
if (autoCommit) {
// AutoCommit off -> on === branch on current state of transaction.
if (session == currentWritingSession) {
// Within active transaction - commit and finalise.
try {
+ userTransaction.dereference();
+ userTransaction.completeTransaction();
} finally {
releaseWriteLock();
}
- } else {
+ } else if (failedSessions.contains(session)) {
// Within failed transaction - cleanup and finalise.
failedSessions.remove(session);
}
} else {
+ logger.info("Attempt to set autocommit false twice");
// AutoCommit off -> off === no-op. Log info.
}
} else {
if (autoCommit) {
// AutoCommit on -> on === no-op. Log info.
+ logger.info("Attempting to set autocommit true without setting it false");
} else {
// AutoCommit on -> off == Start new transaction.
- obtainWriteLock(session);
-// FIXME: finish DS-OC first.
-// userTransaction = new MulgaraTransaction(this, session.newOperationContext(true));
- currentWritingSession = session;
+ userTransaction = getTransaction(session, true);
+ userTransaction.reference();
}
}
}
- public synchronized void closingSession(Session session) throws MulgaraTransactionException {
- // Check if we hold the write lock, if we do then rollback and throw exception.
- // Otherwise - no-op.
- }
+ public synchronized void terminateCurrentTransactions(Session session)
+ throws MulgaraTransactionException {
+ if (failedSessions.contains(session)) {
+ failedSessions.remove(session);
+ return;
+ }
- public void finalizeTransaction() {
- throw new IllegalStateException("mmmm I was doing something here. I need to remember what.");
+ Throwable error = null;
+ try {
+ if (session == currentWritingSession) {
+ logger.error("Terminating session while holding writelock:" + session +
+ ":" + currentWritingSession + ": " + userTransaction);
+ userTransaction.execute(new TransactionOperation() {
+ public void execute() throws MulgaraTransactionException {
+ userTransaction.implicitRollback(
+ new MulgaraTransactionException("Terminating session while holding writelock"));
+ }
+ });
+ }
+ } catch (Throwable th) {
+ error = th;
+ }
+
+ Set trans = (Set)transactions.get(session);
+ if (trans != null) {
+ Iterator i = trans.iterator();
+ while (i.hasNext()) {
+ MulgaraTransaction transaction = (MulgaraTransaction)i.next();
+ logger.error("Active transaction during session termination");
+ Throwable th = transaction.implicitRollback(
+ new MulgaraTransactionException("Terminating session during active transaction"));
+ if (error == null) {
+ error = th;
+ }
+ transaction.completeTransaction();
+ }
+ }
+
+ if (error != null) {
+ if (error instanceof MulgaraTransactionException) {
+ throw (MulgaraTransactionException)error;
+ } else {
+ throw new MulgaraTransactionException("Aborting session on close", error);
+ }
+ }
}
//
@@ -220,6 +306,14 @@
public synchronized Transaction transactionStart(MulgaraTransaction transaction)
throws MulgaraTransactionException {
try {
+ logger.info("Beginning Transaction");
+ if (activeTransactions.get(Thread.currentThread()) != null) {
+ throw new MulgaraTransactionException(
+ "Attempt to start transaction in thread with exiting active transaction.");
+ } else if (activeTransactions.containsValue(transaction)) {
+ throw new MulgaraTransactionException("Attempt to start transaction twice");
+ }
+
transactionManager.begin();
Transaction jtaTrans = transactionManager.getTransaction();
@@ -231,18 +325,17 @@
}
}
- public synchronized void transactionResumed(MulgaraTransaction transaction)
+ public synchronized void transactionResumed(MulgaraTransaction transaction, Transaction jtaXA)
throws MulgaraTransactionException {
if (activeTransactions.get(Thread.currentThread()) != null) {
throw new MulgaraTransactionException(
"Attempt to resume transaction in already activated thread");
} else if (activeTransactions.containsValue(transaction)) {
- throw new MulgaraTransactionException(
- "Attempt to resume resumed transaction");
+ throw new MulgaraTransactionException("Attempt to resume active transaction");
}
try {
- transactionManager.resume(transaction.getTransaction());
+ transactionManager.resume(jtaXA);
activeTransactions.put(Thread.currentThread(), transaction);
} catch (Exception e) {
throw new MulgaraTransactionException("Resume Failed", e);
@@ -259,24 +352,56 @@
return transactionManager.suspend();
} catch (Exception e) {
+ logger.error("Attempt to suspend failed", e);
+ try {
+ transactionManager.setRollbackOnly();
+ } catch (Throwable th) {
+ logger.error("Attempt to setRollbackOnly() failed", th);
+ }
throw new MulgaraTransactionException("Suspend failed", e);
} finally {
activeTransactions.remove(Thread.currentThread());
}
-
}
public synchronized void transactionComplete(MulgaraTransaction transaction)
throws MulgaraTransactionException {
+ if (holdsWriteLock(transaction)) {
+ releaseWriteLock();
+ }
+
+ activeTransactions.remove(Thread.currentThread());
+ Session session = (Session)sessions.get(transaction);
+ sessions.remove(transaction);
+ transactions.remove(session);
+ }
+
+ public synchronized void transactionFailed(MulgaraTransaction transaction) {
+ // No specific behaviour required here.
+ }
+
+ public synchronized void transactionAborted(MulgaraTransaction transaction) {
try {
- transactionManager.commit();
+ // Make sure this cleans up the transaction metadata - this transaction is DEAD!
if (transaction == userTransaction) {
- releaseWriteLock();
+ failedSessions.add(currentWritingSession);
}
- } catch (Exception e) {
- throw new MulgaraTransactionException("Commit Failed", e);
- } finally {
- activeTransactions.remove(Thread.currentThread());
+ transactionComplete(transaction);
+ } catch (Throwable th) {
+ // FIXME: This should probably abort the entire server after logging the error!
+ logger.error("Error managing transaction abort", th);
}
}
+
+ public void setTransactionTimeout(int transactionTimeout) {
+ try {
+ transactionManager.setTransactionTimeout(transactionTimeout);
+ } catch (SystemException es) {
+ logger.warn("Unable to set transaction timeout: " + transactionTimeout, es);
+ }
+ }
+
+ private boolean holdsWriteLock(MulgaraTransaction transaction) {
+ return transaction == userTransaction;
+ }
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/OperationContext.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/OperationContext.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/OperationContext.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -103,8 +103,7 @@
* @throws QueryException if the {@link Resolver} couldn't be obtained, bound
* and enlisted
*/
- public Resolver obtainResolver(ResolverFactory resolverFactory,
- SystemResolver systemResolver)
+ public Resolver obtainResolver(ResolverFactory resolverFactory)
throws QueryException;
@@ -121,5 +120,7 @@
* Oct 2006 - if it's still here after Dec 2006 let someone know it's been
* forgotten.
*/
- public Answer doQuery(SystemResolver systemResolver, Query query) throws Exception;
+ public Answer doQuery(Query query) throws Exception;
+
+ public SystemResolver getSystemResolver(); // FIXME: Scaffolding for transactions.
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/QueryOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/QueryOperation.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/QueryOperation.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -153,14 +153,14 @@
if (query != null) {
assert queryList == null;
- answer = operationContext.doQuery(systemResolver, query);
+ answer = operationContext.doQuery(query);
}
else {
assert queryList != null;
answerList = new ArrayList(queryList.size());
for (Iterator i = queryList.iterator(); i.hasNext();) {
- answerList.add(operationContext.doQuery(systemResolver, (Query) i.next()));
+ answerList.add(operationContext.doQuery((Query) i.next()));
}
}
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/RemoveModelOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/RemoveModelOperation.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/RemoveModelOperation.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -155,8 +155,7 @@
}
// Obtain an appropriate resolver bound to this session
- Resolver resolver =
- operationContext.obtainResolver(resolverFactory, systemResolver);
+ Resolver resolver = operationContext.obtainResolver(resolverFactory);
assert resolver != null;
// Use the resolver to remove the model
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/SetModelOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/SetModelOperation.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/SetModelOperation.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -152,9 +152,7 @@
// Obtain a resolver for the destination model type
Resolver destinationResolver = operationContext.obtainResolver(
- operationContext.findModelResolverFactory(destinationModel),
- systemResolver
- );
+ operationContext.findModelResolverFactory(destinationModel));
assert destinationResolver != null;
ContentHandler contentHandler = contentHandlers.getContentHandler(content);
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/StatusFormat.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/StatusFormat.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/StatusFormat.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -30,7 +30,6 @@
// Java 2 enterprise packages
import javax.transaction.Status;
import javax.transaction.SystemException;
-import javax.transaction.TransactionManager;
/**
* Generate a presentation form for a transaction {@link Status}.
@@ -89,7 +88,8 @@
*
* @param transactionManager the transaction manager
*/
- public static String formatStatus(TransactionManager transactionManager)
+ /*
+ public static String formatStatus(MulgaraTransactionManager transactionManager)
{
try {
return formatStatus(transactionManager.getStatus());
@@ -98,4 +98,5 @@
return e.getMessage();
}
}
+ */
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/StringPoolSession.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/StringPoolSession.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/StringPoolSession.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -491,6 +491,7 @@
} else {
nodeId = persistentNodePool.newNode();
}
+
return nodeId;
}
// If it's a read phase and not the local BlankNode then throw an
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/SubqueryAnswer.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/SubqueryAnswer.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/SubqueryAnswer.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -76,7 +76,7 @@
private Variable[] variables;
/** The current database session for this query. */
- protected AnswerDatabaseSession databaseSession;
+ protected OperationContext operationContext;
/**
* Assignment property.
@@ -115,12 +115,11 @@
* @throws TuplesException if it fails to get the row cardinality of the
* given tuples.
*/
- SubqueryAnswer(AnswerDatabaseSession session, ResolverSession resolverSession,
+ SubqueryAnswer(OperationContext operationContext, ResolverSession resolverSession,
Tuples tuples, List variableList) throws TuplesException {
super(tuples, resolverSession);
- this.databaseSession = session;
- this.databaseSession.registerAnswer(this);
+ this.operationContext = operationContext;
assignVariables(tuples, variableList);
}
@@ -185,7 +184,6 @@
cloned.variables = new Variable[this.variables.length];
System.arraycopy(this.variables, 0, cloned.variables, 0,
this.variables.length);
- databaseSession.registerAnswer(cloned);
return cloned;
}
@@ -194,16 +192,6 @@
//
- public void close() throws TuplesException {
- super.close();
- try {
- databaseSession.deregisterAnswer(this);
- }
- catch (QueryException eq) {
- logger.info("Failed to deregister answer from session", eq);
- }
- }
-
public int getColumnIndex(Variable variable) throws TuplesException {
if (variable == null) {
throw new IllegalArgumentException("Null \"variable\" parameter");
@@ -313,7 +301,7 @@
logger.debug("Generated subquery: " + query);
}
- return databaseSession.innerQuery(query);
+ return operationContext.doQuery(query);
}
catch (Exception e) {
throw new QueryException("Failed to resolve subquery", e);
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/SubqueryAnswerUnitTest.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/SubqueryAnswerUnitTest.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/SubqueryAnswerUnitTest.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -160,7 +160,7 @@
*/
public void testVariableMappings() throws Exception {
ResolverSession testResolver = new TestResolverSession();
- AnswerDatabaseSession testDbSession = new TestAnswerDatabaseSession();
+ OperationContext testContext = new TestOperationContext();
Variable varX = new Variable("x");
Variable varY = new Variable("y");
@@ -177,7 +177,7 @@
variableList.add(varY);
// Create subquery.
- SubqueryAnswer answer = new SubqueryAnswer(testDbSession, testResolver,
+ SubqueryAnswer answer = new SubqueryAnswer(testContext, testResolver,
tuples, variableList);
// Get column index of Z.
@@ -188,19 +188,23 @@
assertEquals("Based on variable list Z should be", 1, columnIndexZ);
}
- private class TestAnswerDatabaseSession implements AnswerDatabaseSession {
+ private class TestOperationContext implements OperationContext {
+ public ResolverFactory findModelResolverFactory(long model)
+ throws QueryException { return null; }
- public TestAnswerDatabaseSession() {
- }
+ public ResolverFactory findModelTypeResolverFactory(URI modelTypeURI)
+ throws QueryException { return null; }
- public Answer innerQuery(Query query) throws QueryException {
- return null;
- }
+ public List getSecurityAdapterList() { return null; }
- public void registerAnswer(SubqueryAnswer answer) {
- }
+ public Resolver obtainResolver(ResolverFactory resolverFactory)
+ throws QueryException { return null; }
- public void deregisterAnswer(SubqueryAnswer answer) throws QueryException {
- }
+ public long getCanonicalModel(long model) { return 0; }
+
+ public Answer doQuery(Query query)
+ throws Exception { return null; }
+
+ public SystemResolver getSystemResolver() { return null; } // FIXME: Scaffolding for transactions.
}
}
Added: trunk/src/jar/resolver/java/org/mulgara/resolver/TransactionOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/TransactionOperation.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/TransactionOperation.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -0,0 +1,24 @@
+/*
+ * 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.rosenlaw.com/OSL3.0.htm
+ *
+ * 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.
+ *
+ * This file is an original work developed by Netymon Pty Ltd
+ * (http://www.netymon.com, mailto:mail at netymon.com). Portions created
+ * by Netymon Pty Ltd are Copyright (c) 2006 Netymon Pty Ltd.
+ * All Rights Reserved.
+ */
+
+package org.mulgara.resolver;
+
+import org.mulgara.query.TuplesException;
+
+interface TransactionOperation {
+ public void execute() throws MulgaraTransactionException;
+}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/TransactionalAnswer.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/TransactionalAnswer.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/TransactionalAnswer.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -17,6 +17,10 @@
package org.mulgara.resolver;
+// Third party packages
+import org.apache.log4j.Logger;
+
+// Local packages
import org.mulgara.query.Answer;
import org.mulgara.query.TuplesException;
import org.mulgara.query.Variable;
@@ -45,18 +49,39 @@
*/
public class TransactionalAnswer implements Answer {
+ /** Logger. */
+ private static final Logger logger =
+ Logger.getLogger(TransactionalAnswer.class.getName());
private Answer answer;
private MulgaraTransaction transaction;
- public TransactionalAnswer(MulgaraTransaction transaction, Answer answer) {
- this.answer = answer;
- this.transaction = transaction;
- transaction.reference();
+ private boolean closing;
+
+ public TransactionalAnswer(MulgaraTransaction transaction, Answer answer) throws TuplesException {
+ try {
+ report("Creating Answer");
+
+ if (transaction == null) {
+ throw new IllegalArgumentException("Transaction null in TransactionalAnswer");
+ } else if (answer == null) {
+ throw new IllegalArgumentException("Answer null in TransactionalAnswer");
+ }
+
+ this.answer = answer;
+ this.closing = false;
+ this.transaction = transaction;
+ transaction.reference();
+
+ report("Created Answer");
+ } catch (MulgaraTransactionException em) {
+ throw new TuplesException("Failed to associate with transaction", em);
+ }
}
public Object getObject(final int column) throws TuplesException {
+ notClosed();
return transaction.execute(new AnswerOperation() {
public void execute() throws TuplesException {
returnObject(answer.getObject(column));
@@ -65,6 +90,7 @@
}
public Object getObject(final String columnName) throws TuplesException {
+ notClosed();
return transaction.execute(new AnswerOperation() {
public void execute() throws TuplesException {
returnObject(answer.getObject(columnName));
@@ -73,6 +99,7 @@
}
public void beforeFirst() throws TuplesException {
+ notClosed();
transaction.execute(new AnswerOperation() {
public void execute() throws TuplesException {
answer.beforeFirst();
@@ -81,19 +108,35 @@
}
public void close() throws TuplesException {
- transaction.execute(new AnswerOperation() {
- public void execute() throws TuplesException {
- answer.close();
- try {
- transaction.dereference();
- } catch (MulgaraTransactionException em) {
- throw new TuplesException("Error dereferencing transaction", em);
+ report("Closing Answer");
+ if (closing) {
+ report("Deferring close to enclosing call");
+ return;
+ }
+ try {
+ notClosed();
+ closing = true;
+ transaction.execute(new AnswerOperation() {
+ public void execute() throws TuplesException {
+ answer.close();
+ try {
+ transaction.dereference();
+ } catch (MulgaraTransactionException em) {
+ throw new TuplesException("Error dereferencing transaction", em);
+ }
}
- }
- });
+ });
+ } finally {
+ // !!FIXME: Note - We will need to add checks for null to all operations.
+ closing = false;
+ transaction = null;
+ answer = null; // Note this permits the gc of the answer.
+ report("Closed Answer");
+ }
}
public int getColumnIndex(final Variable column) throws TuplesException {
+ notClosed();
return transaction.execute(new AnswerOperation() {
public void execute() throws TuplesException {
returnInt(answer.getColumnIndex(column));
@@ -103,29 +146,32 @@
public int getNumberOfVariables() {
try {
+ notClosed();
return transaction.execute(new AnswerOperation() {
public void execute() {
returnInt(answer.getNumberOfVariables());
}
}).getInt();
} catch (TuplesException et) {
- throw new IllegalStateException("Doesn't throw TuplesException", et);
+ throw new IllegalStateException(et.getMessage(), et);
}
}
public Variable[] getVariables() {
try {
+ notClosed();
return (Variable[])(transaction.execute(new AnswerOperation() {
public void execute() {
returnObject(answer.getVariables());
}
}).getObject());
} catch (TuplesException et) {
- throw new IllegalStateException("Doesn't throw TuplesException", et);
+ throw new IllegalStateException(et.getMessage(), et);
}
}
public boolean isUnconstrained() throws TuplesException {
+ notClosed();
return transaction.execute(new AnswerOperation() {
public void execute() throws TuplesException {
returnBoolean(answer.isUnconstrained());
@@ -134,6 +180,7 @@
}
public long getRowCount() throws TuplesException {
+ notClosed();
return transaction.execute(new AnswerOperation() {
public void execute() throws TuplesException {
returnLong(answer.getRowCount());
@@ -142,6 +189,7 @@
}
public long getRowUpperBound() throws TuplesException {
+ notClosed();
return transaction.execute(new AnswerOperation() {
public void execute() throws TuplesException {
returnLong(answer.getRowUpperBound());
@@ -150,6 +198,7 @@
}
public int getRowCardinality() throws TuplesException {
+ notClosed();
return transaction.execute(new AnswerOperation() {
public void execute() throws TuplesException {
returnInt(answer.getRowCardinality());
@@ -158,6 +207,7 @@
}
public boolean next() throws TuplesException {
+ notClosed();
return transaction.execute(new AnswerOperation() {
public void execute() throws TuplesException {
returnBoolean(answer.next());
@@ -174,6 +224,41 @@
return c;
} catch (CloneNotSupportedException ec) {
throw new IllegalStateException("Clone failed on Cloneable");
+ } catch (MulgaraTransactionException em) {
+ throw new IllegalStateException("Failed to associate with transaction", em);
}
}
+
+ private void report(String desc) {
+ if (logger.isInfoEnabled()) {
+ logger.info(desc + ": " + System.identityHashCode(this) + ", xa=" + System.identityHashCode(transaction));
+ }
+ }
+
+ private void warnReport(String desc) {
+ logger.warn(desc + ": " + System.identityHashCode(this) + ", xa=" + System.identityHashCode(transaction));
+ }
+
+ public void finalize() {
+ report("GC-finalizing");
+ if (transaction != null) {
+ logger.warn("TransactionalAnswer not closed");
+ }
+ }
+
+
+ void sessionClose() throws TuplesException {
+ if (answer != null) {
+ report("Session forced close");
+ close();
+ }
+ }
+
+ private void notClosed() throws TuplesException {
+ if (transaction == null) {
+ throw new TuplesException("TransactionalAnswer closed");
+ } else if (answer == null) {
+ throw new TuplesException("TransactionAnswer not closed, but Answer null");
+ }
+ }
}
Modified: trunk/src/jar/resolver-filesystem/java/org/mulgara/resolver/filesystem/FileSystemResolver.java
===================================================================
--- trunk/src/jar/resolver-filesystem/java/org/mulgara/resolver/filesystem/FileSystemResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-filesystem/java/org/mulgara/resolver/filesystem/FileSystemResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -474,4 +474,6 @@
throw new ResolverException("Invalid URI", eu);
}
}
+
+ public void abort() {}
}
Modified: trunk/src/jar/resolver-gis/java/org/mulgara/resolver/gis/ReadOnlyGISResolver.java
===================================================================
--- trunk/src/jar/resolver-gis/java/org/mulgara/resolver/gis/ReadOnlyGISResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-gis/java/org/mulgara/resolver/gis/ReadOnlyGISResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -222,4 +222,9 @@
*/
return resolver.resolve(constraint);
}
+
+ public void abort() {
+ resolver.abort();
+ }
+
}
Modified: trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneResolver.java
===================================================================
--- trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -347,4 +347,6 @@
private FullTextStringIndex openFullTextStringIndex(long model) throws FullTextStringIndexException {
return new FullTextStringIndex(new File(directory, Long.toString(model)).toString(), "gn"+model );
}
+
+ public void abort() {}
}
Modified: trunk/src/jar/resolver-memory/java/org/mulgara/resolver/memory/MemoryResolver.java
===================================================================
--- trunk/src/jar/resolver-memory/java/org/mulgara/resolver/memory/MemoryResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-memory/java/org/mulgara/resolver/memory/MemoryResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -49,6 +49,7 @@
import org.mulgara.store.tuples.AbstractTuples;
import org.mulgara.store.tuples.Tuples;
import org.mulgara.store.xa.XAResolverSession;
+import org.mulgara.store.xa.SimpleXAResourceException;
/**
* Resolves constraints in models stored on the Java heap.
@@ -380,4 +381,18 @@
return buffer.toString();
}
+
+ public void abort() {
+ if (xaResolverSession != null) {
+ try {
+ try {
+ xaResolverSession.rollback();
+ } finally {
+ xaResolverSession.release();
+ }
+ } catch (SimpleXAResourceException es) {
+ throw new IllegalStateException("Error aborting resolver session", es);
+ }
+ }
+ }
}
Modified: trunk/src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype/NodeTypeResolver.java
===================================================================
--- trunk/src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype/NodeTypeResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype/NodeTypeResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -371,4 +371,5 @@
// no-op
}
+ public void abort() {}
}
Modified: trunk/src/jar/resolver-prefix/java/org/mulgara/resolver/prefix/PrefixResolver.java
===================================================================
--- trunk/src/jar/resolver-prefix/java/org/mulgara/resolver/prefix/PrefixResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-prefix/java/org/mulgara/resolver/prefix/PrefixResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -336,4 +336,5 @@
// no-op
}
+ public void abort() {}
}
Modified: trunk/src/jar/resolver-relational/java/org/mulgara/resolver/relational/RelationalResolver.java
===================================================================
--- trunk/src/jar/resolver-relational/java/org/mulgara/resolver/relational/RelationalResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-relational/java/org/mulgara/resolver/relational/RelationalResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -338,4 +338,9 @@
throw new ResolverException("Invalid URI", eu);
}
}
+
+ public void abort() {
+ // We need to clear the JDBC connections here, but we don't have a handle on
+ // the Resolutions.
+ }
}
Modified: trunk/src/jar/resolver-spi/java/org/mulgara/content/ContentResolver.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/content/ContentResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/content/ContentResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -305,6 +305,11 @@
throw new QueryException("Unable to parse " + content.getURI());
}
+ public void abort() {
+ // I don't believe there is anything to do here. It is possible that we may
+ // need to close file handles or clear caches.
+ }
+
//
// SPI methods
//
Added: trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/EnlistableResource.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/EnlistableResource.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/EnlistableResource.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -0,0 +1,58 @@
+/*
+ * 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.rosenlaw.com/OSL3.0.htm
+ *
+ * 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.
+ *
+ * This file is an original work developed by Netymon Pty Ltd
+ * (http://www.netymon.com, mailto:mail at netymon.com). Portions
+ * created
+ * by Netymon Pty Ltd are Copyright (c) 2006 Netymon Pty Ltd.
+ * All Rights Reserved.
+ */
+
+package org.mulgara.resolver.spi;
+
+// Java 2 standard packages
+import javax.transaction.xa.XAResource;
+
+/**
+ * A resource that can participate within a JTA transaction.
+ *
+ * @created 2006-11-14
+ * @author <a href="mailto:andrae at netymon.com">Andrae Muys</a>
+ * @maintenanceAuthor $Author: andrae $
+ * @company <a href="mailto:mail at netymon.com">Netymon Pty Ltd</a>
+ * @copyright ©2006 <a href="http://www.netymon.com/">Netymon Pty Ltd</a>
+ * @licence Open Software License v3.0
+ */
+
+public interface EnlistableResource
+{
+ /**
+ * Expose a callback object for enlistment by a transaction manager.
+ *
+ * Note: Resources that do not wish to participate in the transaction
+ * should return a new DummyXAResource instead.
+ *
+ * @return an {@link XAResource} that can be used by a transaction manager to
+ * coordinate this resolver's participation in a distributed transaction
+ * @see javax.resource.spi.ManagedConnection#getXAResource
+ */
+ public XAResource getXAResource();
+
+ /**
+ * Abort current transaction; release all resources.
+ *
+ * This method is called in the event of a catastrophic transaction control
+ * failure that has rendered it impossible to terminate the transaction
+ * normally - even as a rollback. The resource should treat this as a
+ * rollback operation, abort all updates, and release all resources.
+ */
+ public void abort();
+}
Modified: trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/LocalSession.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/LocalSession.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/LocalSession.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -56,55 +56,5 @@
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
public interface LocalSession extends Session {
-
- /**
- * Start's or resumes a transaction for an operation.
- *
- * Using start/finish TransactionalOperation ensures properly matched pairs of
- * begin/end and suspend/resume.
- *
- */
- public void startTransactionalOperation(boolean needsWrite)
- throws QueryException;
-
- /**
- * Mark the current transaction for rollback due to an exception.
- *
- * @param throwable the exception which caused the rollback
- */
- public void rollbackTransactionalBlock(Throwable throwable)
- throws QueryException;
-
- /**
- * Ends's or suspends a transaction for an operation.
- *
- * Using start/finish TransactionalOperation ensures properly matched pairs of
- * begin/end and suspend/resume.
- *
- */
- public void finishTransactionalOperation(String errorString)
- throws QueryException;
-
- /**
- * Resumes the previously suspended transaction from the current session.
- *
- * @throws QueryException Must be called outside the try/catch(Throwable) block
- * protecting the transaction.
- */
- public void resumeTransactionalBlock() throws QueryException;
-
- /**
- * Suspends current transaction, storing it in session for latter resumption.
- *
- * @throws Throwable Must be called inside the try/catch(Throwable) block
- * protecting the transaction.
- */
- public void suspendTransactionalBlock() throws Throwable;
-
- /**
- * Returns the current Resolver Session.
- *
- * @return the current resolver session.
- */
public ResolverSession getResolverSession();
}
Modified: trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/Resolver.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/Resolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/Resolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -52,7 +52,7 @@
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
-public interface Resolver
+public interface Resolver extends EnlistableResource
{
/**
* Create a model of a specified type.
@@ -75,18 +75,6 @@
public void createModel(long model, URI modelType) throws ResolverException, LocalizeException;
/**
- * Expose a callback object for enlistment by a transaction manager.
- *
- * Note: Only the primary store can currently be transactional, so this method
- * is best ignored for now. return a new DummyXAResource instead.
- *
- * @return an {@link XAResource} that can be used by a transaction manager to
- * coordinate this resolver's participation in a distributed transaction
- * @see javax.resource.spi.ManagedConnection#getXAResource
- */
- public XAResource getXAResource();
-
- /**
* Insert or delete RDF statements in an existing model.
*
* @param model the local node identifying an existing model
Modified: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -56,6 +56,7 @@
import org.mulgara.store.tuples.Tuples;
import org.mulgara.store.tuples.TuplesOperations;
import org.mulgara.store.xa.SimpleXAResource;
+import org.mulgara.store.xa.SimpleXAResourceException;
import org.mulgara.store.xa.XAResolverSession;
import org.mulgara.store.xa.XAStatementStore;
@@ -525,4 +526,25 @@
constraintElement.getClass() + ")");
}
}
+
+
+ public void abort() {
+ try {
+ try {
+ statementStore.rollback();
+ } finally {
+ try {
+ xaResolverSession.rollback();
+ } finally {
+ try {
+ statementStore.release();
+ } finally {
+ xaResolverSession.release();
+ }
+ }
+ }
+ } catch (SimpleXAResourceException es) {
+ throw new IllegalStateException("Failed to Abort store", es);
+ }
+ }
}
Modified: trunk/src/jar/resolver-test/java/org/mulgara/resolver/test/TestResolver.java
===================================================================
--- trunk/src/jar/resolver-test/java/org/mulgara/resolver/test/TestResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-test/java/org/mulgara/resolver/test/TestResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -137,4 +137,6 @@
throw new QueryException("Failed to resolve constraint", et);
}
}
+
+ public void abort() {}
}
Modified: trunk/src/jar/resolver-url/java/org/mulgara/resolver/url/URLResolver.java
===================================================================
--- trunk/src/jar/resolver-url/java/org/mulgara/resolver/url/URLResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-url/java/org/mulgara/resolver/url/URLResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -363,4 +363,6 @@
throw new QueryException("Couldn't read URL " + modelURIReference, e);
}
}
+
+ public void abort() {}
}
Modified: trunk/src/jar/resolver-view/java/org/mulgara/resolver/view/ViewResolver.java
===================================================================
--- trunk/src/jar/resolver-view/java/org/mulgara/resolver/view/ViewResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-view/java/org/mulgara/resolver/view/ViewResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -395,4 +395,6 @@
throw new ResolverException("Invalid URI", eu);
}
}
+
+ public void abort() {}
}
Modified: trunk/src/jar/resolver-xsd/java/org/mulgara/resolver/xsd/XSDResolver.java
===================================================================
--- trunk/src/jar/resolver-xsd/java/org/mulgara/resolver/xsd/XSDResolver.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/resolver-xsd/java/org/mulgara/resolver/xsd/XSDResolver.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -452,4 +452,6 @@
throw new Error("Unsupported constraint element: " + constraintElement);
}
}
+
+ public void abort() {}
}
Modified: trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/BlankNodeWrapperAnswer.java
===================================================================
--- trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/BlankNodeWrapperAnswer.java 2006-12-13 12:29:00 UTC (rev 156)
+++ trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/BlankNodeWrapperAnswer.java 2007-01-03 21:32:43 UTC (rev 157)
@@ -69,7 +69,7 @@
/**
* The wrapped instance.
*/
- protected final Answer answer;
+ protected Answer answer;
/**
* The blank node map.
@@ -93,6 +93,7 @@
public Object clone() {
try {
BlankNodeWrapperAnswer cloned = (BlankNodeWrapperAnswer) super.clone();
+ cloned.answer = (Answer)this.answer.clone();
return cloned;
}
catch (CloneNotSupportedException e) {
More information about the Mulgara-svn
mailing list