if ( objectTimestamp > 0 && oid.getIdentity() != null ) {
// valid range of timestamp
if ((_timeStampable) && (lockTimestamp == TimeStampable.NO_TIMESTAMP)) {
_log.warn (Messages.format("persist.objectNotInCache", _name, oid.getIdentity()));
throw new PersistenceException (Messages.format("persist.objectNotInCache", _name, oid.getIdentity()));
}
if ( _timeStampable && objectTimestamp != lockTimestamp )
throw new ObjectModifiedException("Timestamp mismatched!");
if ( !_timeStampable && isDependent() && fields == null ) {
// allow a dependent object not implements timeStampable
fields = new Object[_fhs.length];
Connection conn = (Connection)tx.getConnection(oid.getLockEngine());
stamp = _persistence.load( conn, fields, oid.getIdentity(), accessMode );
oid.setDbLock( accessMode == AccessMode.DbLocked );
locker.setObject( tx, fields );
}
// load the original field into the transaction. so, store will
// have something to compare later.
try {
for ( int i=0; i <_fhs.length; i++ ) {
fieldType = _fhs[i].getFieldType();
switch (fieldType) {
case FieldMolder.PRIMITIVE:
break;
case FieldMolder.SERIALIZABLE:
break;
case FieldMolder.PERSISTANCECAPABLE:
fieldClassMolder = _fhs[i].getFieldClassMolder();
fieldEngine = _fhs[i].getFieldLockEngine();
o = _fhs[i].getValue( object, tx.getClassLoader() );
if ( _fhs[i].isDependent() ) {
// depedent class won't have persistenceInfo in LockEngine
// must look at fieldMolder for it
if ( o != null && !tx.isRecorded(o) )
tx.markUpdate( fieldEngine, fieldClassMolder, o, oid );
// load the cached dependent object from the data store.
// The loaded will be compared with the new one
if ( fields[i] != null )
tx.load( fieldEngine, fieldClassMolder, fields[i], null, suggestedAccessMode );
} else if ( tx.isAutoStore() ) {
if ( o != null && !tx.isRecorded(o) )
tx.markUpdate( fieldEngine, fieldClassMolder, o, null );
if ( fields[i] != null )
tx.load( fieldEngine, fieldClassMolder, fields[i], null, suggestedAccessMode );
}
break;
case FieldMolder.ONE_TO_MANY:
fieldClassMolder = _fhs[i].getFieldClassMolder();
fieldEngine = _fhs[i].getFieldLockEngine();
if ( _fhs[i].isDependent() ) {
if ( !_fhs[i].isLazy() ) {
Iterator itor = getIterator( _fhs[i].getValue( object, tx.getClassLoader() ) );
ArrayList v = (ArrayList)fields[i];
ArrayList newSetOfIds = new ArrayList();
// iterate the collection of this data object field
while ( itor.hasNext() ) {
Object element = itor.next();
Object actualIdentity = fieldClassMolder.getActualIdentity( tx, element );
newSetOfIds.add( actualIdentity );
if ( v != null && v.contains( actualIdentity ) ) {
if ( !tx.isRecorded( element ) )
tx.markUpdate( fieldEngine, fieldClassMolder, element, oid );
} else {
/*
if ( !tx.isRecorded( element ) )
tx.markCreate( fieldEngine, fieldClassMolder, element, oid );
*/
}
}
if ( v != null ) {
for ( int j=0,l=v.size(); j<l; j++ ) {
if ( !newSetOfIds.contains( v.get(j) ) ) {
// load all the dependent object in cache for modification
// check at commit time.
tx.load( oid.getLockEngine(), fieldClassMolder, v.get(j), null, suggestedAccessMode );
}
}
}
} else {
// ArrayList avlist = (ArrayList) fields[i];
fieldClassMolder = _fhs[i].getFieldClassMolder();
fieldEngine = _fhs[i].getFieldLockEngine();
// RelationCollection relcol = new RelationCollection( tx, oid, fieldEngine, fieldClassMolder, accessMode, avlist );
}
} else if ( tx.isAutoStore() ) {
Iterator itor = getIterator( _fhs[i].getValue( object, tx.getClassLoader() ) );
ArrayList v = (ArrayList)fields[i];
ArrayList newSetOfIds = new ArrayList();
// iterate the collection of this data object field
while ( itor.hasNext() ) {
Object element = itor.next();
Object actualIdentity = fieldClassMolder.getActualIdentity( tx, element );
newSetOfIds.add( actualIdentity );
if ( v != null && v.contains( actualIdentity ) ) {
if ( !tx.isRecorded( element ) )
tx.markUpdate( fieldEngine, fieldClassMolder, element, null );
} else {
if ( !tx.isRecorded( element ) )
tx.markUpdate( fieldEngine, fieldClassMolder, element, null );
}
}
// load all old objects for comparison in the preStore state
if ( v != null ) {
for ( int j=0,l=v.size(); j<l; j++ ) {
if ( !newSetOfIds.contains( v.get(j) ) ) {
// load all the dependent object in cache for modification
// check at commit time.
tx.load( oid.getLockEngine(), fieldClassMolder, v.get(j), null, suggestedAccessMode );
}
}
}
}
break;
case FieldMolder.MANY_TO_MANY:
fieldClassMolder = _fhs[i].getFieldClassMolder();
fieldEngine = _fhs[i].getFieldLockEngine();
if ( tx.isAutoStore() ) {
Iterator itor = getIterator( _fhs[i].getValue( object, tx.getClassLoader() ) );
ArrayList v = (ArrayList)fields[i];
ArrayList newSetOfIds = new ArrayList();
// iterate the collection of this data object field
while ( itor.hasNext() ) {
Object element = itor.next();
Object actualIdentity = fieldClassMolder.getActualIdentity( tx, element );
newSetOfIds.add( actualIdentity );
if ( v != null && v.contains( actualIdentity ) ) {
if ( !tx.isRecorded( element ) )
tx.markUpdate( fieldEngine, fieldClassMolder, element, null );
} else {
if ( !tx.isRecorded( element ) )
tx.markUpdate( fieldEngine, fieldClassMolder, element, null );
}
}
// load all old objects for comparison in the preStore state
if ( v != null ) {
for ( int j=0,l=v.size(); j<l; j++ ) {
if ( !newSetOfIds.contains( v.get(j) ) ) {
// load all the dependent object in cache for modification
// check at commit time.
tx.load( oid.getLockEngine(), fieldClassMolder, v.get(j), null, suggestedAccessMode );
}
}
}
}
break;
}
}
} catch ( ObjectNotFoundException e ) {
e.printStackTrace();
throw new ObjectModifiedException("dependent object deleted concurrently");
}
return false;
} else if ( objectTimestamp == TimeStampable.NO_TIMESTAMP || objectTimestamp == 1 ) {
// work almost like create, except update the sub field instead of create
// iterate all the fields and mark all the dependent object.
boolean updateCache = false;
for ( int i=0; i<_fhs.length; i++ ) {
fieldType = _fhs[i].getFieldType();
switch (fieldType) {
case FieldMolder.PRIMITIVE:
case FieldMolder.SERIALIZABLE:
// nothing need to be done here for primitive
break;
case FieldMolder.PERSISTANCECAPABLE:
// create dependent object if exists
fieldClassMolder = _fhs[i].getFieldClassMolder();
fieldEngine = _fhs[i].getFieldLockEngine();
o = _fhs[i].getValue( object, tx.getClassLoader() );
if ( o != null ) {
if ( _fhs[i].isDependent() ) {
// creation of dependent object should be delayed to the
// preStore state.
// otherwise, in the case of keygenerator being used in both
// master and dependent object, and if an dependent
// object is replaced by another before commit, the
// orginial dependent object will not be removed.
//
// the only disadvantage for that appoarch is that an
// OQL Query will not able to include the newly generated
// dependent object.
if ( !tx.isRecorded( o ) ) {
tx.markCreate( fieldEngine, fieldClassMolder, o, oid );
if ( !_fhs[i].isStored() && fieldClassMolder._isKeyGenUsed ) {
updateCache = true;
}
} else {}
// fail-fast principle: if the object depend on another object,
// throw exception
// if ( !tx.isDepended( oid, o ) )
// throw new PersistenceException("Dependent object may not change its master. Object: "+o+" new master: "+oid);
} else if ( tx.isAutoStore() ) {
if ( !tx.isRecorded( o ) ) {
// related object should be created right the way, if autoStore
// is enabled, to obtain a database lock on the row. If both side
// uses keygenerator, the current object will be updated in the
// store state.
boolean creating = tx.markUpdate( fieldEngine, fieldClassMolder, o, null );
// if _fhs[i].isStore is true for this field,
// and if key generator is used
// and if the related object is replaced this object by null
// and if everything else is not modified
// then, objectModifiedException will be thrown
// there are two solutions, first introduce preCreate state,
// and walk the create graph, and create non-store object
// first. However, it doesn't guarantee solution. because
// every object may have field which uses key-generator
// second, we can do another SQLStatement at the very end of
// this method.
// note, one-many and many-many doesn't affected, because
// it is always non-store fields.
if ( creating && !_fhs[i].isStored() && fieldClassMolder._isKeyGenUsed ) {
updateCache = true;
}
}
}
}
break;
case FieldMolder.ONE_TO_MANY:
// create dependent objects if exists
fieldClassMolder = _fhs[i].getFieldClassMolder();
fieldEngine = _fhs[i].getFieldLockEngine();
o = _fhs[i].getValue( object, tx.getClassLoader() );
if ( o != null ) {
Iterator itor = getIterator( o );
while (itor.hasNext()) {
Object oo = itor.next();
if ( _fhs[i].isDependent() ) {
if ( !tx.isRecorded( oo ) ) {
//autoCreated = true;
tx.markCreate( fieldEngine, fieldClassMolder, oo, oid );
if ( fieldClassMolder._isKeyGenUsed )
updateCache = true;
} else
// fail-fast principle: if the object depend on another object,
// throw exception
if ( !tx.isDepended( oid, oo ) )
throw new PersistenceException("Dependent object may not change its master");
} else if ( tx.isAutoStore() ) {
if ( !tx.isRecorded( oo ) ) {
boolean creating = tx.markUpdate( fieldEngine, fieldClassMolder, oo, null );
if ( creating && fieldClassMolder._isKeyGenUsed )
updateCache = true;