ClassDescriptor concreteDescriptor = descriptor;
// Ensure correct subclass descriptor.
if (objectFromCache.getClass() != descriptor.getJavaClass()) {
concreteDescriptor = session.getDescriptor(objectFromCache);
}
ObjectBuilder builder = concreteDescriptor.getObjectBuilder();
Object workingClone = null;
// The cache/objects being registered must first be locked to ensure
// that a merge or refresh does not occur on the object while being cloned to
// avoid cloning a partially merged/refreshed object.
// If a cache isolation level is used, then lock the entire cache.
// otherwise lock the object and it related objects (not using indirection) as a unit.
// If just a simple object (all indirection) a simple read-lock can be used.
// PERF: Cache if check to write is required.
boolean identityMapLocked = parentIdentityMapAccessor.acquireWriteLock();
boolean rootOfCloneRecursion = false;
if (identityMapLocked) {
session.checkAndRefreshInvalidObject(objectFromCache, cacheKey, descriptor);
} else {
// Check if we have locked all required objects already.
if (this.objectsLockedForClone == null) {
// PERF: If a simple object just acquire a simple read-lock.
if (concreteDescriptor.shouldAcquireCascadedLocks()) {
this.objectsLockedForClone = parentIdentityMapAccessor.getWriteLockManager().acquireLocksForClone(objectFromCache, concreteDescriptor, cacheKey, session);
} else {
session.checkAndRefreshInvalidObject(objectFromCache, cacheKey, descriptor);
cacheKey.acquireReadLock();
}
rootOfCloneRecursion = true;
}
}
try {
// bug:6167576 Must acquire the lock before cloning.
workingClone = builder.instantiateWorkingCopyClone(objectFromCache, session);
// PERF: Cache the primary key if implements PersistenceEntity.
if (workingClone instanceof PersistenceEntity) {
((PersistenceEntity)workingClone)._persistence_setId(cacheKey.getKey());
}
CacheKey localCacheKey = acquireLock(primaryKey, theClass, descriptor);
try{
localCacheKey.setObject(workingClone);
localCacheKey.setReadTime(cacheKey.getReadTime());
localCacheKey.setWriteLockValue(cacheKey.getWriteLockValue());
builder.populateAttributesForClone(objectFromCache, cacheKey, workingClone, session);
}finally{
localCacheKey.release();
}
//also clone the fetch group reference if applied