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));
}
}