Vector done;
Enumeration enumeration;
ObjectEntry entry;
if ( _status == Status.STATUS_MARKED_ROLLBACK )
throw new TransactionAbortedException( "persist.markedRollback" );
if ( _status != Status.STATUS_ACTIVE )
throw new IllegalStateException( Messages.message( "persist.noTransaction" ) );
try {
// No objects in this transaction -- this is a read only transaction
// Put it into the try block to close connections
if ( _objects.size() == 0 ) {
_status = Status.STATUS_PREPARED;
return false;
}
done = new Vector();
while ( _objects.size() != done.size() ) {
todo = new Vector();
enumeration = _objects.elements();
while ( enumeration.hasMoreElements() ) {
entry = (ObjectEntry) enumeration.nextElement();
if ( ! done.contains( entry ) ) {
todo.addElement( entry );
}
}
enumeration = todo.elements();
while ( enumeration.hasMoreElements() ) {
entry = (ObjectEntry) enumeration.nextElement();
if ( !entry.deleted && !entry.creating ) {
ClassMolder molder;
Object identities;
OID oid;
oid = entry.engine.preStore( this, entry.oid, entry.object, _lockTimeout );
if ( oid != null ) {
entry.oid = oid;
entry.updateCacheNeeded = true;
}
}
done.addElement( entry );
}
}
// preStore will actually walk all existing object and it might marked
// some object to be created (and to be removed).
// Because some objects contains foreign key are key generated, such
// object should be created after some other. We iterate all objects and
// creating object according the priority.
int priority = 0;
int nextPrior = 0;
for ( boolean nextCreate=true; nextCreate; priority=nextPrior ) {
enumeration = _objects.elements();
nextCreate = false;
while ( enumeration.hasMoreElements() ) {
ObjectEntry enumEntry = (ObjectEntry) enumeration.nextElement();
try {
if ( enumEntry.creating && !enumEntry.deleted && !enumEntry.created ) {
if ( enumEntry.molder.getPriority() <= priority ) {
if ( _callback != null ) {
_callback.creating( enumEntry.object, _db );
} else if ( enumEntry.molder.getCallback() != null ) {
enumEntry.molder.getCallback().creating( enumEntry.object, _db );
}
// Must perform creation after object is recorded in transaction
// to prevent circular references.
OID oid = enumEntry.engine.create
( this, enumEntry.oid, enumEntry.object );
if ( oid.getIdentity() == null )
throw new IllegalStateException("oid.getIdentity() is null after create!");
// rehash the object entry, in case of oid changed
entry = rehash( enumEntry.object, oid );
entry.created = true;
// | entry.updateCacheNeeded = true;
if ( _callback != null ) {
_callback.using( entry.object, _db );
_callback.created( entry.object );
} else if ( enumEntry.molder.getCallback() != null ) {
enumEntry.molder.getCallback().using( entry.object, _db );
enumEntry.molder.getCallback().created( entry.object );
}
} else {
nextPrior = Math.min( priority+1, enumEntry.molder.getPriority() );
nextCreate = true;
}
}
} catch ( Exception except ) {
if ( _callback != null ) {
_callback.releasing( enumEntry.object, false );
} else if ( enumEntry.molder.getCallback() != null ) {
enumEntry.molder.getCallback().releasing( enumEntry.object, false );
}
removeObjectEntry( enumEntry.object );
if ( except instanceof DuplicateIdentityException )
throw (DuplicateIdentityException) except;
if ( except instanceof PersistenceException )
throw (PersistenceException) except;
throw new PersistenceException( Messages.format("persist.nested",except) );
}
}
}
// Process all modified objects
enumeration = _objects.elements();
while ( enumeration.hasMoreElements() ) {
entry = (ObjectEntry) enumeration.nextElement();
if ( !entry.deleted && !entry.creating && entry.updatePersistNeeded )
entry.engine.store( this, entry.oid, entry.object );
if ( !entry.deleted && !entry.creating && entry.updateCacheNeeded )
entry.engine.softLock( this, entry.oid, _lockTimeout );
// do the callback
if ( !entry.deleted && _callback != null ) {
try {
_callback.storing( entry.object, entry.updateCacheNeeded );
} catch ( Exception except ) {
throw new TransactionAbortedException(
Messages.format("persist.nested", except), except );
}
} else if ( !entry.deleted && entry.molder.getCallback() != null ) {
try {
entry.molder.getCallback().storing( entry.object, entry.updateCacheNeeded );
// updatePersistNeeded implies updateCacheNeeded
} catch ( Exception except ) {
throw new TransactionAbortedException(
Messages.format("persist.nested", except), except );
}
}
}
_status = Status.STATUS_PREPARING;
// patch for bug 973 Dependent order deletion problem
// Search maximum priority in _deletedList
entry = _deletedList;
int maxPriority = 0;
while ( entry != null ) {
maxPriority = Math.max(maxPriority, entry.molder.getPriority());
entry = entry.nextDeleted;
}
// Process all deleted objects last in FIFO order.
// Take priority into account
for (int i = maxPriority; i >= 0;i--) {
entry = _deletedList;
while ( entry != null ) {
if (entry.molder.getPriority() == i) {
entry.engine.delete( this, entry.oid );
}
entry = entry.nextDeleted;
}
}
_deletedList = null;
_status = Status.STATUS_PREPARED;
return true;
} catch ( Exception except ) {
_status = Status.STATUS_MARKED_ROLLBACK;
if ( except instanceof TransactionAbortedException )
throw (TransactionAbortedException) except;
// Any error is reported as transaction aborted
throw new TransactionAbortedException( Messages.format("persist.nested", except), except );
}
}