use of org.eclipse.persistence.descriptors.changetracking.ObjectChangePolicy in project eclipselink by eclipse-ee4j.
the class ObjectBuilder method buildWorkingCopyCloneFromRow.
/**
* INTERNAL:
* Builds a working copy clone directly from the database row.
* This is the key method that allows us to execute queries against a
* UnitOfWork while in transaction and not cache the results in the shared
* cache. This is because we might violate transaction isolation by
* putting uncommitted versions of objects in the shared cache.
*/
protected Object buildWorkingCopyCloneFromRow(ObjectBuildingQuery query, JoinedAttributeManager joinManager, AbstractRecord databaseRow, UnitOfWorkImpl unitOfWork, Object primaryKey, CacheKey preFetchedCacheKey) throws DatabaseException, QueryException {
ClassDescriptor descriptor = this.descriptor;
// If the clone already exists then it may only need to be refreshed or returned.
// We call directly on the identity map to avoid going to the parent,
// registering if found, and wrapping the result.
// Acquire or create the cache key as is need once the object is build anyway.
CacheKey unitOfWorkCacheKey = unitOfWork.getIdentityMapAccessorInstance().getIdentityMapManager().acquireLock(primaryKey, descriptor.getJavaClass(), false, descriptor, true);
Object workingClone = unitOfWorkCacheKey.getObject();
FetchGroup fetchGroup = query.getExecutionFetchGroup(descriptor);
FetchGroupManager fetchGroupManager = descriptor.getFetchGroupManager();
try {
// If there is a clone, and it is not a refresh then just return it.
boolean wasAClone = workingClone != null;
boolean isARefresh = query.shouldRefreshIdentityMapResult() || (query.isLockQuery() && (!wasAClone || !query.isClonePessimisticLocked(workingClone, unitOfWork)));
// Also need to refresh if the clone is a partial object and query requires more than its fetch group.
if (wasAClone && fetchGroupManager != null && (fetchGroupManager.isPartialObject(workingClone) && (!fetchGroupManager.isObjectValidForFetchGroup(workingClone, fetchGroupManager.getEntityFetchGroup(fetchGroup))))) {
isARefresh = true;
}
if (wasAClone && (!isARefresh)) {
return workingClone;
}
boolean wasAnOriginal = false;
boolean isIsolated = descriptor.getCachePolicy().shouldIsolateObjectsInUnitOfWork() || (descriptor.shouldIsolateObjectsInUnitOfWorkEarlyTransaction() && unitOfWork.wasTransactionBegunPrematurely());
Object original = null;
CacheKey originalCacheKey = null;
// If not refreshing can get the object from the cache.
if ((!isARefresh) && (!isIsolated) && !query.shouldRetrieveBypassCache() && !unitOfWork.shouldReadFromDB() && (!unitOfWork.shouldForceReadFromDB(query, primaryKey))) {
AbstractSession session = unitOfWork.getParentIdentityMapSession(query);
if (preFetchedCacheKey == null) {
originalCacheKey = session.getIdentityMapAccessorInstance().getCacheKeyForObject(primaryKey, descriptor.getJavaClass(), descriptor, false);
} else {
originalCacheKey = preFetchedCacheKey;
originalCacheKey.acquireLock(query);
}
if (originalCacheKey != null) {
// PERF: Read-lock is not required on object as unit of work will acquire this on clone and object cannot gc and object identity is maintained.
original = originalCacheKey.getObject();
wasAnOriginal = original != null;
// If the original is invalid or always refresh then need to refresh.
isARefresh = wasAnOriginal && (descriptor.shouldAlwaysRefreshCache() || descriptor.getCacheInvalidationPolicy().isInvalidated(originalCacheKey, query.getExecutionTime()));
// Otherwise can just register the cached original object and return it.
if (wasAnOriginal && (!isARefresh)) {
if (descriptor.getCachePolicy().isSharedIsolation() || !descriptor.shouldIsolateProtectedObjectsInUnitOfWork()) {
// or using protected isolation and isolated client sessions
return unitOfWork.cloneAndRegisterObject(original, originalCacheKey, unitOfWorkCacheKey, descriptor);
}
}
}
}
if (!wasAClone) {
// The copy policy is easier to invoke if we have an original.
if (wasAnOriginal && !query.shouldRetrieveBypassCache()) {
workingClone = instantiateWorkingCopyClone(original, unitOfWork);
// intentionally put nothing in clones to originals, unless really was one.
unitOfWork.getCloneToOriginals().put(workingClone, original);
} else {
if (descriptor.hasSerializedObjectPolicy() && query.shouldUseSerializedObjectPolicy() && !databaseRow.hasSopObject()) {
// serialized sopObject is a value corresponding to sopField in the row, row.sopObject==null;
// the following line sets deserialized sopObject into row.sopObject variable and sets sopField's value to null;
workingClone = descriptor.getSerializedObjectPolicy().getObjectFromRow(databaseRow, unitOfWork, (ObjectLevelReadQuery) query);
}
if (workingClone == null) {
// What happens if a copy policy is defined is not pleasant.
// workingClone = instantiateWorkingCopyCloneFromRow(databaseRow, query, primaryKey, unitOfWork);
// Create a new instance instead. The object is populated later by buildAttributesIntoWorkingCopyClone method.
workingClone = buildNewInstance();
}
}
// This must be registered before it is built to avoid cycles.
// The version and read is set below in copyQueryInfoToCacheKey.
unitOfWorkCacheKey.setObject(workingClone);
// This must be registered before it is built to avoid cycles.
unitOfWork.getCloneMapping().put(workingClone, workingClone);
}
// Must avoid infinite loops while refreshing.
if (wasAClone && (unitOfWorkCacheKey.getLastUpdatedQueryId() >= query.getQueryId())) {
return workingClone;
}
copyQueryInfoToCacheKey(unitOfWorkCacheKey, query, databaseRow, unitOfWork, descriptor);
ObjectChangePolicy policy = descriptor.getObjectChangePolicy();
// If it was a clone the change listener must be cleared after.
if (!wasAClone) {
// The change listener must be set before building the clone as aggregate/collections need the listener.
policy.setChangeListener(workingClone, unitOfWork, descriptor);
}
// Turn it 'off' to prevent unwanted events.
policy.dissableEventProcessing(workingClone);
if (isARefresh && fetchGroupManager != null) {
fetchGroupManager.setObjectFetchGroup(workingClone, query.getExecutionFetchGroup(this.descriptor), unitOfWork);
}
if (!unitOfWork.wasTransactionBegunPrematurely() && descriptor.getCachePolicy().isProtectedIsolation() && !isIsolated && !query.shouldStoreBypassCache()) {
// we are at this point because we have isolated protected entities to the UnitOfWork
// we should ensure that we populate the cache as well.
originalCacheKey = (CacheKey) buildObject(true, query, databaseRow, unitOfWork.getParentIdentityMapSession(descriptor, false, true), primaryKey, preFetchedCacheKey, descriptor, joinManager);
}
// the cachekey will be null so the attribute building will not be able to access the shared cache.
if (isARefresh) {
// if we need to refresh the UOW then remove the cache key and the clone will be rebuilt not using any of the
// cache. This should be updated to force the buildAttributesIntoWorkingCopyClone to refresh the objects
originalCacheKey = null;
}
// Build/refresh the clone from the row.
buildAttributesIntoWorkingCopyClone(workingClone, originalCacheKey, query, joinManager, databaseRow, unitOfWork, wasAClone);
// Set fetch group after building object if not a refresh to avoid checking fetch during building.
if ((!isARefresh) && fetchGroupManager != null) {
if (wasAnOriginal) {
// 485984: Save the FetchGroup from the original
fetchGroupManager.setObjectFetchGroup(workingClone, fetchGroupManager.getObjectFetchGroup(original), unitOfWork);
} else {
fetchGroupManager.setObjectFetchGroup(workingClone, query.getExecutionFetchGroup(this.descriptor), unitOfWork);
}
}
Object backupClone = policy.buildBackupClone(workingClone, this, unitOfWork);
// If it was a clone the change listener must be cleared.
if (wasAClone) {
policy.clearChanges(workingClone, unitOfWork, descriptor, isARefresh);
}
policy.enableEventProcessing(workingClone);
unitOfWork.getCloneMapping().put(workingClone, backupClone);
query.recordCloneForPessimisticLocking(workingClone, unitOfWork);
// PERF: Cache the primary key if implements PersistenceEntity.
if (workingClone instanceof PersistenceEntity) {
((PersistenceEntity) workingClone)._persistence_setId(primaryKey);
}
} finally {
unitOfWorkCacheKey.release();
}
instantiateEagerMappings(workingClone, unitOfWork);
return workingClone;
}
use of org.eclipse.persistence.descriptors.changetracking.ObjectChangePolicy in project eclipselink by eclipse-ee4j.
the class ObjectBuilder method buildObjectFromResultSetInternal.
/**
* INTERNAL:
* Builds a working copy clone directly from a result set.
* PERF: This method is optimized for a specific case of building objects
* so can avoid many of the normal checks, only queries that have this criteria
* can use this method of building objects.
*/
private Object buildObjectFromResultSetInternal(ObjectBuildingQuery query, JoinedAttributeManager joinManager, ResultSet resultSet, AbstractSession executionSession, DatabaseAccessor accessor, ResultSetMetaData metaData, DatabasePlatform platform, Vector fieldsList, DatabaseField[] fieldsArray) throws SQLException {
ClassDescriptor descriptor = this.descriptor;
int pkFieldsSize = descriptor.getPrimaryKeyFields().size();
DatabaseMapping primaryKeyMapping = null;
AbstractRecord row = null;
Object[] values = null;
Object primaryKey;
if (isSimple && pkFieldsSize == 1) {
primaryKeyMapping = this.primaryKeyMappings.get(0);
primaryKey = primaryKeyMapping.valueFromResultSet(resultSet, query, executionSession, accessor, metaData, 1, platform);
} else {
values = new Object[fieldsArray.length];
row = new ArrayRecord(fieldsList, fieldsArray, values);
accessor.populateRow(fieldsArray, values, resultSet, metaData, executionSession, 0, pkFieldsSize);
primaryKey = extractPrimaryKeyFromRow(row, executionSession);
}
UnitOfWorkImpl unitOfWork = null;
AbstractSession session = executionSession;
boolean isolated = !descriptor.getCachePolicy().isSharedIsolation();
if (session.isUnitOfWork()) {
unitOfWork = (UnitOfWorkImpl) executionSession;
isolated |= unitOfWork.wasTransactionBegunPrematurely() && descriptor.shouldIsolateObjectsInUnitOfWorkEarlyTransaction();
}
CacheKey cacheKey = session.getIdentityMapAccessorInstance().getIdentityMapManager().acquireLock(primaryKey, descriptor.getJavaClass(), false, descriptor, query.isCacheCheckComplete());
CacheKey cacheKeyToUse = cacheKey;
CacheKey parentCacheKey = null;
Object object = cacheKey.getObject();
try {
// Found locally in the unit of work, or session query and found in the session.
if (object != null) {
return object;
}
if ((unitOfWork != null) && !isolated) {
// Need to lookup in the session.
session = unitOfWork.getParentIdentityMapSession(query);
parentCacheKey = session.getIdentityMapAccessorInstance().getIdentityMapManager().acquireLock(primaryKey, descriptor.getJavaClass(), false, descriptor, query.isCacheCheckComplete());
cacheKeyToUse = parentCacheKey;
object = parentCacheKey.getObject();
}
// If the object is not in the cache, it needs to be built, this is building in the unit of work if isolated.
if (object == null) {
object = buildNewInstance();
if (unitOfWork == null) {
cacheKey.setObject(object);
} else {
if (isolated) {
cacheKey.setObject(object);
unitOfWork.getCloneMapping().put(object, object);
} else {
parentCacheKey.setObject(object);
}
}
List<DatabaseMapping> mappings = descriptor.getMappings();
int size = mappings.size();
if (isSimple) {
int shift = descriptor.getTables().size() * pkFieldsSize;
if (primaryKeyMapping != null) {
// simple primary key - set pk directly through the mapping
primaryKeyMapping.setAttributeValueInObject(object, primaryKey);
} else {
// composite primary key - set pk using pkRow
boolean isTargetProtected = session.isProtectedSession();
for (int index = 0; index < pkFieldsSize; index++) {
DatabaseMapping mapping = mappings.get(index);
mapping.readFromRowIntoObject(row, joinManager, object, cacheKeyToUse, query, session, isTargetProtected);
}
}
// set the rest using mappings directly
for (int index = pkFieldsSize; index < size; index++) {
DatabaseMapping mapping = mappings.get(index);
mapping.readFromResultSetIntoObject(resultSet, object, query, session, accessor, metaData, index + shift, platform);
}
} else {
boolean isTargetProtected = session.isProtectedSession();
accessor.populateRow(fieldsArray, values, resultSet, metaData, session, pkFieldsSize, fieldsArray.length);
for (int index = 0; index < size; index++) {
DatabaseMapping mapping = mappings.get(index);
mapping.readFromRowIntoObject(row, joinManager, object, cacheKeyToUse, query, session, isTargetProtected);
}
}
((PersistenceEntity) object)._persistence_setId(primaryKey);
if ((unitOfWork != null) && isolated) {
ObjectChangePolicy policy = descriptor.getObjectChangePolicy();
policy.setChangeListener(object, unitOfWork, descriptor);
}
}
if ((unitOfWork != null) && !isolated) {
// Need to clone the object in the unit of work.
// TODO: Doesn't work all the time
// With one setup (jpa2.performance tests) produces a shallow clone (which is good enough for isSimple==true case only),
// in other (jpa.advanced tests) - just a brand new empty object.
Object clone = instantiateWorkingCopyClone(object, unitOfWork);
((PersistenceEntity) clone)._persistence_setId(cacheKey.getKey());
unitOfWork.getCloneMapping().put(clone, clone);
unitOfWork.getCloneToOriginals().put(clone, object);
cacheKey.setObject(clone);
ObjectChangePolicy policy = descriptor.getObjectChangePolicy();
policy.setChangeListener(clone, unitOfWork, descriptor);
object = clone;
}
} finally {
cacheKey.release();
if (parentCacheKey != null) {
parentCacheKey.release();
}
}
return object;
}
use of org.eclipse.persistence.descriptors.changetracking.ObjectChangePolicy in project eclipselink by eclipse-ee4j.
the class OrderedListAttributeChangeTrackingJunitTest method suite.
public static Test suite() {
TestSuite suite = new TestSuite();
suite.setName("OrderedListAttributeChangeTrackingJunitTest");
suite.addTest(new OrderedListAttributeChangeTrackingJunitTest("testInitialize"));
suite.addTest(new OrderedListAttributeChangeTrackingJunitTest("test1"));
suite.addTest(new OrderedListAttributeChangeTrackingJunitTest("testInitialize"));
suite.addTest(new OrderedListAttributeChangeTrackingJunitTest("test2"));
suite.addTest(new OrderedListAttributeChangeTrackingJunitTest("testInitialize"));
suite.addTest(new OrderedListAttributeChangeTrackingJunitTest("test3"));
return new TestSetup(suite) {
private ObjectChangePolicy origPolicy;
@Override
protected void setUp() {
DatabaseSession session = JUnitTestCase.getServerSession();
new InheritedTableManager().replaceTables(session);
session.logout();
origPolicy = session.getDescriptor(BeerConsumer.class).getObjectChangePolicy();
session.getDescriptor(BeerConsumer.class).setObjectChangePolicy(new AttributeChangeTrackingPolicy());
session.login();
}
@Override
protected void tearDown() {
new OrderedListAttributeChangeTrackingJunitTest().clearCache();
ServerSession session = JUnitTestCase.getServerSession();
session.logout();
session.getDescriptor(BeerConsumer.class).setObjectChangePolicy(origPolicy);
session.login();
}
};
}
use of org.eclipse.persistence.descriptors.changetracking.ObjectChangePolicy in project eclipselink by eclipse-ee4j.
the class FetchGroupManager method writePartialIntoClones.
/**
* INTERNAL:
* Write data of the partially fetched object into the working and backup clones
*/
public void writePartialIntoClones(Object partialObject, Object workingClone, Object backupClone, UnitOfWorkImpl uow) {
FetchGroup fetchGroupInClone = ((FetchGroupTracker) workingClone)._persistence_getFetchGroup();
FetchGroup fetchGroupInObject = ((FetchGroupTracker) partialObject)._persistence_getFetchGroup();
// Update fetch group in clone as the union of two,
// do this first to avoid fetching during method access.
// this method is not called for aggregates
EntityFetchGroup union = flatUnionFetchGroups(fetchGroupInObject, fetchGroupInClone, false);
// Finally, update clone's fetch group reference.
setObjectFetchGroup(workingClone, union, uow);
if (workingClone != backupClone) {
setObjectFetchGroup(backupClone, union, uow);
}
ObjectChangePolicy policy = descriptor.getObjectChangePolicy();
// Turn it 'off' to prevent unwanted events.
policy.dissableEventProcessing(workingClone);
try {
// if refresh is set, force to fill in fetch group data
if (((FetchGroupTracker) partialObject)._persistence_shouldRefreshFetchGroup()) {
// refresh and fill in the fetch group data
refreshFetchGroupIntoClones(partialObject, workingClone, backupClone, fetchGroupInObject, fetchGroupInClone, uow);
} else {
// no refresh is enforced
// revert the unfetched attributes of the clones.
revertDataIntoUnfetchedAttributesOfClones(partialObject, workingClone, backupClone, fetchGroupInObject, fetchGroupInClone, uow);
}
} finally {
policy.enableEventProcessing(workingClone);
}
}
use of org.eclipse.persistence.descriptors.changetracking.ObjectChangePolicy in project eclipselink by eclipse-ee4j.
the class OrderListTestModel method setup.
@Override
public void setup() {
if (!isTopLevel) {
if (changeTracking == ChangeTracking.ATTRIBUTE) {
// Save change policies for the all employee demo class in order to restore them at reset time.
Map<Class<?>, ObjectChangePolicy> originalChangeTrackingPolicies = new HashMap<>();
originalChangeTrackingPolicies.put(Employee.class, getSession().getDescriptor(Employee.class).getObjectChangePolicy());
getSession().getDescriptor(Employee.class).setObjectChangePolicy(new AttributeChangeTrackingPolicy());
originalChangeTrackingPolicies.put(Project.class, getSession().getDescriptor(Project.class).getObjectChangePolicy());
getSession().getDescriptor(Project.class).setObjectChangePolicy(new AttributeChangeTrackingPolicy());
originalChangeTrackingPolicies.put(SmallProject.class, getSession().getDescriptor(SmallProject.class).getObjectChangePolicy());
getSession().getDescriptor(SmallProject.class).setObjectChangePolicy(new AttributeChangeTrackingPolicy());
originalChangeTrackingPolicies.put(LargeProject.class, getSession().getDescriptor(LargeProject.class).getObjectChangePolicy());
getSession().getDescriptor(LargeProject.class).setObjectChangePolicy(new AttributeChangeTrackingPolicy());
// currently attribute change tracking is incompatible with AggregateCollectionMapping
if (this.changeTracking != ChangeTracking.ATTRIBUTE) {
originalChangeTrackingPolicies.put(PhoneNumber.class, getSession().getDescriptor(PhoneNumber.class).getObjectChangePolicy());
getSession().getDescriptor(PhoneNumber.class).setObjectChangePolicy(new AttributeChangeTrackingPolicy());
}
}
}
}
Aggregations