boolean isNew = state.length == 3 + offset;
// attempting to attach an instance that has been deleted
// will throw an OVE if it was not PNEW when it was detached
if (!isNew)
throw new OptimisticException(_loc.get("attach-deleted",
ImplHelper.getManagedInstance(pc).getClass(), id))
.setFailedObject(id);
// if the instance does not exist, we assume that it was
// made persistent in a new transaction, detached, and then
// the transaction was rolled back; the danger is that
// the instance was made persistent, detached, committed,
// and then deleted, but this is an uncommon case
sm = persist(manager, pc, meta, id, explicit);
into = sm.getPersistenceCapable();
// nullify the state, since the new instance won't have one
state = null;
} else
sm = manager.assertManaged(into);
} else
sm = manager.assertManaged(into);
// mark that we attached the instance *before* we
// fill in values to avoid endless recursion
manager.setAttachedCopy(pc, into);
meta = sm.getMetaData();
manager.fireBeforeAttach(pc, meta);
offset = meta.getIdentityType() == meta.ID_DATASTORE ? 1 : 0;
// assign the detached pc the same state manager as the object we're
// copying into during the attach process
pc.pcReplaceStateManager(sm);
BitSet fields = state == null ? null : (BitSet) state[1 + offset];
try {
FieldMetaData[] fmds = meta.getFields();
for (int i = 0; i < fmds.length; i++) {
// only attach fields in the FG of the detached instance; new
// instances get all their fields attached
if (fields == null || fields.get(i))
attachField(manager, pc, sm, fmds[i], true);
}
}
finally {
pc.pcReplaceStateManager(null);
}
// set the next version for non-new instances that are not embedded
if (state != null && !embedded) {
// make sure that all the fields in the original FG are loaded
// before we try to compare version
if (fields != null && !fields.equals(sm.getLoaded())) {
BitSet toLoad = (BitSet) fields.clone();
toLoad.andNot(sm.getLoaded()); // skip already loaded fields
if (toLoad.length() > 0)
sm.loadFields(toLoad, null, LockLevels.LOCK_NONE, null,
false);
//### we should calculate lock level above
}
Object version = state[offset];
StoreManager store = broker.getStoreManager();
switch (store.compareVersion(sm, version, sm.getVersion())) {
case StoreManager.VERSION_LATER:
// we have a later version: set it into the object.
// lock validation will occur at commit time
sm.setVersion(version);
break;
case StoreManager.VERSION_EARLIER:
case StoreManager.VERSION_DIFFERENT:
sm.setVersion(version);
throw new OptimisticException(into);
case StoreManager.VERSION_SAME:
// no action required
break;
}
}