blob: 8aeb3e4a55afddbc5cf794be6ecbce4aa29529aa [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 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 v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.testing.tests.unitofwork;
import java.math.BigDecimal;
import java.util.Vector;
import org.eclipse.persistence.expressions.ExpressionBuilder;
import org.eclipse.persistence.queries.ReadObjectQuery;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.UnitOfWork;
import org.eclipse.persistence.testing.framework.AutoVerifyTestCase;
import org.eclipse.persistence.testing.framework.TestErrorException;
import org.eclipse.persistence.testing.framework.TestWarningException;
public class ConcurrentRefreshOnCloneTest extends AutoVerifyTestCase {
// used as monitor for test
public static ConcurrentAddress lock;
//stores the cloned copy of the lock object
public static ConcurrentAddress clone;
//stores a copy of the original values
public static ConcurrentAddress original;
public static boolean cloneWaiting = false;
public static boolean readerWaiting = false;
//attribute stores if the thread has waiting to prevent the back clone from entering a wait state
public static boolean waited = false;
//used in remote unit of work tests to control when the lock is released
public static int depth;
public boolean toClone;
//session for the threads
public static Session session;
//stores the original cache isolation level for this session
int originalIsolationLevel;
public ConcurrentRefreshOnCloneTest() {
}
public ConcurrentRefreshOnCloneTest(boolean toClone) {
this.toClone = toClone;
}
@Override
public void setup() {
if (getSession().isDistributedSession()) {
throw new TestWarningException("Test unavailable on Remote UnitOfWork because of timing issues");
}
getSession().getIdentityMapAccessor().initializeAllIdentityMaps();
ConcurrentRefreshOnCloneTest.session = getSession();
ConcurrentRefreshOnCloneTest.waited = false;
ConcurrentAddress newAddress = new ConcurrentAddress();
newAddress.id = new BigDecimal(15);
newAddress.city = "Meductic";
newAddress.country = "Canada";
newAddress.postalCode = "C1C 1C1";
newAddress.province = "New Brunswick";
newAddress.street = "St. Jermone";
UnitOfWork uow = getSession().acquireUnitOfWork();
uow.registerObject(newAddress);
uow.commit();
ConcurrentRefreshOnCloneTest.lock = newAddress;
this.originalIsolationLevel = getSession().getLogin().getCacheTransactionIsolation();
getSession().getLogin().setCacheTransactionIsolation(org.eclipse.persistence.sessions.DatasourceLogin.SYNCHRONIZED_READ_ON_WRITE);
}
@Override
public void test() {
ConcurrentRefreshOnCloneTest.lock.city = "Some Large City";
ConcurrentRefreshOnCloneTest.lock.country = "Some Small Country";
ConcurrentRefreshOnCloneTest.lock.postalCode = "A1A 1A1";
ConcurrentRefreshOnCloneTest.lock.province = "No Nation";
ConcurrentRefreshOnCloneTest.lock.street = "No Name";
ConcurrentRefreshOnCloneTest.original = (ConcurrentAddress)ConcurrentRefreshOnCloneTest.lock.clone();
Vector primaryKey = new Vector(1);
primaryKey.add(ConcurrentRefreshOnCloneTest.lock.getId());
Thread thread1 = null;
Thread thread2 = null;
try {
thread1 = new Thread(new ConcurrentRefreshOnCloneTest(true).runnable());
//start the thread and wait for the thread to get under way before continueing.
thread1.start();
thread2 = new Thread(new ConcurrentRefreshOnCloneTest(false).runnable());
//start the thread and wait for the thread to get under way before continueing.
thread2.start();
} catch (Exception ex) {
System.out.println("Exception" + ex.toString());
//just ignore
}
try {
thread1.join();
thread2.join();
} catch (Exception ex) {
//just an inturrupt ignore
}
if (getAbstractSession().compareObjectsDontMatch(ConcurrentRefreshOnCloneTest.lock,
ConcurrentRefreshOnCloneTest.clone)) {
if (getAbstractSession().compareObjectsDontMatch(ConcurrentRefreshOnCloneTest.original,
ConcurrentRefreshOnCloneTest.clone)) {
throw new TestErrorException("The test failed to clone the object without data corruption");
}
}
}
public Runnable runnable() {
return new Runnable() {
@Override
public void run() {
if (ConcurrentRefreshOnCloneTest.this.toClone) {
UnitOfWork uow = ConcurrentRefreshOnCloneTest.session.acquireUnitOfWork();
ConcurrentRefreshOnCloneTest.clone =
(ConcurrentAddress)uow.registerObject(ConcurrentRefreshOnCloneTest.lock);
} else {
try {
//sleep here to let the register catch up,
//can not wait here as the cloning thread may never wait if a read lock is acquired
Thread.sleep(5000);
} catch (Exception ex) {
}
ReadObjectQuery query = new ReadObjectQuery(ConcurrentAddress.class);
query.setShouldRefreshIdentityMapResult(true);
query.setSelectionCriteria(new ExpressionBuilder().get("id").equal(ConcurrentRefreshOnCloneTest.lock.getId()));
ConcurrentRefreshOnCloneTest.session.executeQuery(query);
try {
if (ConcurrentRefreshOnCloneTest.lock != null) {
synchronized (ConcurrentRefreshOnCloneTest.lock) {
ConcurrentRefreshOnCloneTest.lock.notifyAll();
}
}
} catch (Exception ex) {
}
}
}
};
}
@Override
public void reset() {
UnitOfWork uow = getSession().acquireUnitOfWork();
uow.deleteObject(ConcurrentRefreshOnCloneTest.original);
ConcurrentRefreshOnCloneTest.lock = null;
uow.commit();
getSession().getIdentityMapAccessor().initializeAllIdentityMaps();
getSession().getLogin().setCacheTransactionIsolation(this.originalIsolationLevel);
}
}