[Mulgara-svn] r131 - in branches/xafix-impl/src/jar: resolver/java/org/mulgara/resolver resolver-spi/java/org/mulgara/content resolver-spi/java/org/mulgara/resolver/spi resolver-store/java/org/mulgara/resolver/store
andrae at mulgara.org
andrae at mulgara.org
Tue Nov 14 08:33:20 UTC 2006
Author: andrae
Date: 2006-11-14 02:33:20 -0600 (Tue, 14 Nov 2006)
New Revision: 131
Added:
branches/xafix-impl/src/jar/resolver-spi/java/org/mulgara/resolver/spi/EnlistableResource.java
Modified:
branches/xafix-impl/src/jar/resolver-spi/java/org/mulgara/content/ContentResolver.java
branches/xafix-impl/src/jar/resolver-spi/java/org/mulgara/resolver/spi/Resolver.java
branches/xafix-impl/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java
branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java
branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java
branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java
branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/OperationContext.java
branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/SubqueryAnswerUnitTest.java
Log:
This is the next major increment. Note this doesn't compile, let alone run yet.
The goal for this increment is to finally move *all* the transaction handling
out of DatabaseSession and DatabaseOperationContext and into the
MulgaraTransaction and MulgaraTransactionManager objects.
IMPORTANT: Note this does add a method to Resolver, this will make this change
non-backwards compatible with existing resolvers. The need is for an extra
abort() method to allow the recovery of the write phase upon serious failure.
This should fix the 'Mulgara threw an exception and now I can't start a
write-transaction' problems.
Modified: branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java
===================================================================
--- branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java 2006-11-09 02:32:53 UTC (rev 130)
+++ branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java 2006-11-14 08:33:20 UTC (rev 131)
@@ -123,16 +123,18 @@
* 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 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;
@@ -140,64 +142,46 @@
private final List securityAdapterList;
private final URI temporaryModelTypeURI;
private final ResolverFactory temporaryResolverFactory;
- private final MulgaraTransactionManager transactionManager;
- private final Set outstandingAnswers;
/** Symbolic transformations this instance should apply. */
- private final List symbolicTransformationList;
+ private final List symbolicTransformationList;
+ private final boolean isWriting;
private WeakHashMap answers; // Used as a set, all values are null. Java doesn't provide a WeakHashSet.
- //
- // Constructor
- //
- /**
- * 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,
- MulgaraTransactionManager 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.cachedModelSet = new HashSet();
+ this.changedCachedModelSet = new HashSet();
+ this.enlistedResolverMap = new HashMap();
this.answers = new WeakHashMap();
}
@@ -227,8 +211,7 @@
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 = systemResolver.globalize(model);
@@ -275,8 +258,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.");
}
@@ -304,20 +286,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
{
@@ -341,9 +376,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
@@ -353,15 +386,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;
}
@@ -420,66 +461,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().isSuspended()) {
- 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
@@ -528,21 +513,18 @@
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);
}
}
@@ -555,7 +537,7 @@
* @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
@@ -568,8 +550,7 @@
}
// Return the protocol
return ((URIReference) node).getURI().getScheme();
- }
- catch (GlobalizeException e) {
+ } catch (GlobalizeException e) {
throw new QueryException("Unable to globalize node " + n, e);
}
}
@@ -605,11 +586,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);
}
@@ -633,6 +612,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.");
@@ -785,7 +765,6 @@
}
Tuples innerCount(LocalQuery localQuery) throws QueryException {
- // Validate "query" parameter
if (localQuery == null) {
throw new IllegalArgumentException("Null \"query\" parameter");
}
@@ -851,15 +830,11 @@
// Complete the numerical phase of resolution
Tuples tuples = localQuery.resolve();
- MulgaraTransaction xa = databaseSession.getTransaction();
- result = new TransactionalAnswer(xa, 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;
}
@@ -906,6 +881,11 @@
} catch (TuplesException et) {
throw new QueryException("Error force-closing answers", et);
}
+
+ clearCache();
+ systemResolver = null;
+ systemModelCacheMap.clear();
+ enlistedResolverMap.clear();
}
public SystemResolver getSystemResolver() {
@@ -916,8 +896,73 @@
this.systemResolver = systemResolver;
}
- // !!FIXME: Temp hack for transactions.
- public void endTransaction() throws QueryException {
- databaseSession.endTransactionalBlock("Failed to end transaction");
+
+ /**
+ * Clear the cache of temporary models.
+ */
+ private void clearCache() {
+ // Clear the temporary models
+ if (!cachedModelSet.isEmpty()) {
+ try {
+ Resolver temporaryResolver =
+ temporaryResolverFactory.newResolver(true,
+ operationContext.getSystemResolver(),
+ operationContext.getSystemResolver());
+ 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,
+ operationContext.getSystemResolver(),
+ operationContext.getSystemResolver());
+ 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().valueSet();
+ while (i.hasNext()) {
+ ((Resolver)i.next()).abort();
+ }
+ this.clear();
+ }
+
+ public void initiate(MulgaraTransaction transaction) throws QueryException {
+ this.transaction = transaction;
+ this.systemResolver = systemResolverFactory.newResolver(isWriting);
+ try {
+ transaction.enlist(systemResolver);
+ } catch (Exception e) {
+ throw new QueryException("Unable to enlist systemResolver:" + resolver + " into transaction", e);
+ }
+ }
}
Modified: branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java
===================================================================
--- branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java 2006-11-09 02:32:53 UTC (rev 130)
+++ branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java 2006-11-14 08:33:20 UTC (rev 131)
@@ -83,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;
/**
@@ -159,48 +136,9 @@
/** 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
- //
/**
* Construct a database session.
@@ -258,43 +196,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;
@@ -310,26 +240,9 @@
this.cachedResolverFactorySet = cachedResolverFactorySet;
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
- );
+ this.operationContext = null;
if (logger.isDebugEnabled()) {
logger.debug("Constructed DatabaseSession");
}
@@ -512,9 +425,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);
@@ -615,131 +527,28 @@
public void setAutoCommit(boolean autoCommit) throws QueryException {
- try {
- if (logger.isInfoEnabled()) {
- logger.info("setAutoCommit(" + autoCommit + ") called with autoCommit = " + this.autoCommit);
- }
-
- if (!this.autoCommit && autoCommit) { // Turning autoCommit on
- try {
- transaction.execute(new AnswerOperation() {
- public void execute() {
- try {
- transaction.dereference();
- } catch (MulgaraTransactionException em) {
- logger.error("Dereference Failed", em);
- throw new IllegalStateException("dereferenced failed");
- }
- }
- });
- } catch (TuplesException et) {
- throw new QueryException("Failed to dereference transaction", et);
- } finally {
- this.autoCommit = true;
- this.inFailedTransaction = false;
- // Guarentee transaction ends here.
- cleanupTransaction();
- }
- } else if (this.autoCommit && !autoCommit) { // Turning autoCommit off
- transaction = beginTransactionalBlock(true);
- try {
- transaction.reference();
- operationContext.setSystemResolver(systemResolverFactory.newResolver(true));
- operationContext.enlistResolver(operationContext.getSystemResolver());
- transaction.tempDeactivate();
- this.autoCommit = false;
- } catch (QueryException eq) {
- throw eq;
- } catch (Throwable t) {
- this.autoCommit = true;
- logger.error("Failed to set autocommit off", t);
- throw new QueryException("Failed to set autocommit off", t);
- }
- } 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);
- }
- }
- } catch (QueryException eq) {
- logger.error("Threw exception in autoCommit:", eq);
- throw eq;
- } catch (Exception e) {
- logger.error("Threw RuntimeException in ac:", e);
- throw new QueryException("setAutoCommit failed:", e);
+ if (logger.isInfoEnabled()) {
+ logger.info("setAutoCommit(" + autoCommit + ") called.");
}
+ transactionManager.setAutoCommit(this, autoCommit);
}
public void commit() throws QueryException {
logger.info("Committing transaction");
- if (!autoCommit) {
- synchronized (DatabaseSession.class) {
- setAutoCommit(true);
- setAutoCommit(false);
- }
- }
+ transactionManager.explicitCommit(this);
}
public void rollback() throws QueryException {
logger.info("Rollback transaction");
- if (autoCommit) {
- throw new QueryException(
- "Attempt to rollback transaction outside user-transaction");
- } else if (transaction == null) {
- throw new QueryException("Didn't find transaction");
- }
-
- try {
- transaction.execute(new AnswerOperation() {
- public void execute() {
- try {
- transaction.explicitRollback();
- } catch (MulgaraTransactionException em) {
- logger.error("Explicit Rollback failed");
- throw new IllegalStateException("Explicit Rollback failed");
- }
- }
- });
- explicitRollback = true;
- } catch (TuplesException et) {
- throw new QueryException("Rollback failed", et);
- } finally {
- synchronized (DatabaseSession.class) {
- cleanupTransaction();
- setAutoCommit(false);
- }
- }
+ transactionManager.explicitRollback(this);
}
public void close() throws QueryException {
logger.info("Closing session");
try {
- if (!autoCommit) {
- logger.warn("Closing session while holding write-lock");
-
- if (transaction != null) {
- transaction.execute(new AnswerOperation() {
- public void execute() {
- try {
- transaction.setRollbackOnly();
- transaction.dereference();
- } catch (Exception e) {
- logger.error("Close failed", e);
- throw new IllegalStateException("Close failed", e);
- }
- }
- });
- }
- }
- } catch (TuplesException et) {
- throw new QueryException ("Close failed", et);
- } finally {
- try {
- operationContext.clear();
- } finally {
- releaseWriteLock();
- }
+ transactionManager.terminateCurrentTransactions(this);
+ } catch (MulgaraTransactionException em) {
+ throw new QueryException("Error closing session. Forced close required", em);
}
}
@@ -752,10 +561,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();) {
@@ -768,335 +573,12 @@
// Transaction control methods. Implements LocalSession.
//
- /**
- * 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);
- }
- transaction.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;
- }
-
- /**
- * 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 without starting transaction");
- } else if (!transaction.isSuspended()) {
- throw new IllegalStateException("Attempt to resume unsuspended transaction");
- } else if (inFailedTransaction == true) {
- throw new IllegalStateException("Transaction already failed, set autocommit true to reset");
- }
-
- try {
- this.transaction.resume();
- } 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 unstarted transaction");
- } else if (transaction.isSuspended()) {
- 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 = transaction.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.suspend();
- }
-
public ResolverSession getResolverSession() {
+ assert operationContext != null;
return operationContext.getSystemResolver();
}
//
- // 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 MulgaraTransaction 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);
- }
- }
-
- if (transaction != null) {
- throw new QueryException("Attempt to start nested transaction");
- }
-
- try {
- transaction = new MulgaraTransaction(transactionManager, operationContext);
- operationContext.setSystemResolver(systemResolverFactory.newResolver(allowWrites));
- operationContext.enlistResolver(operationContext.getSystemResolver());
-
- return transaction;
- } 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) {
- transaction.commit();
- } else {
- try {
- transaction.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 {
- cleanupTransaction();
- }
- }
-
- 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,
- operationContext.getSystemResolver(),
- operationContext.getSystemResolver());
- 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,
- operationContext.getSystemResolver(),
- operationContext.getSystemResolver());
- 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 = operationContext.getSystemResolver().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
//
@@ -1104,20 +586,6 @@
return transaction;
}
- boolean isWriting() {
- return writing;
- }
-
- boolean ensureTransactionResumed() throws QueryException {
- if (transaction != null && transaction.isSuspended()) {
- 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.
@@ -1175,15 +643,13 @@
// Clear previous transaction. FIXME: This won't be necessary once we
// support overlapping transactions.
if (autoCommit) {
- operationContext.clear();
+ newOperationContext(operation.isWriteOperation());
transaction = null;
}
// FIXME: This currently always initiates transaction - eventually manager
// will handle begin vs. resume.
if (transaction == null) {
- transaction = beginTransactionalBlock(operation.isWriteOperation());
- } else {
- transaction.tempActivate();
+ transaction = transactionManager.getTransaction(this, operation.isWriteOperation());
}
//
@@ -1193,25 +659,28 @@
transaction.execute(operation, resolverSessionFactory, metadata);
} catch (MulgaraTransactionException em) {
throw new QueryException(errorString, em);
- } finally {
- transaction.tempDeactivate();
}
}
- OperationContext getOperationContext() {
+ // !!FIXME: needs to be updated to 1-N
+ public OperationContext newOperationContext(boolean writing) {
+ if (operationContext != null) {
+ operationContext.clear();
+ }
+
+ operationContext = new DatabaseOperationContext(
+ cachedResolverFactorySet,
+ externalResolverFactoryMap,
+ internalResolverFactoryMap,
+ metadata,
+ securityAdapterList,
+ temporaryModelTypeURI,
+ temporaryResolverFactory,
+ transactionManager,
+ symbolicTransformationList,
+ systemResolverFactory,
+ writing
+ );
return operationContext;
}
-
- void cleanupTransaction() {
- releaseWriteLock();
- transaction = null;
- explicitRollback = false;
- autoCommit = true;
-
- operationContext.setSystemResolver(null);
- outstandingAnswers.clear();
- enlistedResolverMap.clear();
- clearCache();
- operationContext.clearSystemModelCache();
- }
}
Modified: branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java
===================================================================
--- branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java 2006-11-09 02:32:53 UTC (rev 130)
+++ branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java 2006-11-14 08:33:20 UTC (rev 131)
@@ -53,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. */
@@ -80,70 +80,64 @@
private int rollback;
private Throwable rollbackCause;
- //
- // Temporary scaffolding to support transition.
- //
-
- private boolean suspended;
- private boolean ended;
-
public MulgaraTransaction(MulgaraTransactionManager manager, OperationContext context)
throws Exception {
report("Creating Transaction");
- 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;
+ 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;
- this.transaction = manager.transactionStart(this);
+ inuse = 0;
+ using = 0;
- inuse = 1; // Note: This implies implict activation as a part of construction.
- using = 0;
+ rollback = NO_ROLLBACK;
+ rollbackCause = null;
- rollback = NO_ROLLBACK;
- rollbackCause = null;
+ // FIXME: need this added to context. Allows context to cleanup caches at end of transaction.
+ // this.transaction.enlistResource(context.getXAResource());
+ // logger.warn("Created Transaction from: ", new Throwable());
+ } finally {
+ report("Created Transaction");
+ }
+ }
-// FIXME: scaffolding.
- suspended = false;
- ended = false;
-// FIXME: need this added to context. Sets up and enlists the system-resolver.
-// context.initiate();
+ synchronized void activate() throws MulgaraTransactionException {
+ report("Activating Transaction");
+ try {
+ if (rollback != NO_ROLLBACK) {
+ throw new MulgaraTransactionException("Attempt to activate failed transaction");
+ }
-// FIXME: need this added to context. Allows context to cleanup caches at end of transaction.
-// this.transaction.enlistResource(context.getXAResource());
-// logger.warn("Created Transaction from: ", new Throwable());
- report("Created Transaction");
- }
+ 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) {
+ throw new MulgaraTransactionException("Attempt to activate terminated 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 {
- report("Activating Transaction");
- 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) {
+ if (transaction == null) {
+ startTransaction();
+ } else {
+ resumeTransaction();
+ }
+ }
- if (inuse == 0) {
- report("Resuming transaction");
-// try {
-// manager.transactionResumed(this);
-// } catch (Throwable th) {
-// logger.warn("Error resuming transaction: ", th);
-// failTransaction();
-// throw new MulgaraTransactionException("Error resuming transaction", th);
-// }
+ inuse++;
+
+ checkActivated();
+ } finally {
+ report("Activated transaction");
}
-
- inuse++;
-
- report("Activated transaction");
}
@@ -152,166 +146,254 @@
// 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 new MulgaraTransactionException("Mismatched activate/deactivate. inuse < 0: " + inuse);
-// throw implicitRollback(
-// new MulgaraTransactionException("Mismatched activate/deactivate. inuse < 0: " + inuse));
- } else if (using < 0) {
- throw new MulgaraTransactionException("Reference Failure. using < 0: " + using);
- }
-
- if (inuse == 0) {
- if (using == 0) {
- report("Completing Transaction");
- // END TRANSACTION HERE. But commit might fail.
- try {
-// manager.transactionComplete(this);
- context.endTransaction();
-// } catch (MulgaraTransactionException em) {
-// logger.warn("Error committing transaction", em);
-// throw em;
- } catch (QueryException eq) {
- logger.warn("Error committing transaction", eq);
- throw new MulgaraTransactionException("Failed to commit transaciton", eq);
- } finally {
- manager = null;
- transaction = null;
+ if (inuse == 0) {
+ if (using == 0) {
+ terminateTransaction();
+ } else {
+ suspendTransaction();
}
- } else {
- report("Suspending Transaction");
- // 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;
}
- currentThread = null;
+ } finally {
+ report("Deactivated Transaction");
}
- 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() throws MulgaraTransactionException {
report("Referencing Transaction");
- if (inuse < 1) {
- throw new MulgaraTransactionException("Mismatched activate/deactivate. inuse < 1: " + inuse);
- } else if (using < 0) {
- throw new MulgaraTransactionException("Reference Failure. using < 0: " + using);
+ try {
+ checkActivated();
+ using++;
+ } finally {
+ report("Referenced Transaction");
}
- using++;
- report("Referenced Transaction");
}
void dereference() throws MulgaraTransactionException {
report("Dereferencing Transaction");
- if (inuse < 1) {
- throw new MulgaraTransactionException("Mismatched activate/deactivate. inuse < 1: " + inuse);
- } else if (using < 1) {
- throw new MulgaraTransactionException("Reference Failure. using < 1: " + using);
+ try {
+ checkActivated();
+ if (using < 1) {
+ throw implicitRollback(new MulgaraTransactionException(
+ "Reference Failure. Dereferencing while using < 1: " + using));
+ }
+ using--;
+ } finally {
+ report("Dereferenced Transaction");
}
- using--;
- 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 {
- 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) {
+ // This exception will be replaced by the exception thrown by deactivate().
+ // We still throw this exception as it will abort any outer operations
+ // should we be in a nested operation.
+ throw implicitRollback(th);
+ } finally {
+ deactivate();
+ }
} finally {
- deactivate();
+ report("Executed Operation");
}
}
- /** Should rename this 'wrap' */
AnswerOperationResult execute(AnswerOperation ao) throws TuplesException {
- report("Executing Operation");
+ debugReport("Executing AnswerOperation");
try {
activate();
try {
ao.execute();
return ao.getResult();
} catch (Throwable th) {
- throw new TuplesException("Error accessing Answer", th);
- // throw implicitRollback(th);
+ throw implicitRollback(th);
} finally {
deactivate();
}
} catch (MulgaraTransactionException em) {
throw new TuplesException("Transaction error", em);
} finally {
- report("Executed Operation");
+ debugReport("Executed AnswerOperation");
}
}
- private MulgaraTransactionException implicitRollback(Throwable cause) throws MulgaraTransactionException {
- rollback = IMPLICIT_ROLLBACK;
- rollbackCause = cause;
- failTransaction();
- return new MulgaraTransactionException("Transaction Rolledback", cause);
+ 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 {
+ // Not sure if this is correct - we may already be deactivated due to an
+ // inner operation failing - if we are then we don't want to overwrite the
+ // rollbackCause as that will most likely be the root cause of the problem.
+ checkActivated();
+ rollback = IMPLICIT_ROLLBACK;
+ rollbackCause = cause;
+ failTransaction();
+ return new MulgaraTransactionException("Transaction in Rollback", cause);
+ } catch (Throwable th) {
+ abortTransaction("Failed to rollback normally", 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 MulgaraTransactioinException {
+ 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);
+ try {
+ switch (rollback) {
+ case NO_ROLLBACK:
+ report("Completing Transaction");
+ transaction.commit();
+ transaction = null;
+ break;
+ case IMPLICIT_ROLLBACK:
+ report("Completing Implicitly Failed Transaction");
+ // Check that transaction is cleaned up.
+ throw new MulgaraTransactionException(
+ "Failed transaction finalised with ROLLBACK", rollbackCause);
+ case EXPLICIT_ROLLBACK:
+ report("Completing Explicitly Failed Transaction");
+ // Check that transaction is cleaned up.
+ break;
+ }
+ } finally {
+ manager.transactionComplete(this);
+ manager = null;
+ inuse = 0;
+ using = 0;
+ context.clear();
+ 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() {
+ 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!
+ }
+
+ Transaction getTransaction() {
return transaction;
}
@@ -325,68 +407,33 @@
}
}
- private void report(String desc) {
- if (logger.isInfoEnabled()) {
- logger.info(desc + ": " + System.identityHashCode(this) +
- ", inuse=" + inuse + ", using=" + using);
- }
- }
-
//
- // Scaffolding
+ // Used internally
//
- public boolean isSuspended() {
- return suspended;
- }
- public void suspend() throws Throwable {
- if (ended) {
- throw new MulgaraTransactionException("Attempt to suspend ended transaction");
+ private void checkActivated() throws MulgaraTransactionException {
+ 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(
+ throw new MulgaraTransactionException("Reference Failure. using < 0: " + using));
}
- manager.suspend();
- suspended = true;
}
- public void resume() throws Exception {
- if (ended) {
- throw new MulgaraTransactionException("Attempt to resume ended transaction");
+ private void report(String desc) {
+ if (logger.isInfoEnabled()) {
+ logger.info(desc + ": " + System.identityHashCode(this) +
+ ", inuse=" + inuse + ", using=" + using);
}
- manager.resume(this.transaction);
- suspended = false;
}
- public void commit() throws Exception {
- if (suspended) {
- throw new MulgaraTransactionException("Attempt to commit suspended transaction");
+ private void debugReport(String desc) {
+ if (logger.isDebugEnabled()) {
+ logger.debug(desc + ": " + System.identityHashCode(this) +
+ ", inuse=" + inuse + ", using=" + using);
}
- ended = true;
- manager.commit();
}
-
- public void setRollbackOnly() throws Exception {
- if (suspended) {
- throw new MulgaraTransactionException("Attempt to rollback suspended transaction");
- }
- manager.setRollbackOnly();
- }
-
- public int getStatus() throws Throwable {
- return manager.getStatus();
- }
-
- public void tempDeactivate() throws QueryException {
- try {
- deactivate();
- } catch (MulgaraTransactionException em) {
- throw new QueryException("Failed to deactivate", em);
- }
- }
-
- public void tempActivate() throws QueryException {
- try {
- activate();
- } catch (MulgaraTransactionException em) {
- throw new QueryException("Failed to activate", em);
- }
- }
}
Modified: branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
===================================================================
--- branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java 2006-11-09 02:32:53 UTC (rev 130)
+++ branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java 2006-11-14 08:33:20 UTC (rev 131)
@@ -70,10 +70,23 @@
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;
@@ -84,7 +97,10 @@
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 = transactionManagerFactory.newTransactionManager();
this.writeLockMutex = new Object();
@@ -101,21 +117,27 @@
* </ul>
*/
public synchronized MulgaraTransaction getTransaction(DatabaseSession session, boolean write) throws MulgaraTransactionException {
-//
-// FIXME: When we migrate autocommit and the writelock into the manager
-// uncomment this.
-//
-// if (session == currentWritingSession) {
-// return userTransaction;
-// }
-//
-// if (write) {
-// obtainWriteLock(session);
-// }
+ if (session == currentWritingSession) {
+ return userTransaction;
+ }
+
+ // FIXME: Remove this once we go to 1-N.
+ if (sessions.contains(session)) {
+ throw MulgaraTransactionException("Multiple Transactions started per session");
+ }
+
+ if (write) {
+ obtainWriteLock(session);
+ }
+
// FIXME: Need to finish 1-N DS-OC and provide this method - should really be newOperationContext.
try {
- return new MulgaraTransaction(this, session.getOperationContext());
+ MulgaraTransaction transaction =
+ new MulgaraTransaction(this, session.newOperationContext(write));
+ sessions.put(transaction, session);
+
+ return transaction;
} catch (MulgaraTransactionException em) {
throw em;
} catch (Exception e) {
@@ -124,19 +146,6 @@
}
-/*
- * disabled temporarally while migrating.
- 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) {
@@ -157,6 +166,13 @@
public synchronized void commit(Session 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);
}
@@ -173,58 +189,90 @@
userTransaction.explicitRollback();
finalizeTransaction();
} finally {
- failedSessions.put(currentWritingSession, userTransaction);
+ failedSessions.add(currentWritingSession);
userTransaction = null;
currentWritingSession = null;
releaseWriteLock();
+ setAutoCommit(false);
}
+ } else if (failedSessions.contains(session) {
+ failedSessions.remove(session);
+ setAutoCommit(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)) {
+ if (session == currentWritingSession && failedSessions.contains(session)) {
// CRITICAL ERROR - transaction failed, but we did not finalise it.
}
- 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.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));
+ userTransaction = getTransaction(session, 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.
- // Regardless we need to close all associated Answer objects
- }
+ 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;
+ try {
+ if (session == currentWritingSession) {
+ logger.error("Terminating session while holding writelock");
+ userTransaction.execute(new AnswerOperation() {
+ public void execute() {
+ 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");
+ transaction.implicitRollback(new MulgaraTransactionException(
+ "Terminating session during active transaction");
+ transaction.completeTransaction();
+ }
+ }
}
//
@@ -234,12 +282,18 @@
public synchronized Transaction transactionStart(MulgaraTransaction transaction)
throws MulgaraTransactionException {
try {
- logger.info("Beginning Transaction: ", new Throwable());
+ 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();
-// FIXME: Not in use yet - activate later.
-// activeTransactions.put(Thread.currentThread(), transaction);
+ activeTransactions.put(Thread.currentThread(), transaction);
return jtaTrans;
} catch (Exception e) {
@@ -253,8 +307,7 @@
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 {
@@ -275,33 +328,42 @@
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());
+ sessions.remove(transaction);
+ }
+
+ public synchronized void transactionAborted(MulgaraTransaction transaction) {
try {
- transactionManager.commit();
-// if (transaction == userTransaction) {
-// releaseWriteLock();
-// }
- } catch (Exception e) {
- throw new MulgaraTransactionException("Commit Failed", e);
- } finally {
- activeTransactions.remove(Thread.currentThread());
-// Remove transaction from Session's list.
+ // Make sure this cleans up the transaction metadata - this transaction is DEAD!
+ if (transaction == userTransaction) {
+ failedSessions.add(currentWritingSession);
+ }
+ transactionComplete(transaction);
+ } catch (Throwable th) {
+ // FIXME: This should probably abort the entire server after logging the error!
+ logger.error("Error managing transaction abort", th);
}
}
- //
- // Temporary methods to introduce the manager into the code-path.
- //
-
- void setTransactionTimeout(int transactionTimeout) {
+ public void setTransactionTimeout(int transactionTimeout) {
try {
transactionManager.setTransactionTimeout(transactionTimeout);
} catch (SystemException es) {
@@ -309,32 +371,7 @@
}
}
- void setRollbackOnly() throws Exception {
- transactionManager.setRollbackOnly();
+ private boolean holdsWriteLock(MulgaraTransaction transaction) {
+ return transaction == userTransaction;
}
-
- void resume(Transaction t) throws Exception {
- transactionManager.resume(t);
- }
-
- int getStatus() throws SystemException {
- return transactionManager.getStatus();
- }
-
- void commit() throws Exception {
- transactionManager.commit();
- }
-
- Transaction getTransaction() throws Exception {
- return transactionManager.getTransaction();
- }
-
- Transaction suspend() throws Exception {
- return transactionManager.suspend();
- }
-
- void begin() throws Exception {
- logger.info("Beginning Transaction:", new Throwable());
- transactionManager.begin();
- }
}
Modified: branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/OperationContext.java
===================================================================
--- branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/OperationContext.java 2006-11-09 02:32:53 UTC (rev 130)
+++ branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/OperationContext.java 2006-11-14 08:33:20 UTC (rev 131)
@@ -123,7 +123,4 @@
public Answer doQuery(Query query) throws Exception;
public SystemResolver getSystemResolver(); // FIXME: Scaffolding for transactions.
-
- // !!FIXME: Transactions hack
- public void endTransaction() throws QueryException;
}
Modified: branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/SubqueryAnswerUnitTest.java
===================================================================
--- branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/SubqueryAnswerUnitTest.java 2006-11-09 02:32:53 UTC (rev 130)
+++ branches/xafix-impl/src/jar/resolver/java/org/mulgara/resolver/SubqueryAnswerUnitTest.java 2006-11-14 08:33:20 UTC (rev 131)
@@ -206,7 +206,5 @@
throws Exception { return null; }
public SystemResolver getSystemResolver() { return null; } // FIXME: Scaffolding for transactions.
-
- public void endTransaction () { }
}
}
Modified: branches/xafix-impl/src/jar/resolver-spi/java/org/mulgara/content/ContentResolver.java
===================================================================
--- branches/xafix-impl/src/jar/resolver-spi/java/org/mulgara/content/ContentResolver.java 2006-11-09 02:32:53 UTC (rev 130)
+++ branches/xafix-impl/src/jar/resolver-spi/java/org/mulgara/content/ContentResolver.java 2006-11-14 08:33:20 UTC (rev 131)
@@ -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: branches/xafix-impl/src/jar/resolver-spi/java/org/mulgara/resolver/spi/EnlistableResource.java
===================================================================
--- branches/xafix-impl/src/jar/resolver-spi/java/org/mulgara/resolver/spi/EnlistableResource.java 2006-11-09 02:32:53 UTC (rev 130)
+++ branches/xafix-impl/src/jar/resolver-spi/java/org/mulgara/resolver/spi/EnlistableResource.java 2006-11-14 08:33:20 UTC (rev 131)
@@ -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: branches/xafix-impl/src/jar/resolver-spi/java/org/mulgara/resolver/spi/Resolver.java
===================================================================
--- branches/xafix-impl/src/jar/resolver-spi/java/org/mulgara/resolver/spi/Resolver.java 2006-11-09 02:32:53 UTC (rev 130)
+++ branches/xafix-impl/src/jar/resolver-spi/java/org/mulgara/resolver/spi/Resolver.java 2006-11-14 08:33:20 UTC (rev 131)
@@ -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: branches/xafix-impl/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java
===================================================================
--- branches/xafix-impl/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java 2006-11-09 02:32:53 UTC (rev 130)
+++ branches/xafix-impl/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java 2006-11-14 08:33:20 UTC (rev 131)
@@ -525,4 +525,13 @@
constraintElement.getClass() + ")");
}
}
+
+
+ // FIXME: Need to propagate to other resolvers.
+ public void abort() {
+ statementStore.rollback();
+ xaResolverSession.rollback();
+ statementStore.release();
+ xaResolverSession.release();
+ }
}
More information about the Mulgara-svn
mailing list