{
// Object in the process of detaching (recursive) so return the object which will be the detached object
return referencedPC;
}
PersistenceCapable detachedPC = myPC.jdoNewInstance(this);
referencedPC = detachedPC;
// Check if detachable ... if so then we detach a copy, otherwise we return a transient copy
boolean detachable = myOM.getApiAdapter().isDetachable(myPC);
// make sure a detaching PC is not read by another thread while we are detaching
synchronized (referencedPC)
{
if (detachable)
{
if (NucleusLogger.PERSISTENCE.isDebugEnabled())
{
NucleusLogger.PERSISTENCE.debug(LOCALISER.msg("010010", StringUtils.toJVMIDString(myPC),
"" + state.getCurrentFetchDepth(), StringUtils.toJVMIDString(detachedPC)));
}
// Call any "pre-detach" listeners
getCallbackHandler().preDetach(myPC);
}
try
{
operationalFlags |= MISC_DETACHING;
// Handle any field loading/unloading before the detach
if ((myOM.getFetchPlan().getDetachmentOptions() & FetchPlan.DETACH_LOAD_FIELDS) != 0)
{
// Load any unloaded fetch-plan fields
loadUnloadedFieldsInFetchPlan();
}
if (myLC == myOM.getOMFContext().getApiAdapter().getLifeCycleState(LifeCycleState.HOLLOW) ||
myLC == myOM.getOMFContext().getApiAdapter().getLifeCycleState(LifeCycleState.P_NONTRANS))
{
// Migrate any HOLLOW/P_NONTRANS to P_CLEAN etc
myLC = myLC.transitionReadField(this, true);
}
// Create a SM for our copy object
JDOStateManagerImpl smDetachedPC = new JDOStateManagerImpl(myOM, cmd);
smDetachedPC.initialiseForDetached(detachedPC, getExternalObjectId(myPC), getVersion(myPC));
smDetachedPC.referencedPC = myPC;
smDetachedPC.replaceFields(getFieldsNumbersToDetach(), new DetachFieldManager(this, getSecondClassMutableFields(),
myFP, state, true));
smDetachedPC.referencedPC = null;
if (detachable)
{
// Update the object with its detached state - not to be confused with the "state" object above
detachedPC.jdoReplaceFlags();
((Detachable)detachedPC).jdoReplaceDetachedState();
}
else
{
smDetachedPC.makeTransient(null);
}
// Remove its StateManager since now detached or transient
replaceStateManager(detachedPC, null);
}
catch (Exception e)
{
// What could possible be thrown here ?
NucleusLogger.PERSISTENCE.debug("DETACH ERROR : Error thrown while detaching " +
StringUtils.toJVMIDString(myPC) + " (id=" + myID + ")", e);
}
finally
{
operationalFlags &= ~MISC_DETACHING;
referencedPC = null;
}
if (detachable && !myOM.getApiAdapter().isDetached(detachedPC))
{
// Sanity check on the objects detached state
throw new NucleusUserException(LOCALISER.msg("026025", detachedPC.getClass().getName(), myID));
}
if (detachable)
{
// Call any "post-detach" listeners