protected void flush()

in openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java [2217:2358]


    protected void flush(int reason) {
        // this will enlist proxied states as necessary so we know whether we
        // have anything to flush
        Collection transactional = getTransactionalStates();

        // do we actually have to flush?  only if our flags say so, or if
        // we have transaction listeners that need to be invoked for commit
        // (no need to invoke them on inc flush if nothing is dirty).  we
        // special case the remote commit listener used by the datacache cause
        // we know it doesn't require the commit event when nothing changes
        boolean flush = (_flags & FLAG_FLUSH_REQUIRED) != 0;
        boolean listeners = (_transEventManager.hasFlushListeners()
            || _transEventManager.hasEndListeners())
            && ((_flags & FLAG_REMOTE_LISTENER) == 0
            || _transEventManager.getListeners().size() > 1);
        if (!flush && (reason != FLUSH_COMMIT || !listeners))
            return;

        Collection mobjs = null;
        _flags |= FLAG_PRESTORING;
        try {
            if (flush) {
                // call pre store on all currently transactional objs
                for (Object o : transactional) {
                    ((StateManagerImpl) o).beforeFlush(reason, _call);
                }
                flushAdditions(transactional, reason);
            }

            // hopefully now all dependent instances that are going to end
            // up referenced have been marked as such; delete unrefed
            // dependents
            _flags |= FLAG_DEREFDELETING;
            if (flush && _derefCache != null && !_derefCache.isEmpty()) {
                // mark for delete all elements in deref, otherwise in some situations it
                // throws ConcurrentModificationException
                Set<StateManagerImpl> statesMarkedForDelete = new HashSet<>(_derefCache);
                for (StateManagerImpl state: statesMarkedForDelete) {
                    deleteDeref(state);
                }

                flushAdditions(transactional, reason);
            }

            if (reason != FLUSH_LOGICAL) {
                // if no datastore transaction, start one; even if we don't
                // think we'll need to flush at this point, our transaction
                // listeners might introduce some dirty objects or interact
                // directly with the database
                if ((_flags & FLAG_STORE_ACTIVE) == 0)
                    beginStoreManagerTransaction(false);

                if ((_transEventManager.hasFlushListeners()
                    || _transEventManager.hasEndListeners())
                    && (flush || reason == FLUSH_COMMIT)) {
                    // fire events
                    mobjs = new ManagedObjectCollection(transactional);
                    if (reason == FLUSH_COMMIT
                        && _transEventManager.hasEndListeners()) {
                        fireTransactionEvent(new TransactionEvent(this,
                            TransactionEvent.BEFORE_COMMIT, mobjs,
                            _persistedClss, _updatedClss, _deletedClss));

                        flushAdditions(transactional, reason);
                        flush = (_flags & FLAG_FLUSH_REQUIRED) != 0;
                    }

                    if (flush && _transEventManager.hasFlushListeners()) {
                        fireTransactionEvent(new TransactionEvent(this,
                            TransactionEvent.BEFORE_FLUSH, mobjs,
                            _persistedClss, _updatedClss, _deletedClss));
                        flushAdditions(transactional, reason);
                    }
                }
            }
        }
        finally {
            _flags &= ~FLAG_PRESTORING;
            _flags &= ~FLAG_DEREFDELETING;
            _transAdditions = null;
            _derefAdditions = null;

            // also clear derefed set; the deletes have been recorded
            if (_derefCache != null)
                _derefCache = null;
        }

        // flush to store manager
        List<Exception> exceps = null;
        try {
            if (flush && reason != FLUSH_LOGICAL) {
                _flags |= FLAG_STORE_FLUSHING;
                exceps = add(exceps,
                    newFlushException(_store.flush(transactional)));
            }
        } finally {
            _flags &= ~FLAG_STORE_FLUSHING;

            if (reason == FLUSH_ROLLBACK)
                exceps = add(exceps, endStoreManagerTransaction(true));
            else if (reason != FLUSH_LOGICAL)
                _flags &= ~FLAG_FLUSH_REQUIRED;

            // mark states as flushed
            if (flush) {
                StateManagerImpl sm;
                for (Object o : transactional) {
                    sm = (StateManagerImpl) o;
                    try {
                        // the state may have become transient, such as if
                        // it is embedded and the owner has been deleted during
                        // this flush process; bug #1100
                        if (sm.getPCState() == PCState.TRANSIENT)
                            continue;

                        sm.afterFlush(reason);
                        if (reason == FLUSH_INC) {
                            // if not about to clear trans cache for commit
                            // anyway, re-cache dirty objects with default soft
                            // refs; we don't need hard refs now that the
                            // changes have been flushed
                            sm.proxyFields(true, false);
                            _transCache.flushed(sm);
                        }
                    }
                    catch (Exception e) {
                        exceps = add(exceps, e);
                    }
                }
            }
        }

        // throw any exceptions to shortcut listeners on fail
        throwNestedExceptions(exceps, true);

        if (flush && reason != FLUSH_ROLLBACK && reason != FLUSH_LOGICAL
            && _transEventManager.hasFlushListeners()) {
            fireTransactionEvent(new TransactionEvent(this,
                TransactionEvent.AFTER_FLUSH, mobjs, _persistedClss,
                _updatedClss, _deletedClss));
        }
    }