blob: a943613c311ee945a6bb260910f062378bc48361 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.persistence.lockmgr;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.LockModeType;
import javax.persistence.PessimisticLockScope;
import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
import org.apache.openjpa.persistence.test.SQLListenerTestCase;
public class TestLocking extends SQLListenerTestCase {
String _phone = "5075555555";
@Override
protected String getPersistenceUnitName() {
return "locking-test";
}
public void setUp() {
super.setUp(CLEAR_TABLES, Person.class, PhoneNumber.class
// ,"openjpa.Log", "SQL=trace"
);
populate();
}
public void testExtendedLockScope() throws Exception {
Map<String, Object> props = new HashMap<String, Object>();
props.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED);
OpenJPAEntityManagerSPI em1 = emf.createEntityManager();
OpenJPAEntityManagerSPI em2 = emf.createEntityManager();
CommitterThread committer = new CommitterThread(em2);
em1.getTransaction().begin();
Person e1 = em1.find(Person.class, 1);
assertEquals(1, e1.getPhoneNumbers().size());
// This SHOULD lock Employee with id=1 AND the join table.
//
// pg 86
// Element collections and relationships owned by the entity that are contained in join tables will be
// locked if the javax.persistence.lock.scope property is specified with a value of
// PessimisticLockScope.EXTENDED. The state of entities referenced by such relationships will
// not be locked (unless those entities are explicitly locked). This property may be passed as an argument
// to the methods of the EntityManager, Query, and TypedQuery interfaces that allow lock modes
// to be specified or used with the NamedQuery annotation.
em1.refresh(e1, LockModeType.PESSIMISTIC_FORCE_INCREMENT, props);
// Kick off the committer thread
committer.start();
// Make sure to sleep at least for 5 seconds AFTER the committer calls commit
while (System.currentTimeMillis() - committer.sleepStartTime < 5000) {
Thread.sleep(5000);
}
// The committer should still be waiting because the em1.refresh(...) call should have locked the join table and
// the remove can't complete
assertFalse(committer.commitComplete);
em1.getTransaction().commit();
em1.close();
// wait for child thread to finish
committer.join();
}
private class CommitterThread extends Thread {
OpenJPAEntityManagerSPI _em2;
boolean inCommit = false;
boolean commitComplete = false;
long sleepStartTime = Long.MAX_VALUE;
public CommitterThread(OpenJPAEntityManagerSPI e) {
_em2 = e;
}
@Override
public void run() {
_em2.getTransaction().begin();
PhoneNumber phoneNumber = _em2.find(PhoneNumber.class, _phone);
_em2.remove(phoneNumber);
inCommit = true;
sleepStartTime = System.currentTimeMillis();
_em2.getTransaction().commit();
commitComplete = true;
_em2.close();
}
}
private void populate() {
OpenJPAEntityManagerSPI em = emf.createEntityManager();
em.getTransaction().begin();
PhoneNumber p = new PhoneNumber(_phone);
List<PhoneNumber> numbers = Arrays.asList(new PhoneNumber[] { p });
Person e1 = new Person();
e1.setId(1);
e1.setPhoneNumbers(numbers);
Person e2 = new Person();
e2.setId(2);
e2.setPhoneNumbers(numbers);
p.setOwners(Arrays.asList(new Person[] { e1, e2 }));
em.persist(e1);
em.persist(e2);
em.persist(p);
em.getTransaction().commit();
em.close();
}
}