private Boolean dirty(int field, Boolean mutate, boolean loadFetchGroup) {
boolean locked = false;
boolean newFlush = false;
boolean clean = false;
try {
FieldMetaData fmd = _meta.getField(field);
if (!isNew() || isFlushed()) {
if (fmd.getUpdateStrategy() == UpdateStrategies.RESTRICT)
throw new InvalidStateException(_loc.get
("update-restrict", fmd));
if (fmd.getUpdateStrategy() == UpdateStrategies.IGNORE)
return Boolean.FALSE;
}
if (isEmbedded()) {
if (isEmbeddedNotUpdatable())
throw new UserException(_loc.get
("cant-update-embed-in-query-result")).setFailedObject
(getManagedInstance());
else
// notify owner of change
_owner.dirty(_ownerIndex, Boolean.TRUE, loadFetchGroup);
}
// is this a direct mutation of an sco field?
if (mutate == null) {
switch (fmd.getDeclaredTypeCode()) {
case JavaTypes.COLLECTION:
case JavaTypes.MAP:
case JavaTypes.ARRAY:
case JavaTypes.DATE:
case JavaTypes.CALENDAR:
case JavaTypes.OBJECT:
mutate = Boolean.TRUE;
break;
case JavaTypes.PC:
mutate =
(fmd.isEmbedded()) ? Boolean.TRUE : Boolean.FALSE;
break;
default:
mutate = Boolean.FALSE; // not sco
}
}
// possibly change state
boolean active = _broker.isActive();
clean = !_state.isDirty(); // intentional direct access
// fire event fast before state change.
if (clean)
fireLifecycleEvent(LifecycleEvent.BEFORE_DIRTY);
if (active) {
if (_broker.getOptimistic())
setPCState(_state.beforeOptimisticWrite(this, field,
mutate.booleanValue()));
else
setPCState(_state.beforeWrite(this, field,
mutate.booleanValue()));
} else if (fmd.getManagement() == FieldMetaData.MANAGE_PERSISTENT) {
if (isPersistent() && !_broker.getNontransactionalWrite())
throw new InvalidStateException(_loc.get
("non-trans-write")).setFailedObject
(getManagedInstance());
setPCState(_state.beforeNontransactionalWrite(this, field,
mutate.booleanValue()));
}
if ((_flags & FLAG_FLUSHED) != 0) {
newFlush = (_flags & FLAG_FLUSHED_DIRTY) == 0;
_flags |= FLAG_FLUSHED_DIRTY;
}
lock();
locked = true;
// note that the field is in need of flushing again, and tell the
// broker too
clearFlushField(field);
_broker.setDirty(this, newFlush && !clean);
// save the field for rollback if needed
saveField(field);
// dirty the field and mark loaded; load fetch group if needed
int lockLevel = calculateLockLevel(active, true, null);
if (!isFieldDirty(field)) {
setLoaded(field, true);
setFieldDirty(field);
// make sure the field's fetch group is loaded
if (loadFetchGroup && isPersistent()
&& fmd.getManagement() == fmd.MANAGE_PERSISTENT)
loadField(field, lockLevel, true, true);
}
obtainLocks(active, true, lockLevel, null, null);
} catch (RuntimeException re) {
throw translate(re);