[Mulgara-svn] r113 - in trunk/src/jar: resolver/java/org/mulgara/resolver resolver-spi/java/org/mulgara/resolver/spi resolver-spi/java/org/mulgara/resolver/view
andrae at mulgara.org
andrae at mulgara.org
Thu Oct 26 13:56:44 UTC 2006
Author: andrae
Date: 2006-10-26 08:56:44 -0500 (Thu, 26 Oct 2006)
New Revision: 113
Added:
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionException.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
trunk/src/jar/resolver/java/org/mulgara/resolver/TransactionalAnswer.java
Modified:
trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/LocalSession.java
trunk/src/jar/resolver-spi/java/org/mulgara/resolver/view/SessionView.java
trunk/src/jar/resolver-spi/java/org/mulgara/resolver/view/ViewMarker.java
trunk/src/jar/resolver/java/org/mulgara/resolver/AnswerOperation.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/LocalQuery.java
trunk/src/jar/resolver/java/org/mulgara/resolver/ModifyModelOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/OperationContext.java
trunk/src/jar/resolver/java/org/mulgara/resolver/QueryOperation.java
Log:
The only methods left on DatabaseSession that are not directly involved in
implementing the Session interface are
1) Transaction Methods - which will be replaced by the new MulgaraTransaction*
classes.
2) clearcache and fineResolverFactory - The former will be migrated to
OperationContextXAResource; the latter will be merged into
DatabaseOperationContext.
This commit also imports the MulgaraTransaction* classes and support. This code
has been fixed from the xafix-design to the extent required to allow it to
compile. It has also had various lines commented out to isolate it from the
existing code - permitting the existing code to continue to run unaffected.
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/AnswerOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/AnswerOperation.java 2006-10-25 22:35:58 UTC (rev 112)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/AnswerOperation.java 2006-10-26 13:56:44 UTC (rev 113)
@@ -17,6 +17,8 @@
package org.mulgara.resolver;
+import org.mulgara.query.TuplesException;
+
public abstract class AnswerOperation {
// Should use enum here.
public static final int OBJECT = 1;
@@ -31,7 +33,7 @@
protected long longint;
protected boolean bool;
- public abstract void execute();
+ public abstract void execute() throws TuplesException;
protected void returnObject(Object object) {
returnType = OBJECT;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java 2006-10-25 22:35:58 UTC (rev 112)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java 2006-10-26 13:56:44 UTC (rev 113)
@@ -63,6 +63,8 @@
import org.mulgara.resolver.spi.ResolverFactoryException;
import org.mulgara.resolver.spi.ResolverSession;
import org.mulgara.resolver.spi.SecurityAdapter;
+import org.mulgara.resolver.spi.Statements;
+import org.mulgara.resolver.spi.SymbolicTransformation;
import org.mulgara.resolver.spi.SymbolicTransformationContext;
import org.mulgara.resolver.spi.SystemResolver;
import org.mulgara.resolver.view.ViewMarker;
@@ -93,8 +95,12 @@
* This is named after the class.
*/
private static final Logger logger =
- Logger.getLogger("DatabaseOperationContext.class,getName()");
+ Logger.getLogger(DatabaseOperationContext.class.getName());
+ /** Logger for {@link SymbolicTransformation} plugins. */
+ private static final Logger symbolicLogger =
+ Logger.getLogger(DatabaseOperationContext.class.getName() + "#symbolic");
+
/**
* The models from external resolvers which have been cached as temporary
* models.
@@ -134,6 +140,8 @@
private final ResolverFactory temporaryResolverFactory;
private final TransactionManager transactionManager;
private final Set outstandingAnswers;
+ /** Symbolic transformations this instance should apply. */
+ private final List symbolicTransformationList;
//
// Constructor
@@ -154,7 +162,8 @@
URI temporaryModelTypeURI,
ResolverFactory temporaryResolverFactory,
TransactionManager transactionManager,
- Set outstandingAnswers)
+ Set outstandingAnswers,
+ List symbolicTransformationList)
{
assert cachedModelSet != null;
assert cachedResolverFactorySet != null;
@@ -185,6 +194,7 @@
// Note this is only temporary - we will be eliminating outstandingAnswers
// before the end of the transaction fix.
this.outstandingAnswers = outstandingAnswers;
+ this.symbolicTransformationList = symbolicTransformationList;
}
//
@@ -631,7 +641,10 @@
*
* This method must be called within a transactional context.
*
- * @deprecated Will be made package-scope as soon as the View kludge is resolved.
+ * Will be made package-scope as soon as the View kludge is resolved.
+ *
+ * Deprecation warning removed to assist development.
+ *
* @param constraint a localized constraint
* @return the tuples satisfying the <var>constraint</var>
* @throws IllegalArgumentException if <var>constraint</var> is
@@ -788,7 +801,7 @@
Answer result = null;
try {
- result = DatabaseSession.doQuery(databaseSession, systemResolver, query);
+ result = doQuery(systemResolver, query);
} catch (Throwable th) {
try {
logger.warn("Inner Query failed", th);
@@ -831,7 +844,7 @@
} else {
outstandingAnswers.remove(answer);
if (databaseSession.autoCommit && outstandingAnswers.isEmpty()) {
- if (databaseSession.transaction != null) {
+ if (databaseSession.getTransaction() != null) {
databaseSession.resumeTransactionalBlock();
}
databaseSession.endTransactionalBlock("Could not commit query");
@@ -855,7 +868,7 @@
Tuples result = null;
try {
LocalQuery lq = (LocalQuery)localQuery.clone();
- DatabaseSession.transform(databaseSession, lq);
+ transform(lq);
result = lq.resolve();
lq.close();
} catch (Throwable th) {
@@ -882,4 +895,93 @@
throw new QueryException("Failed to suspend Transaction");
}
}
+
+ protected void doModify(SystemResolver systemResolver, URI modelURI,
+ Statements statements, boolean insert) throws Throwable {
+ long model = systemResolver.localize(new URIReferenceImpl(modelURI));
+ model = getCanonicalModel(model);
+
+ // Make sure security adapters are satisfied
+ for (Iterator i = securityAdapterList.iterator(); i.hasNext(); ) {
+ SecurityAdapter securityAdapter = (SecurityAdapter) i.next();
+
+ // Lie to the user
+ if (!securityAdapter.canSeeModel(model, systemResolver)) {
+ throw new QueryException("No such model " + modelURI);
+ }
+
+ // Tell the truth to the user
+ if (!securityAdapter.canModifyModel(model, systemResolver)) {
+ throw new QueryException("You aren't allowed to modify " + modelURI);
+ }
+ }
+
+ // Obtain a resolver for the destination model type
+ Resolver resolver = obtainResolver(findModelResolverFactory(model), systemResolver);
+ assert resolver != null;
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Modifying " + modelURI + " using " + resolver);
+ }
+
+ resolver.modifyModel(model, statements, insert);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Modified " + modelURI);
+ }
+ }
+
+ public Answer doQuery(SystemResolver systemResolver, Query query) throws Exception
+ {
+ Answer result;
+
+ LocalQuery localQuery = new LocalQuery(query, systemResolver, this);
+
+ transform(localQuery);
+
+ // Complete the numerical phase of resolution
+ Tuples tuples = localQuery.resolve();
+ result = new SubqueryAnswer(this, systemResolver, tuples, query.getVariableList());
+ tuples.close();
+ localQuery.close();
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Answer rows = " + result.getRowCount());
+ }
+ return result;
+ }
+
+ /**
+ *
+ * Perform in-place transformation of localQuery.
+ * Note: we really want to convert this to a functional form eventually.
+ */
+ void transform(LocalQuery localQuery) throws Exception {
+ // Start with the symbolic phase of resolution
+ LocalQuery.MutableLocalQueryImpl mutableLocalQueryImpl =
+ localQuery.new MutableLocalQueryImpl();
+ if (symbolicLogger.isDebugEnabled()) {
+ symbolicLogger.debug("Before transformation: " + mutableLocalQueryImpl);
+ }
+ Iterator i = symbolicTransformationList.iterator();
+ while (i.hasNext()) {
+ SymbolicTransformation symbolicTransformation =
+ (SymbolicTransformation) i.next();
+ assert symbolicTransformation != null;
+ symbolicTransformation.transform(this, mutableLocalQueryImpl);
+ if (mutableLocalQueryImpl.isModified()) {
+ // When a transformation succeeds, we rewind and start from the
+ // beginning of the symbolicTransformationList again
+ if (symbolicLogger.isDebugEnabled()) {
+ symbolicLogger.debug("Symbolic transformation: " +
+ mutableLocalQueryImpl);
+ }
+ mutableLocalQueryImpl.close();
+ mutableLocalQueryImpl = localQuery.new MutableLocalQueryImpl();
+ i = symbolicTransformationList.iterator();
+ }
+ }
+ mutableLocalQueryImpl.close();
+ }
+
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java 2006-10-25 22:35:58 UTC (rev 112)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java 2006-10-26 13:56:44 UTC (rev 113)
@@ -86,10 +86,6 @@
private static final Logger logger =
Logger.getLogger(DatabaseSession.class.getName());
- /** Logger for {@link SymbolicTransformation} plugins. */
- private static final Logger symbolicLogger =
- Logger.getLogger(DatabaseSession.class.getName() + "#symbolic");
-
private static DatabaseSession writeSession = null;
private boolean writing;
@@ -161,7 +157,7 @@
private final TransactionManager transactionManager;
/** Session transaction */
- Transaction transaction;
+ private Transaction transaction;
/** The name of the rule loader to use */
private String ruleLoaderClassName;
@@ -337,7 +333,8 @@
temporaryModelTypeURI,
temporaryResolverFactory,
transactionManager,
- outstandingAnswers
+ outstandingAnswers,
+ symbolicTransformationList
);
if (logger.isDebugEnabled()) {
@@ -352,6 +349,36 @@
}
}
+
+ /**
+ * Non-rule version of the constructor. Accepts all parameters except ruleLoaderClassName.
+ */
+ DatabaseSession(TransactionManager transactionManager,
+ List securityAdapterList,
+ List symbolicTransformationList,
+ ResolverSessionFactory resolverSessionFactory,
+ SystemResolverFactory systemResolverFactory,
+ ResolverFactory temporaryResolverFactory,
+ List resolverFactoryList,
+ Map externalResolverFactoryMap,
+ Map internalResolverFactoryMap,
+ DatabaseMetadata metadata,
+ ContentHandlerManager contentHandlers,
+ Set cachedResolverFactorySet,
+ URI temporaryModelTypeURI) throws ResolverFactoryException {
+ this(transactionManager, securityAdapterList, symbolicTransformationList, resolverSessionFactory,
+ systemResolverFactory, temporaryResolverFactory, resolverFactoryList, externalResolverFactoryMap,
+ internalResolverFactoryMap, metadata, contentHandlers, cachedResolverFactorySet,
+ temporaryModelTypeURI, "");
+ }
+
+ //
+ // Internal methods required for database initialisation.
+ //
+
+ /**
+ * Used by Database *only* to bootstrap the system model on DB startup.
+ */
long bootstrapSystemModel(DatabaseMetadataImpl metadata) throws
QueryException {
logger.info("Bootstrapping System Model");
@@ -416,34 +443,7 @@
}
}
-
/**
- * Non-rule version of the constructor. Accepts all parameters except ruleLoaderClassName.
- */
- DatabaseSession(TransactionManager transactionManager,
- List securityAdapterList,
- List symbolicTransformationList,
- ResolverSessionFactory resolverSessionFactory,
- SystemResolverFactory systemResolverFactory,
- ResolverFactory temporaryResolverFactory,
- List resolverFactoryList,
- Map externalResolverFactoryMap,
- Map internalResolverFactoryMap,
- DatabaseMetadata metadata,
- ContentHandlerManager contentHandlers,
- Set cachedResolverFactorySet,
- URI temporaryModelTypeURI) throws ResolverFactoryException {
- this(transactionManager, securityAdapterList, symbolicTransformationList, resolverSessionFactory,
- systemResolverFactory, temporaryResolverFactory, resolverFactoryList, externalResolverFactoryMap,
- internalResolverFactoryMap, metadata, contentHandlers, cachedResolverFactorySet,
- temporaryModelTypeURI, "");
- }
-
- public ResolverSession getResolverSession() {
- return systemResolver;
- }
-
- /**
* Preallocate a local node number for an RDF {@link Node}.
*
* This method is used only by {@link DatabaseResolverFactoryInitializer}
@@ -465,6 +465,22 @@
// Methods implementing Session
//
+ public void insert(URI modelURI, Set statements) throws QueryException {
+ modify(modelURI, statements, ASSERT_STATEMENTS);
+ }
+
+ public void insert(URI modelURI, Query query) throws QueryException {
+ modify(modelURI, query, ASSERT_STATEMENTS);
+ }
+
+ public void delete(URI modelURI, Set statements) throws QueryException {
+ modify(modelURI, statements, DENY_STATEMENTS);
+ }
+
+ public void delete(URI modelURI, Query query) throws QueryException {
+ modify(modelURI, query, DENY_STATEMENTS);
+ }
+
/**
* Backup all the data on the specified server. The database is not changed by
* this method.
@@ -485,67 +501,67 @@
* @param outputStream The stream to receive the contents
* @throws QueryException if the backup cannot be completed.
*/
- public void backup(URI sourceURI,
- OutputStream outputStream) throws QueryException {
+ public void backup(URI sourceURI, OutputStream outputStream) throws QueryException {
this.backup(outputStream, sourceURI, null);
}
/**
- * Backup all the data on the specified server to a URI or an output stream.
- * The database is not changed by this method.
+ * Restore all the data on the specified server. If the database is not
+ * currently empty then the database will contain the union of its current
+ * content and the content of the backup file when this method returns.
*
- * If an outputstream is supplied then the destinationURI is ignored.
+ * @param serverURI The URI of the server to restore.
+ * @param sourceURI The URI of the backup file to restore from.
+ * @throws QueryException if the restore cannot be completed.
+ */
+ public void restore(URI serverURI, URI sourceURI) throws QueryException {
+ this.restore(null, serverURI, sourceURI);
+ }
+
+ /**
+ * Restore all the data on the specified server. If the database is not
+ * currently empty then the database will contain the union of its current
+ * content and the content of the backup file when this method returns.
*
- * @param outputStream Optional output stream to receive the contents
- * @param serverURI The URI of the server to backup.
- * @param destinationURI Option URI of the file to backup into.
- * @throws QueryException if the backup cannot be completed.
+ * @param inputStream a client supplied inputStream to obtain the restore
+ * content from. If null assume the sourceURI has been supplied.
+ * @param serverURI The URI of the server to restore.
+ * @param sourceURI The URI of the backup file to restore from.
+ * @throws QueryException if the restore cannot be completed.
*/
- private synchronized void backup(OutputStream outputStream,
- URI serverURI,
- URI destinationURI) throws QueryException {
- execute(
- new BackupOperation(outputStream, serverURI, destinationURI),
- "Unable to backup to " + destinationURI
- );
+ public void restore(InputStream inputStream, URI serverURI,
+ URI sourceURI) throws QueryException {
+ execute(new RestoreOperation(inputStream, serverURI, sourceURI),
+ "Unable to restore from " + sourceURI);
}
- 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();
- }
+ public Answer query(Query query) throws QueryException {
+ if (logger.isInfoEnabled()) {
+ logger.info("QUERY: " + query);
}
+
+ // Evaluate the query
+ QueryOperation queryOperation = new QueryOperation(query, this);
+ executeQuery(queryOperation);
+ return queryOperation.getAnswer();
}
- public void commit() throws QueryException {
- logger.info("Committing transaction");
- if (!autoCommit) {
- synchronized (DatabaseSession.class) {
- setAutoCommit(true);
- setAutoCommit(false);
+ public List query(List queryList) throws QueryException {
+
+ if (logger.isInfoEnabled()) {
+ StringBuffer log = new StringBuffer("QUERYING LIST: ");
+ for (int i = 0; i < queryList.size(); i++) {
+ log.append(queryList.get(i));
}
+ logger.info(log.toString());
}
+
+ QueryOperation queryOperation = new QueryOperation(queryList, this);
+ executeQuery(queryOperation);
+ return queryOperation.getAnswerList();
}
+
public void createModel(URI modelURI, URI modelTypeURI) throws QueryException {
if (logger.isInfoEnabled()) {
logger.info("Creating Model " + modelURI + " with type " + modelTypeURI);
@@ -556,231 +572,84 @@
modelTypeURI);
}
- public void delete(URI modelURI, Set statements) throws QueryException {
- modify(modelURI, statements, DENY_STATEMENTS);
- }
-
- public void delete(URI modelURI, Query query) throws QueryException {
- modify(modelURI, query, DENY_STATEMENTS);
- }
-
- public void insert(URI modelURI, Set statements) throws QueryException {
- modify(modelURI, statements, ASSERT_STATEMENTS);
- }
-
- public void insert(URI modelURI, Query query) throws QueryException {
- modify(modelURI, query, ASSERT_STATEMENTS);
- }
-
- protected void modify(URI modelURI, Set statements, boolean insert)
- throws QueryException
- {
+ public void removeModel(URI modelURI) throws QueryException {
if (logger.isInfoEnabled()) {
- logger.info("Inserting statements into " + modelURI);
+ logger.info("REMOVE MODEL: " + modelURI);
}
- if (logger.isDebugEnabled()) {
- logger.debug("Inserting statements: " + statements);
+ // Validate "modelURI" parameter
+ if (modelURI == null) {
+ throw new IllegalArgumentException("Null \"modelURI\" parameter");
}
- execute(new ModifyModelOperation(modelURI, statements, insert),
- "Could not commit insert");
+ execute(new RemoveModelOperation(modelURI), "Unable to remove " + modelURI);
}
- private void modify(URI modelURI, Query query,
- boolean insert) throws QueryException {
- if (logger.isInfoEnabled()) {
- logger.info("INSERT QUERY: " + query + " into " + modelURI);
- }
+ public boolean modelExists(URI modelURI) throws QueryException {
+ ModelExistsOperation operation = new ModelExistsOperation(modelURI);
- execute(new ModifyModelOperation(modelURI, query, insert, this),
- "Unable to modify " + modelURI);
- }
+ execute(operation, "Failed to determine model existence");
- protected void doModify(SystemResolver systemResolver, URI modelURI,
- Statements statements, boolean insert) throws Throwable {
- long model = systemResolver.localize(new URIReferenceImpl(modelURI));
- model = operationContext.getCanonicalModel(model);
-
- // Make sure security adapters are satisfied
- for (Iterator i = securityAdapterList.iterator(); i.hasNext(); ) {
- SecurityAdapter securityAdapter = (SecurityAdapter) i.next();
-
- // Lie to the user
- if (!securityAdapter.canSeeModel(model, systemResolver)) {
- throw new QueryException("No such model " + modelURI);
- }
-
- // Tell the truth to the user
- if (!securityAdapter.canModifyModel(model, systemResolver)) {
- throw new QueryException("You aren't allowed to modify " + modelURI);
- }
- }
-
- // Obtain a resolver for the destination model type
- Resolver resolver = operationContext.obtainResolver(
- operationContext.findModelResolverFactory(model),
- systemResolver
- );
- assert resolver != null;
-
- if (logger.isDebugEnabled()) {
- logger.debug("Modifying " + modelURI + " using " + resolver);
- }
-
- resolver.modifyModel(model, statements, insert);
-
- if (logger.isDebugEnabled()) {
- logger.debug("Modified " + modelURI);
- }
+ return operation.getResult();
}
- public void login(URI securityDomain, String user, char[] password) {
- if (logger.isDebugEnabled()) {
- 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();) {
- ((SecurityAdapter) i.next()).login(user, password);
- }
- }
+ /**
+ * Define the contents of a model.
+ *
+ * @param uri the {@link URI} of the model to be redefined
+ * @param modelExpression the new content for the model
+ * @return RETURNED VALUE TO DO
+ * @throws QueryException if the model can't be modified
+ */
+ public synchronized long setModel(URI uri,
+ ModelExpression modelExpression) throws QueryException {
+ return this.setModel(null, uri, modelExpression);
}
- public Answer query(Query query) throws QueryException {
- if (logger.isInfoEnabled()) {
- logger.info("QUERY: " + query);
- }
-
- // Evaluate the query
- QueryOperation queryOperation = new QueryOperation(query, this);
- executeQuery(queryOperation);
- return queryOperation.getAnswer();
- }
-
- static Answer doQuery(DatabaseSession databaseSession,
- SystemResolver systemResolver,
- Query query) throws Exception
- {
- Answer result;
-
- LocalQuery localQuery =
- new LocalQuery(query, systemResolver, databaseSession.operationContext);
-
- transform(databaseSession, localQuery);
-
- // Complete the numerical phase of resolution
- Tuples tuples = localQuery.resolve();
- result = new SubqueryAnswer(databaseSession.operationContext, systemResolver, tuples,
- query.getVariableList());
- tuples.close();
- localQuery.close();
-
- if (logger.isDebugEnabled()) {
- logger.debug("Answer rows = " + result.getRowCount());
- }
- return result;
- }
-
-
/**
+ * Define the contents of a model via an inputstream
*
- * Perform in-place transformation of localQuery.
- * Note: we really want to convert this to a functional form eventually.
+ * @param inputStream a remote inputstream
+ * @param destinationModelURI the {@link URI} of the model to be redefined
+ * @param modelExpression the new content for the model
+ * @return RETURNED VALUE TO DO
+ * @throws QueryException if the model can't be modified
*/
- static void transform(DatabaseSession databaseSession, LocalQuery localQuery) throws Exception {
- // Start with the symbolic phase of resolution
- LocalQuery.MutableLocalQueryImpl mutableLocalQueryImpl =
- localQuery.new MutableLocalQueryImpl();
- if (symbolicLogger.isDebugEnabled()) {
- symbolicLogger.debug("Before transformation: " + mutableLocalQueryImpl);
+ public synchronized long setModel(InputStream inputStream,
+ URI destinationModelURI,
+ ModelExpression modelExpression) throws QueryException {
+ if (logger.isInfoEnabled()) {
+ logger.info("SET-MODEL " + destinationModelURI + " to " + modelExpression +
+ " from " + inputStream);
}
- Iterator i = databaseSession.symbolicTransformationList.iterator();
- while (i.hasNext()) {
- SymbolicTransformation symbolicTransformation =
- (SymbolicTransformation) i.next();
- assert symbolicTransformation != null;
- symbolicTransformation.transform(databaseSession.operationContext, mutableLocalQueryImpl);
- if (mutableLocalQueryImpl.isModified()) {
- // When a transformation succeeds, we rewind and start from the
- // beginning of the symbolicTransformationList again
- if (symbolicLogger.isDebugEnabled()) {
- symbolicLogger.debug("Symbolic transformation: " +
- mutableLocalQueryImpl);
- }
- mutableLocalQueryImpl.close();
- mutableLocalQueryImpl = localQuery.new MutableLocalQueryImpl();
- i = databaseSession.symbolicTransformationList.iterator();
- }
+ // Validate parameters
+ if (destinationModelURI == null) {
+ throw new IllegalArgumentException("Null 'destinationModelURI' parameter");
}
- mutableLocalQueryImpl.close();
- }
-
- 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 (modelExpression == null) {
+ throw new IllegalArgumentException("Null 'modelExpression' parameter");
}
- // 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);
+ // Convert the model expression into the source model URI
+ if (!(modelExpression instanceof ModelResource)) {
+ throw new QueryException("Unsupported model expression " +
+ modelExpression + " (" + modelExpression.getClass() + ")");
}
+ assert modelExpression instanceof ModelResource;
- 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);
- }
- }
+ URI sourceModelURI = ((ModelResource)modelExpression).getURI();
+ assert sourceModelURI != null;
- public List query(List queryList) throws QueryException {
-
- if (logger.isInfoEnabled()) {
- StringBuffer log = new StringBuffer("QUERYING LIST: ");
- for (int i = 0; i < queryList.size(); i++) {
- log.append(queryList.get(i));
- }
- logger.info(log.toString());
+ // Perform the operation
+ SetModelOperation op = new SetModelOperation(sourceModelURI, destinationModelURI,
+ inputStream, contentHandlers, this);
+ // preExcecute is a rather ugly hack, get rid of it once we support re-entrant transactions.
+ if (op.preExecute()) {
+ execute(op, "Unable to load " + sourceModelURI + " into " + destinationModelURI);
}
- QueryOperation queryOperation = new QueryOperation(queryList, this);
- executeQuery(queryOperation);
- return queryOperation.getAnswerList();
+ return op.getStatementCount();
}
-
/**
* {@inheritDoc}
*/
@@ -809,56 +678,52 @@
}
- public void removeModel(URI modelURI) throws QueryException {
+ public void setAutoCommit(boolean autoCommit) throws QueryException {
if (logger.isInfoEnabled()) {
- logger.info("REMOVE MODEL: " + modelURI);
+ logger.info("setAutoCommit(" + autoCommit + ") called with autoCommit = " + this.autoCommit);
}
- // Validate "modelURI" parameter
- if (modelURI == null) {
- throw new IllegalArgumentException("Null \"modelURI\" parameter");
- }
- execute(new RemoveModelOperation(modelURI), "Unable to remove " + modelURI);
+ 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);
+ }
+ }
}
- public boolean modelExists(URI modelURI) throws QueryException {
- ModelExistsOperation operation = new ModelExistsOperation(modelURI);
-
- execute(operation, "Failed to determine model existence");
-
- return operation.getResult();
+ public void commit() throws QueryException {
+ logger.info("Committing transaction");
+ if (!autoCommit) {
+ synchronized (DatabaseSession.class) {
+ setAutoCommit(true);
+ setAutoCommit(false);
+ }
+ }
}
- /**
- * Restore all the data on the specified server. If the database is not
- * currently empty then the database will contain the union of its current
- * content and the content of the backup file when this method returns.
- *
- * @param serverURI The URI of the server to restore.
- * @param sourceURI The URI of the backup file to restore from.
- * @throws QueryException if the restore cannot be completed.
- */
- public void restore(URI serverURI, URI sourceURI) throws QueryException {
- this.restore(null, serverURI, sourceURI);
- }
-
- /**
- * Restore all the data on the specified server. If the database is not
- * currently empty then the database will contain the union of its current
- * content and the content of the backup file when this method returns.
- *
- * @param inputStream a client supplied inputStream to obtain the restore
- * content from. If null assume the sourceURI has been supplied.
- * @param serverURI The URI of the server to restore.
- * @param sourceURI The URI of the backup file to restore from.
- * @throws QueryException if the restore cannot be completed.
- */
- public void restore(InputStream inputStream, URI serverURI,
- URI sourceURI) throws QueryException {
- execute(new RestoreOperation(inputStream, serverURI, sourceURI),
- "Unable to restore from " + sourceURI);
- }
-
public void rollback() throws QueryException {
logger.info("Rollback transaction");
if (autoCommit) {
@@ -885,102 +750,212 @@
}
}
- public void setAutoCommit(boolean autoCommit) throws QueryException {
- if (logger.isInfoEnabled()) {
- logger.info("setAutoCommit(" + autoCommit + ") called with autoCommit = " + this.autoCommit);
- }
+ public void close() throws QueryException {
+ logger.info("Closing session");
+ if (!autoCommit) {
+ logger.warn("Closing session while holding write-lock");
- if (!this.autoCommit && autoCommit) { // Turning autoCommit on
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 {
- this.autoCommit = true;
- this.inFailedTransaction = false;
- endTransactionalBlock("Extended transaction failed");
+ endTransactionalBlock("Failed to release write-lock in close");
}
- } else if (this.autoCommit && !autoCommit) { // Turning autoCommit off
+ } else {
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");
+ }
+ }
+
+ public boolean isLocal() {
+ return true;
+ }
+
+ public void login(URI securityDomain, String user, char[] password) {
+ if (logger.isDebugEnabled()) {
+ 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();) {
+ ((SecurityAdapter) i.next()).login(user, password);
}
- 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);
+ }
+ }
+
+ //
+ // 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;
}
}
/**
- * Define the contents of a model.
+ * Mark the current transaction for rollback due to an exception.
*
- * @param uri the {@link URI} of the model to be redefined
- * @param modelExpression the new content for the model
- * @return RETURNED VALUE TO DO
- * @throws QueryException if the model can't be modified
+ * This records the exception which caused the rollback in the
+ * {@link #rollbackCause} field.
*/
- public synchronized long setModel(URI uri,
- ModelExpression modelExpression) throws QueryException {
- return this.setModel(null, uri, modelExpression);
+ 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;
}
/**
- * Define the contents of a model via an inputstream
+ * Ends's or suspends a transaction for an operation.
*
- * @param inputStream a remote inputstream
- * @param destinationModelURI the {@link URI} of the model to be redefined
- * @param modelExpression the new content for the model
- * @return RETURNED VALUE TO DO
- * @throws QueryException if the model can't be modified
+ * Using start/finish TransactionalOperation ensures properly matched pairs of
+ * begin/end and suspend/resume.
*/
- public synchronized long setModel(InputStream inputStream,
- URI destinationModelURI,
- ModelExpression modelExpression) throws QueryException {
- if (logger.isInfoEnabled()) {
- logger.info("SET-MODEL " + destinationModelURI + " to " + modelExpression +
- " from " + inputStream);
+ public void finishTransactionalOperation(String errorString) throws
+ QueryException {
+ logger.info("Finishing Transactional Operation");
+ if (logger.isDebugEnabled()) {
+ logger.debug("opState = " + opStates[opState]);
+ logger.debug("autoCommit = " + autoCommit);
}
- // Validate parameters
- if (destinationModelURI == null) {
- throw new IllegalArgumentException("Null 'destinationModelURI' parameter");
+ if (opState == FINISH) {
+ throw new IllegalArgumentException(
+ "Attempt to finish transactional operation during: " + opStates[opState]);
}
- if (modelExpression == null) {
- throw new IllegalArgumentException("Null 'modelExpression' parameter");
+ 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;
+ }
}
+ }
- // Convert the model expression into the source model URI
- if (!(modelExpression instanceof ModelResource)) {
- throw new QueryException("Unsupported model expression " +
- modelExpression + " (" + modelExpression.getClass() + ")");
+ /**
+ * 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");
}
- assert modelExpression instanceof ModelResource;
- URI sourceModelURI = ((ModelResource)modelExpression).getURI();
- assert sourceModelURI != null;
+ try {
+ transactionManager.resume(this.transaction);
+ this.transaction = null;
+ } catch (Exception e) {
+ logger.error("Resume failed", e);
+ throw new QueryException("Failed to resume transaction", e);
+ }
+ }
- // Perform the operation
- SetModelOperation op = new SetModelOperation(sourceModelURI, destinationModelURI,
- inputStream, contentHandlers, this);
- // preExcecute is a rather ugly hack, get rid of it once we support re-entrant transactions.
- if (op.preExecute()) {
- execute(op, "Unable to load " + sourceModelURI + " into " + destinationModelURI);
+ /**
+ * 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)
+ );
+ }
- return op.getStatementCount();
+ 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 methods
+ // Internal Transactional Methods. Not exposed via the interface.
//
/**
@@ -1025,107 +1000,6 @@
}
/**
- * 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
- {
- assert operation != null;
-
- startTransactionalOperation(operation.isWriteOperation());
-
- assert systemResolver != null;
- try {
- operation.execute(operationContext, systemResolver, resolverSessionFactory, metadata);
- } catch (Throwable e) {
- rollbackTransactionalBlock(e);
- } finally {
- finishTransactionalOperation(failureMessage);
- }
- }
-
- /**
- * 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");
- }
- }
-
- 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();
- }
- }
- }
-
- /**
* Mark the end of a transactional block.
*
* This commits the current transaction if {@link #autoCommit} is
@@ -1176,6 +1050,81 @@
}
}
+ 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.
*/
@@ -1297,183 +1246,151 @@
}
}
- /**
- * 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;
+ //
+ // Private accessors intended only for DatabaseOperationContext
+ //
- 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);
- }
+ SystemResolver getSystemResolver() {
+ return systemResolver;
+ }
- rollbackCause = throwable;
+ Transaction getTransaction() {
+ return transaction;
}
+ boolean isWriting() {
+ return writing;
+ }
+
+ boolean ensureTransactionResumed() throws QueryException {
+ if (this.transaction != null) {
+ resumeTransactionalBlock();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
/**
- * Suspends current transaction, storing it in session for latter resumption.
+ * Backup all the data on the specified server to a URI or an output stream.
+ * The database is not changed by this method.
*
- * @throws Throwable Must be called inside the try/catch(Throwable) block
- * protecting the transaction.
+ * If an outputstream is supplied then the destinationURI is ignored.
+ *
+ * @param outputStream Optional output stream to receive the contents
+ * @param serverURI The URI of the server to backup.
+ * @param destinationURI Option URI of the file to backup into.
+ * @throws QueryException if the backup cannot be completed.
*/
- public void suspendTransactionalBlock() throws Throwable {
- logger.info("Suspend Transactional Block");
- if (transaction != null) {
- throw new IllegalStateException(
- "Attempt to suspend unresumed transaction.");
- }
+ private synchronized void backup(OutputStream outputStream,
+ URI serverURI,
+ URI destinationURI) throws QueryException {
+ execute(
+ new BackupOperation(outputStream, serverURI, destinationURI),
+ "Unable to backup to " + destinationURI
+ );
+ }
+
+ //
+ // Internal utility methods.
+ //
+ protected void modify(URI modelURI, Set statements, boolean insert) throws QueryException
+ {
if (logger.isInfoEnabled()) {
- logger.info(
- "Suspend Transactional Block autocommit=" + autoCommit +
- " transaction status=" + StatusFormat.formatStatus(transactionManager)
- );
+ logger.info("Inserting statements into " + modelURI);
}
+ if (logger.isDebugEnabled()) {
+ logger.debug("Inserting statements: " + statements);
+ }
- 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");
+ execute(new ModifyModelOperation(modelURI, statements, insert),
+ "Could not commit insert");
+ }
+
+ private void modify(URI modelURI, Query query, boolean insert) throws QueryException
+ {
+ if (logger.isInfoEnabled()) {
+ logger.info("INSERT QUERY: " + query + " into " + modelURI);
}
- this.transaction = transactionManager.suspend();
+ execute(new ModifyModelOperation(modelURI, query, insert, this),
+ "Unable to modify " + modelURI);
}
/**
- * Resumes the previously suspended transaction from the current session.
+ * Execute an {@link Operation}.
*
- * @throws QueryException Must be called outside the try/catch(Throwable) block
- * protecting the transaction.
+ * @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
*/
- 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");
- }
+ private void execute(Operation operation, String failureMessage)
+ throws QueryException
+ {
+ assert operation != null;
+ startTransactionalOperation(operation.isWriteOperation());
+
+ assert systemResolver != null;
try {
- transactionManager.resume(this.transaction);
- this.transaction = null;
- } catch (Exception e) {
- logger.error("Resume failed", e);
- throw new QueryException("Failed to resume transaction", e);
+ operation.execute(operationContext, systemResolver, resolverSessionFactory, metadata);
+ } catch (Throwable e) {
+ rollbackTransactionalBlock(e);
+ } finally {
+ finishTransactionalOperation(failureMessage);
}
}
/**
- * Start's or resumes a transaction for an operation.
+ * Execute an {@link Operation}.
*
- * Using start/finish TransactionalOperation ensures properly matched pairs of
- * begin/end and suspend/resume.
+ * @param operation the {@link Operation} to execute
+ * @throws QueryException if the <var>operation</var> fails
*/
- 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]);
- }
+ 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(needsWrite);
- logger.info("BEGIN new transaction.");
- opState = BEGIN;
- } else {
+ beginTransactionalBlock(operation.isWriteOperation());
+ }
+ else {
resumeTransactionalBlock();
- logger.info("RESUME old transaction.");
- opState = RESUME;
}
- }
- /**
- * 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);
+ try {
+ operation.execute(operationContext,
+ systemResolver,
+ resolverSessionFactory,
+ metadata);
}
- if (opState == FINISH) {
- throw new IllegalArgumentException(
- "Attempt to finish transactional operation during: " + opStates[opState]);
- }
- if (autoCommit) {
+ catch (Throwable th) {
try {
- endTransactionalBlock(errorString);
+ logger.warn("Query failed", th);
+ rollbackTransactionalBlock(th);
} finally {
- logger.info("FINISH(end) implicit transaction.");
- opState = FINISH;
+ endPreviousQueryTransaction();
+ throw new QueryException("Failed to rollback failed transaction", th);
}
- } 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;
- }
}
- }
- public boolean isLocal() {
- return true;
- }
-
- //
- // 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;
+ try {
+ suspendTransactionalBlock();
+ } catch (Throwable th) {
+ endPreviousQueryTransaction();
+ logger.error("Query should have thrown exception", th);
+ throw new IllegalStateException("Query should have thrown exception");
}
}
-
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/LocalQuery.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/LocalQuery.java 2006-10-25 22:35:58 UTC (rev 112)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/LocalQuery.java 2006-10-26 13:56:44 UTC (rev 113)
@@ -246,7 +246,6 @@
if (logger.isDebugEnabled()) {
logger.debug("Tuples result = " + TuplesOperations.formatTuplesTree(result));
- logger.debug("Raw result " + result);
}
result = projectSelectClause(result);
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/ModifyModelOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/ModifyModelOperation.java 2006-10-25 22:35:58 UTC (rev 112)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/ModifyModelOperation.java 2006-10-26 13:56:44 UTC (rev 113)
@@ -199,8 +199,7 @@
else {
assert query != null;
- Answer answer =
- DatabaseSession.doQuery(databaseSession, systemResolver, query);
+ Answer answer = operationContext.doQuery(systemResolver, query);
Variable[] vars = answer.getVariables();
assert vars.length == 3;
statements = new TuplesWrapperStatements(
Copied: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java (from rev 105, branches/xafix/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java)
===================================================================
--- branches/xafix/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java 2006-10-17 12:10:50 UTC (rev 105)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java 2006-10-26 13:56:44 UTC (rev 113)
@@ -0,0 +1,257 @@
+/*
+ * 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;
+
+// Java 2 enterprise packages
+import javax.transaction.RollbackException;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.xa.XAResource;
+
+// Third party packages
+import org.apache.log4j.Logger;
+
+// Local packages
+import org.mulgara.resolver.spi.DatabaseMetadata;
+import org.mulgara.resolver.spi.Resolver;
+import org.mulgara.resolver.spi.ResolverSessionFactory;
+
+import org.mulgara.query.TuplesException;
+
+/**
+ * Responsible for the javax.transaction.Transaction object.
+ * Responsibilities
+ * Ensuring every begin or resume is followed by either a suspend or an end.
+ * Ensuring every suspend or end is preceeded by either a begin or a resume.
+ * In conjunction with TransactionalAnswer ensuring that
+ * all calls to operations on SubqueryAnswer are preceeded by a successful resume.
+ * all calls to operations on SubqueryAnswer conclude with a suspend as the last call prior to returning to the user.
+ * Collaborates with DatabaseTransactionManager to determine when to end the transaction.
+ *
+ * @created 2006-10-06
+ *
+ * @author <a href="mailto:andrae at netymon.com">Andrae Muys</a>
+ *
+ * @version $Revision: $
+ *
+ * @modified $Date: $
+ *
+ * @maintenanceAuthor $Author: $
+ *
+ * @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>
+ */
+public class MulgaraTransaction {
+ /** Logger. */
+ private static final Logger logger =
+ Logger.getLogger(MulgaraTransaction.class.getName());
+
+ private MulgaraTransactionManager manager;
+ private OperationContext context;
+
+ private Transaction transaction;
+ private Thread currentThread;
+
+ private int inuse;
+ private int using;
+
+ private final int NO_ROLLBACK = 0;
+ private final int IMPLICIT_ROLLBACK = 1;
+ private final int EXPLICIT_ROLLBACK = 2;
+
+ private int rollback;
+ private Throwable rollbackCause;
+
+ public MulgaraTransaction(MulgaraTransactionManager manager, OperationContext context) {
+ 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;
+
+ rollback = NO_ROLLBACK;
+ rollbackCause = null;
+
+// 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());
+ }
+
+ // 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 (inuse == 0) {
+ try {
+ manager.transactionResumed(this);
+ } catch (Throwable th) {
+ logger.warn("Error resuming transaction: ", th);
+ failTransaction();
+ throw new MulgaraTransactionException("Error resuming transaction", th);
+ }
+ }
+
+ 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 {
+
+ 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);
+ }
+ currentThread = null;
+ }
+ }
+
+ // Do I want to check for currentThread here? Do I want a seperate check() method to
+ // cover precondition checks against currentThread?
+ void reference() {
+ using++;
+ }
+
+ void dereference() throws MulgaraTransactionException {
+ using--;
+ if (using < 0) {
+ throw implicitRollback(new MulgaraTransactionException("ERROR: Transaction dereferenced more times than referenced!"));
+ }
+ }
+
+ void execute(Operation operation,
+ ResolverSessionFactory resolverSessionFactory, // FIXME: We shouldn't need this. - only used for backup and restore operations.
+ DatabaseMetadata metadata) throws MulgaraTransactionException {
+ activate();
+ 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);
+ } finally {
+ deactivate();
+ }
+ }
+
+ /** Should rename this 'wrap' */
+ AnswerOperationResult execute(AnswerOperation ao) throws TuplesException {
+// FIXME: activate/deactivate won't work until we have MTMgr operational.
+// activate();
+ try {
+ ao.execute();
+ return ao.getResult();
+ } catch (Throwable th) {
+ throw new TuplesException("Error accessing Answer", th);
+// throw implicitRollback(th);
+ } finally {
+// deactivate();
+ }
+ }
+
+
+ private MulgaraTransactionException implicitRollback(Throwable cause) throws MulgaraTransactionException {
+ rollback = IMPLICIT_ROLLBACK;
+ rollbackCause = cause;
+ failTransaction();
+ return new MulgaraTransactionException("Transaction Rolledback", cause);
+ }
+
+ /**
+ * Note: I think this is the only one that matters.
+ */
+ 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.
+ }
+
+ private void terminateTransaction() throws MulgaraTransactionException {
+ }
+
+ private void failTransaction() throws MulgaraTransactionException {
+ // We need to handle the whole fact this is an error, but the core operation is rollback.
+ try {
+ transaction.rollback();
+ } catch (SystemException es) {
+ throw new MulgaraTransactionException("Failed to Rollback", es);
+ }
+ }
+
+ private void finalizeTransaction() throws MulgaraTransactionException {
+ // We need a whole load of error handling here, but the core operation is commit.
+ try {
+ transaction.commit();
+ } catch (Exception e) {
+ throw new MulgaraTransactionException("Error while trying to commit", e);
+ } finally {
+ manager.transactionComplete(this);
+ }
+ }
+
+ //
+ // 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 {
+ try {
+ XAResource resource = resolver.getXAResource();
+ transaction.enlistResource(resource);
+ } catch (Exception e) {
+ throw new MulgaraTransactionException("Error enlisting resolver", e);
+ }
+ }
+
+ /**
+ * Should only be visible to MulgaraTransactionManager.
+ */
+ protected Transaction getTransaction() {
+ return transaction;
+ }
+}
Added: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionException.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionException.java 2006-10-25 22:35:58 UTC (rev 112)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionException.java 2006-10-26 13:56:44 UTC (rev 113)
@@ -0,0 +1,47 @@
+/*
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.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;
+
+/**
+ * Exception to indicate a failure within the transaction handling.
+ *
+ * @created 2006-10-06
+ *
+ * @author <a href="mailto:andrae at netymon.com">Andrae Muys</a>
+ *
+ * @version $Revision: $
+ *
+ * @modified $Date: $
+ *
+ * @maintenanceAuthor $Author: $
+ *
+ * @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>
+ */
+public class MulgaraTransactionException extends Exception
+{
+ public MulgaraTransactionException(String message) {
+ super(message);
+ }
+
+ public MulgaraTransactionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Copied: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java (from rev 105, branches/xafix/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java)
===================================================================
--- branches/xafix/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java 2006-10-17 12:10:50 UTC (rev 105)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java 2006-10-26 13:56:44 UTC (rev 113)
@@ -0,0 +1,282 @@
+/*
+ * 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;
+
+// Java2 packages
+import java.util.HashMap;
+import java.util.Map;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAResource;
+
+// Third party packages
+import org.apache.log4j.Logger;
+
+// Local packages
+import org.mulgara.server.Session;
+
+/**
+ * Manages transactions within Mulgara.
+ *
+ * see http://mulgara.org/confluence/display/dev/Transaction+Architecture
+ *
+ * Maintains association between Answer's and TransactionContext's.
+ * Manages tracking the ownership of the write-lock.
+ * Maintains the write-queue and any timeout algorithm desired.
+ * Provides new/existing TransactionContext's to DatabaseSession on request.
+ * Note: Returns new context unless Session is currently in a User Demarcated Transaction.
+ *
+ *
+ * @created 2006-10-06
+ *
+ * @author <a href="mailto:andrae at netymon.com">Andrae Muys</a>
+ *
+ * @version $Revision: $
+ *
+ * @modified $Date: $
+ *
+ * @maintenanceAuthor $Author: $
+ *
+ * @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>
+ */
+
+public class MulgaraTransactionManager {
+ /** Logger. */
+ private static final Logger logger =
+ Logger.getLogger(MulgaraTransactionManager.class.getName());
+
+ // Write lock is associated with a session.
+ private Session currentWritingSession;
+ private MulgaraTransaction userTransaction;
+
+ /** Map from session to transaction for all 'write' transactions that have been rolledback. */
+ private Map failedSessions;
+
+ /** Map from thread to associated transaction. */
+ private Map activeTransactions;
+
+ private TransactionManager transactionManager;
+
+ private Object writeLockMutex;
+
+ public MulgaraTransactionManager(TransactionManager transactionManager) {
+ this.currentWritingSession = null;
+ this.userTransaction = null;
+
+ this.failedSessions = new HashMap();
+
+ this.transactionManager = transactionManager;
+ this.writeLockMutex = new Object();
+ }
+
+ /**
+ * Allows DatabaseSession to initiate/obtain a transaction.
+ * <ul>
+ * <li>If the Session holds the write lock, return the current Write-Transaction.</li>
+ * <li>If the Session does not hold the write lock and requests a read-only transaction,
+ * create a new ro-transaction object and return it.</li>
+ * <li>If the Session does not hold the write lock and requests a read-write transaction,
+ * obtain the write-lock, create a new transaction object and return it.</li>
+ * </ul>
+ */
+ public synchronized MulgaraTransaction getTransaction(DatabaseSession session, boolean write) throws MulgaraTransactionException {
+ if (session == currentWritingSession) {
+ return userTransaction;
+ }
+
+ if (write) {
+ obtainWriteLock(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");
+ }
+ }
+
+ private synchronized void obtainWriteLock(Session session)
+ throws MulgaraTransactionException {
+ while (currentWritingSession != null) {
+ try {
+ writeLockMutex.wait();
+ } catch (InterruptedException ei) {
+ throw new MulgaraTransactionException("Interrupted while waiting for write lock", ei);
+ }
+ }
+ currentWritingSession = session;
+ }
+
+ private synchronized void releaseWriteLock() {
+ currentWritingSession = null;
+ userTransaction = null;
+ writeLockMutex.notify();
+ }
+
+
+ public synchronized void commit(Session session) throws MulgaraTransactionException {
+ setAutoCommit(session, true);
+ setAutoCommit(session, false);
+ }
+
+
+ /**
+ * This is an explicit, user-specified rollback.
+ * This
+ * This needs to be distinguished from an implicit rollback triggered by failure.
+ */
+ public synchronized void rollback(Session session) throws MulgaraTransactionException {
+ if (session == currentWritingSession) {
+ try {
+ userTransaction.explicitRollback();
+ finalizeTransaction();
+ } finally {
+ failedSessions.put(currentWritingSession, userTransaction);
+ userTransaction = null;
+ currentWritingSession = null;
+ releaseWriteLock();
+ }
+ } else {
+ // We have a problem - rollback called on session that doesn't have a transaction active.
+ }
+ }
+
+ public synchronized void setAutoCommit(Session 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.containsKey(session)) {
+ if (autoCommit) {
+ // AutoCommit off -> on === branch on current state of transaction.
+ if (session == currentWritingSession) {
+ // Within active transaction - commit and finalise.
+ try {
+ } finally {
+ releaseWriteLock();
+ }
+ } else {
+ // Within failed transaction - cleanup and finalise.
+ failedSessions.remove(session);
+ }
+ } else {
+ // AutoCommit off -> off === no-op. Log info.
+ }
+ } else {
+ if (autoCommit) {
+ // AutoCommit on -> on === no-op. Log info.
+ } else {
+ // AutoCommit on -> off == Start new transaction.
+ obtainWriteLock(session);
+// FIXME: finish DS-OC first.
+// userTransaction = new MulgaraTransaction(this, session.newOperationContext(true));
+ currentWritingSession = session;
+ }
+ }
+ }
+
+ 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 void finalizeTransaction() {
+ throw new IllegalStateException("mmmm I was doing something here. I need to remember what.");
+ }
+
+ //
+ // Transaction livecycle callbacks.
+ //
+
+ public synchronized Transaction transactionStart(MulgaraTransaction transaction)
+ throws MulgaraTransactionException {
+ try {
+ transactionManager.begin();
+ Transaction jtaTrans = transactionManager.getTransaction();
+
+ activeTransactions.put(Thread.currentThread(), transaction);
+
+ return jtaTrans;
+ } catch (Exception e) {
+ throw new MulgaraTransactionException("Transaction Begin Failed", e);
+ }
+ }
+
+ public synchronized void transactionResumed(MulgaraTransaction transaction)
+ 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");
+ }
+
+ try {
+ transactionManager.resume(transaction.getTransaction());
+ activeTransactions.put(Thread.currentThread(), transaction);
+ } catch (Exception e) {
+ throw new MulgaraTransactionException("Resume Failed", e);
+ }
+ }
+
+ public synchronized Transaction transactionSuspended(MulgaraTransaction transaction)
+ throws MulgaraTransactionException {
+ try {
+ if (transaction != activeTransactions.get(Thread.currentThread())) {
+ throw new MulgaraTransactionException(
+ "Attempt to commit transaction from outside thread");
+ }
+
+ return transactionManager.suspend();
+ } catch (Exception e) {
+ throw new MulgaraTransactionException("Suspend failed", e);
+ } finally {
+ activeTransactions.remove(Thread.currentThread());
+ }
+
+ }
+
+ public synchronized void transactionComplete(MulgaraTransaction transaction)
+ throws MulgaraTransactionException {
+ try {
+ transactionManager.commit();
+ if (transaction == userTransaction) {
+ releaseWriteLock();
+ }
+ } catch (Exception e) {
+ throw new MulgaraTransactionException("Commit Failed", e);
+ } finally {
+ activeTransactions.remove(Thread.currentThread());
+ }
+ }
+}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/OperationContext.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/OperationContext.java 2006-10-25 22:35:58 UTC (rev 112)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/OperationContext.java 2006-10-26 13:56:44 UTC (rev 113)
@@ -32,6 +32,8 @@
import java.util.List;
// Local packages
+import org.mulgara.query.Answer;
+import org.mulgara.query.Query;
import org.mulgara.query.QueryException;
import org.mulgara.resolver.spi.GlobalizeException;
import org.mulgara.resolver.spi.Resolver;
@@ -114,4 +116,10 @@
*/
public long getCanonicalModel(long model);
+ /**
+ * Here for the moment while we fix transactions.
+ * 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;
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/QueryOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/QueryOperation.java 2006-10-25 22:35:58 UTC (rev 112)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/QueryOperation.java 2006-10-26 13:56:44 UTC (rev 113)
@@ -153,16 +153,14 @@
if (query != null) {
assert queryList == null;
- answer = DatabaseSession.doQuery(databaseSession, systemResolver, query);
+ answer = operationContext.doQuery(systemResolver, query);
}
else {
assert queryList != null;
answerList = new ArrayList(queryList.size());
for (Iterator i = queryList.iterator(); i.hasNext();) {
- answerList.add(DatabaseSession.doQuery(databaseSession,
- systemResolver,
- (Query) i.next()));
+ answerList.add(operationContext.doQuery(systemResolver, (Query) i.next()));
}
}
}
Copied: trunk/src/jar/resolver/java/org/mulgara/resolver/TransactionalAnswer.java (from rev 98, branches/xafix/src/jar/resolver/java/org/mulgara/resolver/TransactionalAnswer.java)
===================================================================
--- branches/xafix/src/jar/resolver/java/org/mulgara/resolver/TransactionalAnswer.java 2006-10-10 10:50:08 UTC (rev 98)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/TransactionalAnswer.java 2006-10-26 13:56:44 UTC (rev 113)
@@ -0,0 +1,179 @@
+/*
+ * 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.Answer;
+import org.mulgara.query.TuplesException;
+import org.mulgara.query.Variable;
+
+/**
+ * A transactional answer.
+ * Wraps all calls to the enclosed answer object, ensuring all calls are made
+ * within an activated transactional context. Also ensures that that context
+ * is deactivated upon returning from the outer-call.
+ *
+ * @created 2006-10-06
+ *
+ * @author <a href="mailto:andrae at netymon.com">Andrae Muys</a>
+ *
+ * @version $Revision: $
+ *
+ * @modified $Date: $
+ *
+ * @maintenanceAuthor $Author: $
+ *
+ * @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>
+ */
+
+public class TransactionalAnswer implements Answer {
+
+ private Answer answer;
+
+ private MulgaraTransaction transaction;
+
+ public TransactionalAnswer(MulgaraTransaction transaction, Answer answer) {
+ this.answer = answer;
+ this.transaction = transaction;
+ transaction.reference();
+ }
+
+ public Object getObject(final int column) throws TuplesException {
+ return transaction.execute(new AnswerOperation() {
+ public void execute() throws TuplesException {
+ returnObject(answer.getObject(column));
+ }
+ }).getObject();
+ }
+
+ public Object getObject(final String columnName) throws TuplesException {
+ return transaction.execute(new AnswerOperation() {
+ public void execute() throws TuplesException {
+ returnObject(answer.getObject(columnName));
+ }
+ });
+ }
+
+ public void beforeFirst() throws TuplesException {
+ transaction.execute(new AnswerOperation() {
+ public void execute() throws TuplesException {
+ answer.beforeFirst();
+ }
+ });
+ }
+
+ 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);
+ }
+ }
+ });
+ }
+
+ public int getColumnIndex(final Variable column) throws TuplesException {
+ return transaction.execute(new AnswerOperation() {
+ public void execute() throws TuplesException {
+ returnInt(answer.getColumnIndex(column));
+ }
+ }).getInt();
+ }
+
+ public int getNumberOfVariables() {
+ try {
+ return transaction.execute(new AnswerOperation() {
+ public void execute() {
+ returnInt(answer.getNumberOfVariables());
+ }
+ }).getInt();
+ } catch (TuplesException et) {
+ throw new IllegalStateException("Doesn't throw TuplesException", et);
+ }
+ }
+
+ public Variable[] getVariables() {
+ try {
+ return (Variable[])(transaction.execute(new AnswerOperation() {
+ public void execute() {
+ returnObject(answer.getVariables());
+ }
+ }).getObject());
+ } catch (TuplesException et) {
+ throw new IllegalStateException("Doesn't throw TuplesException", et);
+ }
+ }
+
+ public boolean isUnconstrained() throws TuplesException {
+ return transaction.execute(new AnswerOperation() {
+ public void execute() throws TuplesException {
+ returnBoolean(answer.isUnconstrained());
+ }
+ }).getBoolean();
+ }
+
+ public long getRowCount() throws TuplesException {
+ return transaction.execute(new AnswerOperation() {
+ public void execute() throws TuplesException {
+ returnLong(answer.getRowCount());
+ }
+ }).getLong();
+ }
+
+ public long getRowUpperBound() throws TuplesException {
+ return transaction.execute(new AnswerOperation() {
+ public void execute() throws TuplesException {
+ returnLong(answer.getRowUpperBound());
+ }
+ }).getLong();
+ }
+
+ public int getRowCardinality() throws TuplesException {
+ return transaction.execute(new AnswerOperation() {
+ public void execute() throws TuplesException {
+ returnInt(answer.getRowCardinality());
+ }
+ }).getInt();
+ }
+
+ public boolean next() throws TuplesException {
+ return transaction.execute(new AnswerOperation() {
+ public void execute() throws TuplesException {
+ returnBoolean(answer.next());
+ }
+ }).getBoolean();
+ }
+
+ public Object clone() {
+ try {
+ TransactionalAnswer c = (TransactionalAnswer)super.clone();
+ c.answer = (Answer)this.answer.clone();
+ c.transaction.reference();
+
+ return c;
+ } catch (CloneNotSupportedException ec) {
+ throw new IllegalStateException("Clone failed on Cloneable");
+ }
+ }
+}
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-10-25 22:35:58 UTC (rev 112)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/LocalSession.java 2006-10-26 13:56:44 UTC (rev 113)
@@ -38,6 +38,8 @@
* extension API. Expect it to change in signifigant, non-backwards compatible
* ways.
*
+ * Note: Deprecation warnings removed Oct 2006 to facilitate complete removal of
+ * this interface. THIS ENTIRE INTERFACE IS DEPRECATED DO NOT USE.
* @created 2004-11-10
*
* @author Andrew Newman
@@ -61,8 +63,6 @@
* Using start/finish TransactionalOperation ensures properly matched pairs of
* begin/end and suspend/resume.
*
- * @deprecated This should not be relied upon to create resolvers as this
- * should go away.
*/
public void startTransactionalOperation(boolean needsWrite)
throws QueryException;
@@ -71,8 +71,6 @@
* Mark the current transaction for rollback due to an exception.
*
* @param throwable the exception which caused the rollback
- * @deprecated This should not be relied upon to create resolvers as this
- * should go away.
*/
public void rollbackTransactionalBlock(Throwable throwable)
throws QueryException;
@@ -83,8 +81,6 @@
* Using start/finish TransactionalOperation ensures properly matched pairs of
* begin/end and suspend/resume.
*
- * @deprecated This should not be relied upon to create resolvers as this
- * should go away.
*/
public void finishTransactionalOperation(String errorString)
throws QueryException;
@@ -94,8 +90,6 @@
*
* @throws QueryException Must be called outside the try/catch(Throwable) block
* protecting the transaction.
- * @deprecated This should not be relied upon to create resolvers as this
- * should go away.
*/
public void resumeTransactionalBlock() throws QueryException;
@@ -104,8 +98,6 @@
*
* @throws Throwable Must be called inside the try/catch(Throwable) block
* protecting the transaction.
- * @deprecated This should not be relied upon to create resolvers as this
- * should go away.
*/
public void suspendTransactionalBlock() throws Throwable;
@@ -113,8 +105,6 @@
* Returns the current Resolver Session.
*
* @return the current resolver session.
- * @deprecated This should not be relied upon to create resolvers as this
- * should go away.
*/
public ResolverSession getResolverSession();
}
Modified: trunk/src/jar/resolver-spi/java/org/mulgara/resolver/view/SessionView.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/resolver/view/SessionView.java 2006-10-25 22:35:58 UTC (rev 112)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/resolver/view/SessionView.java 2006-10-26 13:56:44 UTC (rev 113)
@@ -37,8 +37,14 @@
* the ResolverFactory query rewriting interface.
*
* Use of this interface is HIGHLY discouraged!
- * @deprecated If you require this functionality, let the core team know as it
- * may affect scheduling of the new query rewriting interface.
+ *
+ * If you require this functionality, let the core team know as it
+ * may affect scheduling of the new query rewriting interface.
+ *
+ * Deprecation warnings removed to assist with development in this area.
+ * Note: This interface is considered deprecated. If you don't tell us you're
+ * using it it might just disappear without warning.
+ *
* @created 2004-09-22
* @author <a href="http://staff.tucanatech.com/andrae">Andrae Muys</a>
* @version $Revision: 1.8 $
Modified: trunk/src/jar/resolver-spi/java/org/mulgara/resolver/view/ViewMarker.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/resolver/view/ViewMarker.java 2006-10-25 22:35:58 UTC (rev 112)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/resolver/view/ViewMarker.java 2006-10-26 13:56:44 UTC (rev 113)
@@ -37,8 +37,14 @@
* the ResolverFactory query rewriting interface.
*
* Use of this interface is HIGHLY discouraged!
- * @deprecated If you require this functionality, let the core team know as it
- * may affect scheduling of the new query rewriting interface.
+ *
+ * If you require this functionality, let the core team know as it
+ * may affect scheduling of the new query rewriting interface.
+ *
+ * Deprecation warnings removed to assist with development in this area.
+ * Note: This interface is considered deprecated. If you don't tell us you're
+ * using it it might just disappear without warning.
+ *
* @created 2004-09-22
* @author <a href="http://staff.tucanatech.com/andrae">Andrae Muys</a>
* @version $Revision: 1.8 $
More information about the Mulgara-svn
mailing list