/*
* $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/store/impl/rdbms/AbstractRDBMSStore.java,v 1.2.2.1 2004/02/05 16:07:52 mholz Exp $
* $Revision: 1.2.2.1 $
* $Date: 2004/02/05 16:07:52 $
*
* ====================================================================
*
* Copyright 1999-2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.slide.store.impl.rdbms;
import java.lang.reflect.Constructor;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import org.apache.slide.common.AbstractXAService;
import org.apache.slide.common.Service;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.ServiceConnectionFailedException;
import org.apache.slide.common.ServiceDisconnectionFailedException;
import org.apache.slide.common.ServiceInitializationFailedException;
import org.apache.slide.common.ServiceParameterErrorException;
import org.apache.slide.common.ServiceParameterMissingException;
import org.apache.slide.common.ServiceResetFailedException;
import org.apache.slide.common.Uri;
import org.apache.slide.content.NodeRevisionContent;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.content.NodeRevisionNumber;
import org.apache.slide.content.RevisionAlreadyExistException;
import org.apache.slide.content.RevisionDescriptorNotFoundException;
import org.apache.slide.content.RevisionNotFoundException;
import org.apache.slide.lock.LockTokenNotFoundException;
import org.apache.slide.lock.NodeLock;
import org.apache.slide.security.NodePermission;
import org.apache.slide.store.ContentStore;
import org.apache.slide.store.LockStore;
import org.apache.slide.store.NodeStore;
import org.apache.slide.store.RevisionDescriptorStore;
import org.apache.slide.store.RevisionDescriptorsStore;
import org.apache.slide.store.SecurityStore;
import org.apache.slide.structure.ObjectAlreadyExistsException;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.util.logger.Logger;
/**
* J2EE store implementation - implements the shared parts of
* the two (content, descriptors) J2EE stores for the new Indexed DB Schema.
*
* @author <a href="mailto:msmith@apache.org">Michael Smith</a>
* @author <a href="mailto:akumar@metatomix.com">Ashok Kumar</a>
* @author <a href="mailto:cmlenz@apache.org">Christopher Lenz</a>
* @author <a href="mailto:ozeigermann@c1-fse.de">Oliver Zeigermann</a>
* @version $Revision: 1.2.2.1 $
*/
public abstract class AbstractRDBMSStore
extends AbstractXAService
implements LockStore, NodeStore, RevisionDescriptorsStore, RevisionDescriptorStore, SecurityStore, ContentStore {
protected String LOG_CHANNEL = this.getClass().getName();
protected static final int TX_IDLE = 0;
protected static final int TX_PREPARED = 1;
protected static final int TX_SUSPENDED = 2;
protected ThreadLocal activeTransactionContext = new ThreadLocal();
protected RDBMSAdapter adapter;
protected boolean alreadyInitialized = false;
/**
* Indicates whether the transaction manager will commit / rollback
* the transaction or the store is in charge of it. Slide's internal
* TM does not commit / rollback, but TMs more aligned to the spec (e.g. JBoss' TM) do.
*/
protected boolean tmCommits = false;
/**
* Initializes the data source with a set of parameters.
*
* @param parameters Hashtable containing the parameters' name
* and associated value
* @exception ServiceParameterErrorException Incorrect service parameter
* @exception ServiceParameterMissingException Service parameter missing
*/
public void setParameters(Hashtable parameters)
throws ServiceParameterErrorException, ServiceParameterMissingException {
// Adapter class
String value = (String) parameters.get("adapter");
if (value == null) {
adapter = new StandardRDBMSAdapter(this, getLogger());
} else {
try {
Class adapterClass = Class.forName(value);
Constructor ctor = adapterClass.getConstructor(new Class[] { Service.class, Logger.class });
adapter = (RDBMSAdapter) ctor.newInstance(new Object[] { this, getLogger()});
} catch (Exception e) {
// reflection exception
getLogger().log(
"Error instantiating Adapter '" + value + "' (" + e.getMessage() + ")",
LOG_CHANNEL,
Logger.ERROR);
}
}
if (adapter != null) {
adapter.setParameters(parameters);
}
// XXX need to initialize it here, as some security requests access the store before initialization
try {
initialize(null);
} catch (ServiceInitializationFailedException e) {
// XXX this is not very satisfactory...
throw new ServiceParameterErrorException(this, e.getMessage());
}
}
/**
* Establishes the global connection to the data source.
*
* @exception ServiceConnectionFailedException if the connection failed
*/
public synchronized void connect() throws ServiceConnectionFailedException {
}
/**
* Returns connection status.
*/
public boolean isConnected() {
return true;
}
/**
* Closes the global connection to the data source.
*
* @exception ServiceDisconnectionFailedException if closing the connection
* failed
*/
public void disconnect() throws ServiceDisconnectionFailedException {
}
/**
* Does nothing.
*
* @exception ServiceResetFailedException Reset failed
*/
public synchronized void reset() throws ServiceResetFailedException {
}
// ----------------------------------------------------- XAResource Methods
/**
* Get the transaction timeout value for this XAResource.
* Just returns 0, we don't have a way of doing transaction timeouts
* with the connection.
*/
public int getTransactionTimeout() throws XAException {
return 0;
}
/**
* Set transaction timeout, not implemented (returns false).
*/
public boolean setTransactionTimeout(int timeout) throws XAException {
return false;
}
public Xid[] recover(int flag) throws XAException {
getLogger().log("recover() for thread: " + Thread.currentThread(), LOG_CHANNEL, Logger.DEBUG);
TransactionId id = getActiveTransactionContext();
if (id != null && id.status == TX_PREPARED) {
Xid[] xids = new Xid[1];
xids[0] = id.xid;
return xids;
} else
return new Xid[0];
}
public int prepare(Xid xid) throws XAException {
getLogger().log("prepare() for thread: " + Thread.currentThread(), LOG_CHANNEL, Logger.DEBUG);
TransactionId id = getActiveTransactionContext();
if (id == null)
throw new XAException(XAException.XAER_NOTA);
if (xid == null)
throw new XAException(XAException.XAER_INVAL);
if (id.status != TX_IDLE && id.status != TX_SUSPENDED)
throw new XAException(XAException.XAER_PROTO);
if (id.rollbackOnly)
throw new XAException(XAException.XA_RBROLLBACK);
id.status = TX_PREPARED;
return XAResource.XA_OK;
}
public boolean isSameRM(XAResource xares) throws XAException {
if (xares == null)
return false;
else
return this == xares;
}
public void forget(Xid xid) throws XAException {
getLogger().log("forget() for thread: " + Thread.currentThread(), LOG_CHANNEL, Logger.DEBUG);
TransactionId id = getActiveTransactionContext();
if (id == null || id.xid == null)
throw new XAException(XAException.XAER_NOTA);
if (xid == null)
throw new XAException(XAException.XAER_INVAL);
try {
id.connection.close();
} catch (SQLException e) {
getLogger().log("Couldn't close connection.", LOG_CHANNEL, Logger.ERROR);
}
getLogger().log("forget(): removing from map: " + Thread.currentThread(), LOG_CHANNEL, Logger.DEBUG);
activeTransactionContext.set(null);
}
public void end(Xid xid, int flags) throws XAException {
getLogger().log("end() for thread: " + Thread.currentThread(), LOG_CHANNEL, Logger.DEBUG);
TransactionId id = getActiveTransactionContext();
if (id == null || id.xid == null)
throw new XAException(XAException.XAER_NOTA);
if (xid == null)
throw new XAException(XAException.XAER_INVAL);
if (flags == XAResource.TMSUSPEND)
id.status = TX_SUSPENDED;
if (flags == XAResource.TMFAIL)
id.rollbackOnly = true;
}
/**
* Commit the global transaction specified by xid.
*/
public void commit(Xid xid, boolean onePhase) throws XAException {
getLogger().log(
"commit() for thread " + Thread.currentThread() + ", removing from map",
LOG_CHANNEL,
Logger.DEBUG);
TransactionId id = getActiveTransactionContext();
if (id == null) {
getLogger().log(
"Error committing: no transaction associated with current thread",
LOG_CHANNEL,
Logger.ERROR);
throw new XAException(XAException.XAER_NOTA);
}
if (xid == null)
throw new XAException(XAException.XAER_INVAL);
if (!onePhase && id.status != TX_PREPARED)
throw new XAException(XAException.XAER_PROTO);
if (onePhase && (!(id.status == TX_IDLE || id.status == TX_SUSPENDED)))
throw new XAException(XAException.XAER_PROTO);
Connection conn = id.connection;
if (conn == null) {
getLogger().log(
"commit(): No connection in connectionMap for id \"" + id + "\"",
LOG_CHANNEL,
Logger.ERROR);
throw new XAException(XAException.XAER_NOTA);
}
try {
if (!tmCommits) {
if (id.rollbackOnly) {
conn.rollback();
} else {
conn.commit();
}
}
activeTransactionContext.set(null);
} catch (Exception e) {
throw new XAException(XAException.XA_RBCOMMFAIL);
} finally {
try {
conn.close();
/* We must always return connections to the pool,
or we'd eventually run out. */
} catch (SQLException e) {
getLogger().log(e, LOG_CHANNEL, Logger.ERROR);
}
}
}
/**
* Inform the resource manager to roll back work done on behalf of a
* transaction branch.
*/
public void rollback(Xid xid) throws XAException {
getLogger().log(
"rollback() for thread " + Thread.currentThread() + ", removing from map",
LOG_CHANNEL,
Logger.DEBUG);
TransactionId id = getActiveTransactionContext();
if (id == null) {
getLogger().log("No transaction associated with current thread, can't rollback", LOG_CHANNEL, Logger.ERROR);
throw new XAException(XAException.XAER_NOTA);
}
Connection conn = id.connection;
if (conn == null) {
getLogger().log(
"rollback(): No connection in connectionMap for id \"" + id + "\"",
LOG_CHANNEL,
Logger.ERROR);
throw new XAException(XAException.XAER_NOTA);
}
try {
if (!tmCommits) {
conn.rollback();
}
activeTransactionContext.set(null);
} catch (Exception e) {
throw new XAException(XAException.XA_HEURCOM);
} finally {
try {
conn.close();
/* We must always return connections to the pool,
or we'd eventually run out. */
} catch (SQLException e) {
getLogger().log(e, LOG_CHANNEL, Logger.ERROR);
}
}
}
/**
* Start work on behalf of a transaction branch specified in xid.
*/
public void start(Xid xid, int flags) throws XAException {
getLogger().log("start(): beginning transaction with xid " + xid, LOG_CHANNEL, Logger.DEBUG);
TransactionId id = getActiveTransactionContext();
switch (flags) {
case XAResource.TMNOFLAGS :
if (id != null)
throw new XAException(XAException.XAER_INVAL);
try {
id = new TransactionId(xid, TX_IDLE);
} catch (SQLException e) {
throw new XAException(XAException.XAER_RMFAIL); // XXX or is it an error?
}
getLogger().log("start(): adding to map for " + Thread.currentThread(), LOG_CHANNEL, Logger.DEBUG);
activeTransactionContext.set(id);
break;
case XAResource.TMJOIN :
getLogger().log(
"TMJOIN for transaction in thread: " + Thread.currentThread(),
LOG_CHANNEL,
Logger.DEBUG);
if (id == null)
throw new XAException(XAException.XAER_NOTA);
break;
case XAResource.TMRESUME :
getLogger().log(
"TMRESUME for transaction in thread: " + Thread.currentThread(),
LOG_CHANNEL,
Logger.DEBUG);
if (id == null)
throw new XAException(XAException.XAER_NOTA);
if (id.status != TX_SUSPENDED)
throw new XAException(XAException.XAER_INVAL);
id.status = TX_IDLE;
break;
}
}
// ----------------------------------------------- NodeStore Implementation
/**
* Retrieve an object.
*
* @param uri Uri of the object we want to retrieve
* @exception ServiceAccessException Error accessing the Service
* @exception ObjectNotFoundException The object to retrieve was not found
*/
public ObjectNode retrieveObject(Uri uri) throws ServiceAccessException, ObjectNotFoundException {
if (getActiveTransactionContext() == null) {
Connection connection = null;
try {
connection = getNewConnection();
return adapter.retrieveObject(connection, uri);
} catch (SQLException e) {
throw new ServiceAccessException(this, e);
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
getLogger().log(e, LOG_CHANNEL, Logger.WARNING);
}
}
}
} else {
return adapter.retrieveObject(getCurrentConnection(), uri);
}
}
/**
* Update an object.
*
* @param object Object to update
* @exception ServiceAccessException Error accessing the Service
* @exception ObjectNotFoundException The object to update was not found
*/
public void storeObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectNotFoundException {
adapter.storeObject(getCurrentConnection(), uri, object);
}
/**
* Create a new object.
*
* @param object ObjectNode
* @param uri Uri of the object we want to create
* @exception ServiceAccessException Error accessing the Service
* @exception ObjectAlreadyExistsException An object already exists
* at this Uri
*/
public void createObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectAlreadyExistsException {
adapter.createObject(getCurrentConnection(), uri, object);
}
/**
* Remove an object.
*
* @param object Object to remove
* @exception ServiceAccessException Error accessing the Service
* @exception ObjectNotFoundException The object to remove was not found
*/
public void removeObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectNotFoundException {
adapter.removeObject(getCurrentConnection(), uri, object);
}
// ------------------------------------------- SecurityStore Implementation
/**
* Grant a new permission.
*
* @param permission Permission we want to create
* @exception ServiceAccessException Error accessing the Service
*/
public void grantPermission(Uri uri, NodePermission permission) throws ServiceAccessException {
adapter.grantPermission(getCurrentConnection(), uri, permission);
}
/**
* Revoke a permission.
*
* @param permission Permission we want to create
* @exception ServiceAccessException Error accessing the Service
*/
public void revokePermission(Uri uri, NodePermission permission) throws ServiceAccessException {
adapter.revokePermission(getCurrentConnection(), uri, permission);
}
/**
* Revoke all the permissions on an object.
*
* @param permission Permission we want to create
* @exception ServiceAccessException Error accessing the Service
*/
public void revokePermissions(Uri uri) throws ServiceAccessException {
adapter.revokePermissions(getCurrentConnection(), uri);
}
/**
* Enumerate permissions on an object.
*
* @param permission Permission we want to create
* @exception ServiceAccessException Error accessing the Service
*/
public Enumeration enumeratePermissions(Uri uri) throws ServiceAccessException {
if (getActiveTransactionContext() == null) {
Connection connection = null;
try {
connection = getNewConnection();
return adapter.enumeratePermissions(connection, uri);
} catch (SQLException e) {
throw new ServiceAccessException(this, e);
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
getLogger().log(e, LOG_CHANNEL, Logger.WARNING);
}
}
}
} else {
return adapter.enumeratePermissions(getCurrentConnection(), uri);
}
}
// ----------------------------------------------- LockStore Implementation
/**
* Create a new lock.
*
* @param lock Lock token
* @exception ServiceAccessException Service access error
*/
public void putLock(Uri uri, NodeLock lock) throws ServiceAccessException {
adapter.putLock(getCurrentConnection(), uri, lock);
}
/**
* Refresh a lock.
*
* @param lock the lock to renew
* @exception ServiceAccessException Service access error
* @exception LockTokenNotFoundException Lock token was not found
*/
public void renewLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException {
adapter.renewLock(getCurrentConnection(), uri, lock);
}
/**
* Unlock.
*
* @param lock Token to remove
* @exception ServiceAccessException Service access error
* @exception LockTokenNotFoundException Lock token was not found
*/
public void removeLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException {
adapter.removeLock(getCurrentConnection(), uri, lock);
}
/**
* Kill a lock.
*
* @param lock Token to remove
* @exception ServiceAccessException Service access error
* @exception LockTokenNotFoundException Lock token was not found
*/
public void killLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException {
adapter.killLock(getCurrentConnection(), uri, lock);
}
/**
* Enumerate locks on an object.
*
* @param subject Subject
* @return Enumeration List of locks which have been put on the subject
* @exception ServiceAccessException Service access error
*/
public Enumeration enumerateLocks(Uri uri) throws ServiceAccessException {
if (getActiveTransactionContext() == null) {
Connection connection = null;
try {
connection = getNewConnection();
return adapter.enumerateLocks(connection, uri);
} catch (SQLException e) {
throw new ServiceAccessException(this, e);
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
getLogger().log(e, LOG_CHANNEL, Logger.WARNING);
}
}
}
} else {
return adapter.enumerateLocks(getCurrentConnection(), uri);
}
}
// -------------------------------- RevisionDescriptorsStore Implementation
/**
* Retrieve the revisions informations of an object.
*
* @param uri Uri
* @exception ServiceAccessException Service access error
* @exception RevisionDescriptorNotFoundException Revision descriptor
* was not found
*/
public NodeRevisionDescriptors retrieveRevisionDescriptors(Uri uri)
throws ServiceAccessException, RevisionDescriptorNotFoundException {
if (getActiveTransactionContext() == null) {
Connection connection = null;
try {
connection = getNewConnection();
return adapter.retrieveRevisionDescriptors(connection, uri);
} catch (SQLException e) {
throw new ServiceAccessException(this, e);
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
getLogger().log(e, LOG_CHANNEL, Logger.WARNING);
}
}
}
} else {
return adapter.retrieveRevisionDescriptors(getCurrentConnection(), uri);
}
}
/**
* Create a new revision information object.
*
* @param uri Uri
* @param revisionDescriptors Node revision descriptors
* @exception ServiceAccessException Service access error
*/
public void createRevisionDescriptors(Uri uri, NodeRevisionDescriptors revisionDescriptors)
throws ServiceAccessException {
adapter.createRevisionDescriptors(getCurrentConnection(), uri, revisionDescriptors);
}
/**
* Update revision information.
*
* @param uri Uri
* @param revisionDescriptors Node revision descriptors
* @exception ServiceAccessException Service access error
* @exception RevisionDescriptorNotFoundException Revision descriptor
* was not found
*/
public void storeRevisionDescriptors(Uri uri, NodeRevisionDescriptors revisionDescriptors)
throws ServiceAccessException, RevisionDescriptorNotFoundException {
adapter.storeRevisionDescriptors(getCurrentConnection(), uri, revisionDescriptors);
}
/**
* Remove revision information.
*
* @param uri Uri
* @exception ServiceAccessException Service access error
*/
public void removeRevisionDescriptors(Uri uri) throws ServiceAccessException {
adapter.removeRevisionDescriptors(getCurrentConnection(), uri);
}
// --------------------------------- RevisionDescriptorStore Implementation
/**
* Retrieve an individual object's revision descriptor.
*
* @param Uri uri
* @param revisionNumber Node revision number
*/
public NodeRevisionDescriptor retrieveRevisionDescriptor(Uri uri, NodeRevisionNumber revisionNumber)
throws ServiceAccessException, RevisionDescriptorNotFoundException {
if (getActiveTransactionContext() == null) {
Connection connection = null;
try {
connection = getNewConnection();
return adapter.retrieveRevisionDescriptor(connection, uri, revisionNumber);
} catch (SQLException e) {
throw new ServiceAccessException(this, e);
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
getLogger().log(e, LOG_CHANNEL, Logger.WARNING);
}
}
}
} else {
return adapter.retrieveRevisionDescriptor(getCurrentConnection(), uri, revisionNumber);
}
}
/**
* Create a new revision descriptor.
*
* @param uri Uri
* @param revisionDescriptor Node revision descriptor
* @exception ServiceAccessException Service access error
*/
public void createRevisionDescriptor(Uri uri, NodeRevisionDescriptor revisionDescriptor)
throws ServiceAccessException {
adapter.createRevisionDescriptor(getCurrentConnection(), uri, revisionDescriptor);
}
/**
* Update a revision descriptor.
*
* @param uri Uri
* @param revisionDescriptors Node revision descriptor
* @exception ServiceAccessException Service access error
* @exception RevisionDescriptorNotFoundException Revision descriptor
* was not found
*/
public void storeRevisionDescriptor(Uri uri, NodeRevisionDescriptor revisionDescriptor)
throws ServiceAccessException, RevisionDescriptorNotFoundException {
adapter.storeRevisionDescriptor(getCurrentConnection(), uri, revisionDescriptor);
}
/**
* Remove a revision descriptor.
*
* @param uri Uri
* @param revisionNumber Revision number
* @exception ServiceAccessException Service access error
*/
public void removeRevisionDescriptor(Uri uri, NodeRevisionNumber revisionNumber) throws ServiceAccessException {
adapter.removeRevisionDescriptor(getCurrentConnection(), uri, revisionNumber);
}
// -------------------------------------------- ContentStore Implementation
/**
* Retrieve revision content.
*
* @param uri Uri
* @param revisionNumber Node revision number
*/
public NodeRevisionContent retrieveRevisionContent(Uri uri, NodeRevisionDescriptor revisionDescriptor)
throws ServiceAccessException, RevisionNotFoundException {
if (getActiveTransactionContext() == null) {
Connection connection = null;
try {
connection = getNewConnection();
return adapter.retrieveRevisionContent(connection, uri, revisionDescriptor, true);
} catch (SQLException e) {
throw new ServiceAccessException(this, e);
} finally {
// will be done in adapter or upon closing of stream
/*
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
getLogger().log(e, LOG_CHANNEL, Logger.WARNING);
}
}
*/
}
} else {
return adapter.retrieveRevisionContent(getCurrentConnection(), uri, revisionDescriptor, false);
}
}
/**
* Create a new revision
*
* @param uri Uri
* @param revisionDescriptor Node revision descriptor
* @param revisionContent Node revision content
*/
public void createRevisionContent(
Uri uri,
NodeRevisionDescriptor revisionDescriptor,
NodeRevisionContent revisionContent)
throws ServiceAccessException, RevisionAlreadyExistException {
adapter.createRevisionContent(getCurrentConnection(), uri, revisionDescriptor, revisionContent);
}
/**
* Modify the latest revision of an object.
*
* @param uri Uri
* @param revisionDescriptor Node revision descriptor
* @param revisionContent Node revision content
*/
public void storeRevisionContent(
Uri uri,
NodeRevisionDescriptor revisionDescriptor,
NodeRevisionContent revisionContent)
throws ServiceAccessException, RevisionNotFoundException {
adapter.storeRevisionContent(getCurrentConnection(), uri, revisionDescriptor, revisionContent);
}
/**
* Remove revision.
*
* @param uri Uri
* @param revisionNumber Node revision number
*/
public void removeRevisionContent(Uri uri, NodeRevisionDescriptor revisionDescriptor)
throws ServiceAccessException {
adapter.removeRevisionContent(getCurrentConnection(), uri, revisionDescriptor);
}
// ------------------------------------------------------ Protected Methods
/**
* Get the Connection object associated with the current transaction.
*/
protected Connection getCurrentConnection() throws ServiceAccessException {
getLogger().log("Getting current connection for thread " + Thread.currentThread(), LOG_CHANNEL, Logger.DEBUG);
TransactionId id = getActiveTransactionContext();
if (id == null) {
getLogger().log("No id for current thread - called outside transaction?", LOG_CHANNEL, Logger.DEBUG);
return null;
}
return id.connection;
}
protected TransactionId getActiveTransactionContext() {
Object txId = activeTransactionContext.get();
return (TransactionId) txId;
}
abstract protected Connection getNewConnection() throws SQLException;
// ---------------------------------------------------------- Inner Classes
private class TransactionId {
Xid xid;
int status;
boolean rollbackOnly;
Connection connection;
TransactionId(Xid xid, int status) throws SQLException {
this.xid = xid;
this.status = status;
this.rollbackOnly = false;
connection = getNewConnection();
}
}
}