blob: bd3c381ace8e7b71d9aa198e2045fa2bd58f6fc2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.testing.tests.queries;
import org.eclipse.persistence.descriptors.*;
import org.eclipse.persistence.expressions.*;
import org.eclipse.persistence.mappings.*;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.queries.*;
import org.eclipse.persistence.sessions.*;
import org.eclipse.persistence.exceptions.*;
import org.eclipse.persistence.testing.models.employee.domain.*;
import org.eclipse.persistence.testing.framework.*;
/**
* Tests fine-grained / descriptor level pessimistic locking with joined
* attributes.
* <p>
* Specifically tests the unusual cases of bug 3422202, and makes sure the
* joined attributes are properly recorded with the correct session.
* <p>
* This test must be run using the ServerSessionTestAdaptor, so that each
* UnitOfWork is on a separate UnitOfWork, each having their own transaction
* but still sharing the global cache.
* <p>
* Test cases:
* <ul>
* <li>Query on a project, where team leader and its address are joined. Query
* for both the address and the employee: and check the SQL to see if had
* a cache hit (or checkCacheOnly).
* <li>Query on a project, where team leader is joined. Then in a separate UnitOfWork
* query on the same project where team leader is not joined, and then attempt
* project.getTeamLeader(). This should fail.
* <li>Query on a project, where team leader is not joined. Then in a separate
* UnitOfWork query on the project where team leader is joined. Then try to
* get the teamleader on the first UnitOfWork. This should fail.
* <li>Query on a project, where team leader is joined, and rollback. Change
* the cache copy and then have another read the project where team leader is
* joined. The query and the refresh should succeed.
* </ul>
*/
public class PessimisticLockJoinedAttributeTest extends TestCase {
public UnitOfWork uow;
public short lockMode;
CMPPolicy oldCMPPolicy;
/**
* PessimisticLockInheritanceTest constructor comment.
*/
public PessimisticLockJoinedAttributeTest() {
this.lockMode = ObjectLevelReadQuery.LOCK_NOWAIT;
setDescription("For bug 3422202 verifies the pessimistic locking feature works properly when set on the descriptor and joined attributes are involved.");
}
protected void setup() {
getSession().getIdentityMapAccessor().initializeIdentityMaps();
PessimisticLockingPolicy policy = new PessimisticLockingPolicy();
policy.setLockingMode(this.lockMode);
CMPPolicy cmpPolicy = new CMPPolicy();
cmpPolicy.setPessimisticLockingPolicy(policy);
ClassDescriptor projectDescriptor = getSession().getDescriptor(org.eclipse.persistence.testing.models.employee.domain.Project.class);
((ObjectLevelReadQuery)((ForeignReferenceMapping)projectDescriptor.getMappingForAttributeName("teamLeader")).getSelectionQuery()).setLockMode(ObjectLevelReadQuery.DEFAULT_LOCK_MODE);
ClassDescriptor employeeDescriptor = getSession().getDescriptor(Employee.class);
oldCMPPolicy = employeeDescriptor.getCMPPolicy();
employeeDescriptor.setCMPPolicy(cmpPolicy);
employeeDescriptor.getQueryManager().getReadObjectQuery().setLockMode(ObjectLevelReadQuery.DEFAULT_LOCK_MODE);
((ObjectLevelReadQuery)((ForeignReferenceMapping)employeeDescriptor.getMappingForAttributeName("address")).getSelectionQuery()).setLockMode(ObjectLevelReadQuery.DEFAULT_LOCK_MODE);
ClassDescriptor addressDescriptor = getSession().getDescriptor(Address.class);
addressDescriptor.setCMPPolicy(cmpPolicy);
addressDescriptor.getQueryManager().getReadObjectQuery().setLockMode(ObjectLevelReadQuery.DEFAULT_LOCK_MODE);
}
public void reset() {
getSession().getIdentityMapAccessor().initializeAllIdentityMaps();
if (uow != null) {
uow.release();
}
ClassDescriptor projectDescriptor = getSession().getDescriptor(org.eclipse.persistence.testing.models.employee.domain.Project.class);
((ObjectLevelReadQuery)((ForeignReferenceMapping)projectDescriptor.getMappingForAttributeName("teamLeader")).getSelectionQuery()).setLockMode(ObjectLevelReadQuery.DEFAULT_LOCK_MODE);
((ObjectLevelReadQuery)((ForeignReferenceMapping)projectDescriptor.getMappingForAttributeName("teamLeader")).getSelectionQuery()).dontRefreshIdentityMapResult();
ClassDescriptor employeeDescriptor = getSession().getDescriptor(Employee.class);
employeeDescriptor.setCMPPolicy(oldCMPPolicy);
employeeDescriptor.getQueryManager().getReadObjectQuery().setLockMode(ObjectLevelReadQuery.DEFAULT_LOCK_MODE);
((ObjectLevelReadQuery)((ForeignReferenceMapping)employeeDescriptor.getMappingForAttributeName("address")).getSelectionQuery()).setLockMode(ObjectLevelReadQuery.DEFAULT_LOCK_MODE);
((ObjectLevelReadQuery)((ForeignReferenceMapping)employeeDescriptor.getMappingForAttributeName("address")).getSelectionQuery()).dontRefreshIdentityMapResult();
ClassDescriptor addressDescriptor = getSession().getDescriptor(Address.class);
addressDescriptor.setCMPPolicy(oldCMPPolicy);
addressDescriptor.getQueryManager().getReadObjectQuery().setLockMode(ObjectLevelReadQuery.DEFAULT_LOCK_MODE);
}
public void test() throws Exception {
if (!getSession().getPlatform().isOracle() && !getSession().getPlatform().isSQLServer()) {
throw new TestWarningException("This test only runs on Oracle wears writes do not block reads.");
}
uow = getSession().acquireUnitOfWork();
ReadObjectQuery query = new ReadObjectQuery(LargeProject.class);
// Only Charles Chanley and John Way are team leaders of projects they are also working on.
Expression expression = query.getExpressionBuilder().get("teamLeader").get("firstName").equal("Charles");
query.setSelectionCriteria(expression);
query.addJoinedAttribute(query.getExpressionBuilder().get("teamLeader"));
query.addJoinedAttribute(query.getExpressionBuilder().get("teamLeader").get("address"));
Object result = uow.executeQuery(query);
// Now trigger the valueholders... These clones should be registered in
// the uow and marked as already locked.
// Check the SQL so that none gets issued.
Employee charles = (Employee)((LargeProject)result).getTeamLeader();
Address address = charles.getAddress();
ReadObjectQuery cacheQuery = null;
Object cachedObject = null;
// There is only one address in the cache, and it will only be returned
// if it was tracked as being locked.
cacheQuery = new ReadObjectQuery(Address.class);
cacheQuery.checkCacheThenDatabase();
cachedObject = uow.executeQuery(cacheQuery);
if (address != cachedObject) {
throw new TestErrorException("Did not get a cache hit after pessimistically locking a nested joined attribute.");
}
cacheQuery = new ReadObjectQuery(org.eclipse.persistence.testing.models.employee.domain.Employee.class);
cacheQuery.checkCacheThenDatabase();
cachedObject = uow.executeQuery(cacheQuery);
if (charles != cachedObject) {
throw new TestErrorException("Did not get a cache hit after pessimisticly locking a joined attribute.");
}
// Test the lock.
// Because this is on a ServerSession the second UOW will have its own
// ClientSession/exclusive connection.
UnitOfWork uow2 = getSession().acquireUnitOfWork();
try {
boolean isLocked = false;
query = new ReadObjectQuery(LargeProject.class);
expression = query.getExpressionBuilder().get("teamLeader").get("firstName").equal("Charles");
query.setSelectionCriteria(expression);
LargeProject result2 = (LargeProject)uow2.executeQuery(query);
// assert(result2 != null, "It was never meant to be locked.");
try {
result2.getTeamLeader();
} catch (EclipseLinkException exception) {
isLocked = true;
}
if (!isLocked) {
throw new TestErrorException("Triggering an attribute that was locked by another in a joined read should trigger a no_wait exception.");
}
// Now release the first UnitOfWork and try again.
Employee originalCharles = (Employee)uow.getOriginalVersionOfObject(charles);
uow.release();
uow = null;
// Now change the session copy, this is what would happen if the
// object was actually committed to the database. Want to test that
// the object is refreshed when locked.
originalCharles.setSalary(0);
try {
charles = (Employee)result2.getTeamLeader();
address = charles.getAddress();
} catch (EclipseLinkException exception) {
throw new TestErrorException("Now that a joined attribute locked by UOW1 has been released it should be readable now.");
}
if (charles.getSalary() == 0) {
throw new TestErrorException("When a joined attribute is locked by another after it is released, should get refreshed.");
}
} catch (RuntimeException e) {
throw e;
} finally {
if (uow2 != null) {
uow2.release();
}
}
}
}