Search in sources :

Example 1 with TransactionActiveOnCloseException

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);
}
Also used : NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ArrayList(java.util.ArrayList) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) TransactionActiveOnCloseException(org.datanucleus.exceptions.TransactionActiveOnCloseException) ObjectProvider(org.datanucleus.state.ObjectProvider) HashSet(java.util.HashSet)

Example 2 with TransactionActiveOnCloseException

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;
}
Also used : NucleusException(org.datanucleus.exceptions.NucleusException) JDOUserException(javax.jdo.JDOUserException) TransactionActiveOnCloseException(org.datanucleus.exceptions.TransactionActiveOnCloseException)

Example 3 with TransactionActiveOnCloseException

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;
}
Also used : JDOUserException(javax.jdo.JDOUserException) TransactionActiveOnCloseException(org.datanucleus.exceptions.TransactionActiveOnCloseException) ExecutionContext(org.datanucleus.ExecutionContext) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) HashSet(java.util.HashSet)

Aggregations

TransactionActiveOnCloseException (org.datanucleus.exceptions.TransactionActiveOnCloseException)3 HashSet (java.util.HashSet)2 JDOUserException (javax.jdo.JDOUserException)2 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 ExecutionContext (org.datanucleus.ExecutionContext)1 NucleusException (org.datanucleus.exceptions.NucleusException)1 NucleusObjectNotFoundException (org.datanucleus.exceptions.NucleusObjectNotFoundException)1 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)1 ObjectProvider (org.datanucleus.state.ObjectProvider)1