use of org.datanucleus.exceptions.TransactionActiveOnCloseException in project datanucleus-core by datanucleus.
the class ExecutionContextImpl method close.
/**
* Method to close the context.
*/
public void close() {
if (closed) {
throw new NucleusUserException(Localiser.msg("010002"));
}
if (tx.getIsActive()) {
String closeActionTxAction = nucCtx.getConfiguration().getStringProperty(PropertyNames.PROPERTY_EXECUTION_CONTEXT_CLOSE_ACTIVE_TX_ACTION);
if (closeActionTxAction != null) {
if (closeActionTxAction.equalsIgnoreCase("exception")) {
throw new TransactionActiveOnCloseException(this);
} else if (closeActionTxAction.equalsIgnoreCase("rollback")) {
NucleusLogger.GENERAL.warn("ExecutionContext closed with active transaction, so rolling back the active transaction");
tx.rollback();
}
}
}
// Commit any outstanding non-tx updates
if (!dirtyOPs.isEmpty() && tx.getNontransactionalWrite()) {
if (isNonTxAtomic()) {
// TODO Remove this when all mutator operations handle it atomically
// Process as nontransactional update
processNontransactionalUpdate();
} else {
// Process within a transaction
try {
tx.begin();
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
}
}
if (properties.getFrequentProperties().getDetachOnClose() && cache != null && !cache.isEmpty()) {
// "Detach-on-Close", detaching all currently cached objects
// TODO This will remove objects from the L1 cache one-by-one. Is there a possibility for optimisation? See also AttachDetachTest.testDetachOnClose
NucleusLogger.PERSISTENCE.debug(Localiser.msg("010011"));
List<ObjectProvider> toDetach = new ArrayList<>(cache.values());
try {
if (!tx.getNontransactionalRead()) {
tx.begin();
}
for (ObjectProvider op : toDetach) {
if (op != null && op.getObject() != null && !op.getExecutionContext().getApiAdapter().isDeleted(op.getObject()) && op.getExternalObjectId() != null) {
// If the object is deleted then no point detaching. An object can be in L1 cache if transient and passed in to a query as a param for example
try {
op.detach(new DetachState(getApiAdapter()));
} catch (NucleusObjectNotFoundException onfe) {
// Catch exceptions for any objects that are deleted in other managers whilst having this open
}
}
}
if (!tx.getNontransactionalRead()) {
tx.commit();
}
} finally {
if (!tx.getNontransactionalRead()) {
if (tx.isActive()) {
tx.rollback();
}
}
}
NucleusLogger.PERSISTENCE.debug(Localiser.msg("010012"));
}
// Call all listeners to do their clean up TODO Why is this here and not after "disconnect remaining resources" or before "detachOnClose"?
ExecutionContext.LifecycleListener[] listener = nucCtx.getExecutionContextListeners();
for (int i = 0; i < listener.length; i++) {
listener[i].preClose(this);
}
closing = true;
// Disconnect remaining resources
if (cache != null && !cache.isEmpty()) {
// Clear out the cache (use separate list since sm.disconnect will remove the object from "cache" so we avoid any ConcurrentModification issues)
Collection<ObjectProvider> cachedOPsClone = new HashSet<>(cache.values());
for (ObjectProvider op : cachedOPsClone) {
if (op != null) {
// Remove it from any transaction
op.disconnect();
} else {
NucleusLogger.CACHE.error(">> EC.close L1Cache op IS NULL!");
}
}
cache.clear();
if (NucleusLogger.CACHE.isDebugEnabled()) {
NucleusLogger.CACHE.debug(Localiser.msg("003011"));
}
} else {
// TODO If there is no cache we need a way for ObjectProviders to be disconnected; have ObjectProvider as listener for EC close? (ecListeners below)
}
// Clear out lifecycle listeners that were registered
closeCallbackHandler();
if (ecListeners != null) {
// Inform all interested parties that we are about to close
Set<ExecutionContextListener> listeners = new HashSet<>(ecListeners);
for (ExecutionContextListener lstr : listeners) {
lstr.executionContextClosing(this);
}
ecListeners.clear();
ecListeners = null;
}
// Reset the Fetch Plan to its DFG setting
fetchPlan.clearGroups().addGroup(FetchPlan.DEFAULT);
if (statistics != null) {
statistics.close();
statistics = null;
}
enlistedOPCache.clear();
dirtyOPs.clear();
indirectDirtyOPs.clear();
if (nontxProcessedOPs != null) {
nontxProcessedOPs.clear();
nontxProcessedOPs = null;
}
if (managedRelationsHandler != null) {
managedRelationsHandler.clear();
}
if (l2CacheTxIds != null) {
l2CacheTxIds.clear();
}
if (l2CacheTxFieldsToUpdateById != null) {
l2CacheTxFieldsToUpdateById.clear();
}
if (pbrAtCommitHandler != null) {
pbrAtCommitHandler.clear();
}
if (opEmbeddedInfoByOwner != null) {
opEmbeddedInfoByOwner.clear();
opEmbeddedInfoByOwner = null;
}
if (opEmbeddedInfoByEmbedded != null) {
opEmbeddedInfoByEmbedded.clear();
opEmbeddedInfoByEmbedded = null;
}
if (opAssociatedValuesMapByOP != null) {
opAssociatedValuesMapByOP.clear();
opAssociatedValuesMapByOP = null;
}
l2CacheObjectsToEvictUponRollback = null;
closing = false;
closed = true;
// Close the transaction
tx.close();
tx = null;
owner = null;
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("010001", this));
}
// Hand back to the pool for reuse
nucCtx.getExecutionContextPool().checkIn(this);
}
use of org.datanucleus.exceptions.TransactionActiveOnCloseException in project datanucleus-api-jdo by datanucleus.
the class JDOPersistenceManager method internalClose.
/**
* The internal method called by the PMF to cleanup this PM. Called from PMF.releasePersistenceManager().
*/
protected void internalClose() {
if (closed) {
return;
}
try {
// Close the ExecutionContext
ec.close();
} catch (TransactionActiveOnCloseException tae) {
throw new JDOUserException(tae.getMessage(), this);
} catch (NucleusException ne) {
throw NucleusJDOHelper.getJDOExceptionForNucleusException(ne);
}
userObject = null;
userObjectMap = null;
fetchPlan = null;
jdoFetchGroups = null;
jdotx = null;
ec = null;
pmf = null;
closed = true;
}
use of org.datanucleus.exceptions.TransactionActiveOnCloseException in project datanucleus-api-jdo by datanucleus.
the class JDOPersistenceManagerFactory method close.
/**
* Close this PersistenceManagerFactory. Check for JDOPermission("closePersistenceManagerFactory") and if not authorized, throw SecurityException.
* <P>If the authorization check succeeds, check to see that all PersistenceManager instances obtained
* from this PersistenceManagerFactory have no active transactions. If any PersistenceManager instances
* have an active transaction, throw a JDOUserException, with one nested JDOUserException for each
* PersistenceManager with an active Transaction.
* <P>If there are no active transactions, then close all PersistenceManager instances obtained from
* this PersistenceManagerFactory, mark this PersistenceManagerFactory as closed, disallow
* getPersistenceManager methods, and allow all other get methods. If a set method or getPersistenceManager
* method is called after close, then JDOUserException is thrown.
* @see javax.jdo.PersistenceManagerFactory#close()
*/
public synchronized void close() {
checkJDOPermission(JDOPermission.CLOSE_PERSISTENCE_MANAGER_FACTORY);
if (isClosed()) {
return;
}
setIsNotConfigurable();
// Check there are no active transactions before closing any PM
Set<JDOUserException> exceptions = new HashSet<JDOUserException>();
for (JDOPersistenceManager pm : pmCache) {
ExecutionContext ec = pm.getExecutionContext();
if (ec.getTransaction().isActive()) {
// Note: we replicate the exception that would have come from pm.close() when tx active
TransactionActiveOnCloseException tae = new TransactionActiveOnCloseException(ec);
exceptions.add(new JDOUserException(tae.getMessage(), pm));
}
}
if (!exceptions.isEmpty()) {
throw new JDOUserException(Localiser.msg("012002"), exceptions.toArray(new Throwable[exceptions.size()]));
}
// Close all PMs
for (JDOPersistenceManager pm : pmCache) {
pm.internalClose();
}
pmCache.clear();
if (pmfByName != null) {
// Closing so clean out from singleton pattern handler
Iterator<Map.Entry<String, JDOPersistenceManagerFactory>> pmfIter = pmfByName.entrySet().iterator();
while (pmfIter.hasNext()) {
Map.Entry<String, JDOPersistenceManagerFactory> entry = pmfIter.next();
if (entry.getValue() == this) {
pmfIter.remove();
break;
}
}
}
if (sequenceByFactoryClass != null) {
sequenceByFactoryClass.clear();
sequenceByFactoryClass = null;
}
if (lifecycleListeners != null) {
lifecycleListeners.clear();
lifecycleListeners = null;
}
if (datastoreCache != null) {
datastoreCache.evictAll();
datastoreCache = null;
}
if (queryCache != null) {
queryCache.evictAll();
queryCache = null;
}
if (jdoFetchGroups != null) {
jdoFetchGroups.clear();
jdoFetchGroups = null;
}
nucleusContext.close();
active = false;
closed = true;
}
Aggregations