public Object attach(AttachManager manager, Object toAttach,
ClassMetaData meta, PersistenceCapable into, OpenJPAStateManager owner,
ValueMetaData ownerMeta, boolean explicit) {
BrokerImpl broker = manager.getBroker();
PersistenceCapable pc = ImplHelper.toPersistenceCapable(toAttach,
meta.getRepository().getConfiguration());
boolean embedded = ownerMeta != null && ownerMeta.isEmbeddedPC();
boolean isNew = !broker.isDetached(pc);
Object version = null;
StateManagerImpl sm;
// if the state manager for the embedded instance is null, then
// it should be treated as a new instance (since the
// newly persisted owner may create a new embedded instance
// in the constructor); fixed bug #1075.
// also, if the user has attached a detached obj from somewhere
// else in the graph to an embedded field that was previously null,
// copy into a new embedded instance
if (embedded && (isNew || into == null
|| broker.getStateManager(into) == null)) {
if (into == null)
into = pc.pcNewInstance(null, false);
sm = (StateManagerImpl) broker.embed(into, null, owner, ownerMeta);
into = sm.getPersistenceCapable();
} else if (isNew) {
Object oid = null;
if (!isPrimaryKeysGenerated(meta))
oid = ApplicationIds.create(pc, meta);
sm = persist(manager, pc, meta, oid, explicit);
into = sm.getPersistenceCapable();
} else if (!embedded && into == null) {
Object id = getDetachedObjectId(manager, toAttach);
if (id != null)
into =
ImplHelper.toPersistenceCapable(broker.find(id, true, null),
broker.getConfiguration());
if (into == null)
throw new OptimisticException(_loc.get("attach-version-del",
ImplHelper.getManagedInstance(pc).getClass(), id, version))
.setFailedObject(toAttach);
sm = manager.assertManaged(into);
if (meta.getDescribedType()
!= sm.getMetaData().getDescribedType()) {
throw new ObjectNotFoundException(_loc.get
("attach-wrongclass", id, toAttach.getClass(),
sm.getMetaData().getDescribedType())).
setFailedObject(toAttach);
}
} else
sm = manager.assertManaged(into);
// mark that we attached the instance *before* we
// fill in values to avoid endless recursion
manager.setAttachedCopy(toAttach, into);
// if persisting in place, just attach field values
if (pc == into) {
attachFieldsInPlace(manager, sm);
return into;
}
if (isNew) {
broker.fireLifecycleEvent(toAttach, null, meta,
LifecycleEvent.BEFORE_PERSIST);
} else {
// invoke any preAttach on the detached instance
manager.fireBeforeAttach(toAttach, meta);
}
// assign the detached pc the same state manager as the object we're
// copying into during the attach process
StateManager smBefore = pc.pcGetStateManager();
pc.pcReplaceStateManager(sm);
int detach = (isNew) ? DETACH_ALL : broker.getDetachState();
FetchConfiguration fetch = broker.getFetchConfiguration();
try {
FieldMetaData[] fmds = sm.getMetaData().getFields();
for (int i = 0; i < fmds.length; i++) {
switch (detach) {
case DETACH_ALL:
attachField(manager, toAttach, sm, fmds[i], true);
break;
case DETACH_FETCH_GROUPS:
if (fetch.requiresFetch(fmds[i])
!= FetchConfiguration.FETCH_NONE)
attachField(manager, toAttach, sm, fmds[i], true);
break;
case DETACH_LOADED:
attachField(manager, toAttach, sm, fmds[i], false);
break;
}
}
} finally {
pc.pcReplaceStateManager(smBefore);
}
if (!embedded && !isNew)
compareVersion(sm, pc);
return ImplHelper.getManagedInstance(into);
}