// For bug 2782991 a list of nearly 20 problems with this method have
// been fixed.
ReadObjectQuery query = getReadObjectQuery();
ClassDescriptor descriptor = getDescriptor();
boolean conforming = false;
UnitOfWorkImpl uow = null;
if (session.isUnitOfWork()) {
conforming = query.shouldConformResultsInUnitOfWork() || descriptor.shouldAlwaysConformResultsInUnitOfWork();
uow = (UnitOfWorkImpl)session;
}
// Set the in memory query policy automatically for conforming queries, unless the
// user specifies the most cautious one.
int policyToUse = query.getInMemoryQueryIndirectionPolicyState();
if (conforming && (policyToUse != InMemoryQueryIndirectionPolicy.SHOULD_TRIGGER_INDIRECTION)) {
policyToUse = InMemoryQueryIndirectionPolicy.SHOULD_IGNORE_EXCEPTION_RETURN_CONFORMED;
}
Object cachedObject = null;
Expression selectionCriteria = getSelectionCriteria();
// Perform a series of cache checks, in the following order...
// 1: If selection key or selection object, lookup by primary key.
// 2: If selection criteria null, take the first instance in cache.
// 3: If exact primary key expression, lookup by primary key.
// 4: If inexact primary key expression, lookup by primary key and see if it conforms.
// 5: Perform a linear search on the cache, calling doesConform on each object.
// 6: (Conforming) Search through new objects.
// Each check is more optimal than the next.
// Finally: (Conforming) check that any positive result was not deleted in the UnitOfWork.
// 1: If selection key or selection object, do lookup by primary key.
Vector selectionKey = query.getSelectionKey();
Object selectionObject = query.getSelectionObject();
if ((selectionKey != null) || (selectionObject != null)) {
if (selectionKey == null) {
selectionKey = descriptor.getObjectBuilder().extractPrimaryKeyFromObject(selectionObject, session, true);
if (selectionKey == null) {
// Has a null primary key, so must not exist.
return InvalidObject.instance;
}
// Must be checked separately as the expression and row is not yet set.
query.setSelectionKey(selectionKey);
}
if (descriptor.shouldAcquireCascadedLocks()) {
cachedObject = session.getIdentityMapAccessorInstance().getFromIdentityMapWithDeferredLock(selectionKey, query.getReferenceClass(), false, descriptor);
} else {
cachedObject = session.getIdentityMapAccessorInstance().getFromIdentityMap(selectionKey, query.getReferenceClass(), false, descriptor);
}
// Also check if key is null, cannot exist.
if (selectionKey.contains(null)) {
return InvalidObject.instance;
}
} else {
// 2: If selection criteria null, take any instance in cache.
//
if (selectionCriteria == null) {
// In future would like to always return something from cache.
if (query.shouldConformResultsInUnitOfWork() || descriptor.shouldAlwaysConformResultsInUnitOfWork() || query.shouldCheckCacheOnly() || query.shouldCheckCacheThenDatabase()) {
cachedObject = session.getIdentityMapAccessorInstance().getIdentityMapManager().getFromIdentityMap(null, query.getReferenceClass(), translationRow, policyToUse, conforming, false, descriptor);
}
} else {
// 3: If can extract exact primary key expression, do lookup by primary key.
//
selectionKey = descriptor.getObjectBuilder().extractPrimaryKeyFromExpression(true, selectionCriteria, translationRow, session);
// If an exact primary key was extracted or should check cache by exact
// primary key only this will become the final check.
if ((selectionKey != null) || query.shouldCheckCacheByExactPrimaryKey()) {
if (selectionKey != null) {
if (descriptor.shouldAcquireCascadedLocks()) {
cachedObject = session.getIdentityMapAccessorInstance().getFromIdentityMapWithDeferredLock(selectionKey, query.getReferenceClass(), false, descriptor);
} else {
cachedObject = session.getIdentityMapAccessorInstance().getFromIdentityMap(selectionKey, query.getReferenceClass(), false, descriptor);
}
// Because it was exact primary key if the lookup failed then it is not there.
// Also check if key is null, cannot exist.
if (selectionKey.contains(null)) {
return InvalidObject.instance;
}
}
} else {
// 4: If can extract inexact primary key, find one object by primary key and
// check if it conforms. Failure of this object to conform however does not
// rule out a cache hit.
Vector inexactSelectionKey = descriptor.getObjectBuilder().extractPrimaryKeyFromExpression(false, selectionCriteria, translationRow, session);// Check for any primary key in expression, may have other stuff.
if (inexactSelectionKey != null) {
// PERF: Only use deferred lock when required.
if (descriptor.shouldAcquireCascadedLocks()) {
cachedObject = session.getIdentityMapAccessorInstance().getFromIdentityMapWithDeferredLock(inexactSelectionKey, query.getReferenceClass(), false, descriptor);
} else {
cachedObject = session.getIdentityMapAccessorInstance().getFromIdentityMap(inexactSelectionKey, query.getReferenceClass(), false, descriptor);
}
if (cachedObject != null) {
// Must ensure that it matches the expression.
try {
// PERF: 3639015 - cloning the expression no longer required
// when using the root session.
ExpressionBuilder builder = selectionCriteria.getBuilder();
builder.setSession(session.getRootSession(null));
builder.setQueryClass(descriptor.getJavaClass());
if (!selectionCriteria.doesConform(cachedObject, session, translationRow, policyToUse)) {
cachedObject = null;
}
} catch (QueryException exception) {// Ignore if expression too complex.
if (query.shouldCheckCacheOnly()) {// Throw on only cache.
throw exception;
}
cachedObject = null;
}
}
}
// 5: Perform a linear search of the cache, calling expression.doesConform on each element.
// This is a last resort linear time search of the identity map.
// This can be avoided by setting check cache by (inexact/exact) primary key on the query.
// That flag becomes invalid in the conforming case (bug 2609611: SUPPORT CONFORM RESULT IN UOW IN CONJUNCTION WITH OTHER IN-MEMORY FEATURES)
// so if conforming must always do this linear search, but at least only on
// objects registered in the UnitOfWork.
//
boolean conformingButOutsideUnitOfWork = ((query.shouldConformResultsInUnitOfWork() || descriptor.shouldAlwaysConformResultsInUnitOfWork()) && !session.isUnitOfWork());
if ((cachedObject == null) && (conforming || (!query.shouldCheckCacheByPrimaryKey() && !conformingButOutsideUnitOfWork))) {
// PERF: 3639015 - cloning the expression no longer required
// when using the root session
if (selectionCriteria != null) {
ExpressionBuilder builder = selectionCriteria.getBuilder();
builder.setSession(session.getRootSession(null));
builder.setQueryClass(descriptor.getJavaClass());
}
try {
cachedObject = session.getIdentityMapAccessorInstance().getIdentityMapManager().getFromIdentityMap(selectionCriteria, query.getReferenceClass(), translationRow, policyToUse, conforming, false, descriptor);
} catch (QueryException exception) {// Ignore if expression too complex.
if (query.shouldCheckCacheOnly()) {// Throw on only cache.
throw exception;
}
}
}
}
}
}
// 6: If unit of work search through new objects.
//
if (conforming) {
if (cachedObject == null) {
if (selectionKey != null) {
if (!uow.shouldNewObjectsBeCached()) {
cachedObject = uow.getObjectFromNewObjects(query.getReferenceClass(), selectionKey);
}
} else {
// PERF: 3639015 - cloning the expression no longer required
// when using the root session
if (selectionCriteria != null) {
ExpressionBuilder builder = selectionCriteria.getBuilder();
builder.setSession(session.getRootSession(null));
builder.setQueryClass(descriptor.getJavaClass());
}
try {
cachedObject = uow.getObjectFromNewObjects(selectionCriteria, query.getReferenceClass(), translationRow, policyToUse);
} catch (QueryException exception) {
// Ignore if expression too complex.
}
}
}
// Finally, check that a positive result is not deleted in the Unit Of Work.
//
if (cachedObject != null) {
if (uow.isObjectDeleted(cachedObject)) {
if (selectionKey != null) {
// In this case return a special value, to notify
// that the object was found but null must be returned.
return InvalidObject.instance;
} else {