blob: 0688cd92c5b493f7c4787dd06ea93ea9c12be1fb [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.jdbc.kernel;
import java.util.*;
import org.apache.openjpa.kernel.*;
import org.apache.openjpa.jdbc.conf.*;
import org.apache.openjpa.persistence.jdbc.common.apps.*;
import java.lang.annotation.Annotation;
import junit.framework.*;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.FetchPlan;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.persistence.OpenJPAPersistence;
import org.apache.openjpa.persistence.jdbc.kernel.TestSQLListenerTestCase;
/**
* Test various bits of embedded-field functionality.
* <p/>
* ##### this should test embedded-element collections, maps, at least to ensure
* ##### that the state managers of values in embedded collections, maps do not
* ##### have owners. Not relevant in 3.x; will be important in 4.0.
*/
public class TestEmbeddedPessimisticLocking
extends TestSQLListenerTestCase {
private boolean supportsLocking;
private Object oid;
private OpenJPAEntityManagerFactory emf;
public TestEmbeddedPessimisticLocking(String name)
{
super(name);
}
public void setUp() throws Exception{
super.setUp();
emf = (OpenJPAEntityManagerFactory)getEmf(getProps());
}
public void setUpTestCase() {
JDBCConfiguration conf = (JDBCConfiguration) ((OpenJPAEntityManagerFactorySPI) OpenJPAPersistence.cast(emf)).getConfiguration();
supportsLocking = conf.getDBDictionaryInstance().supportsSelectForUpdate;
deleteAll(EmbeddedOwnerPC.class);
OpenJPAEntityManager em =(OpenJPAEntityManager)currentEntityManager();
startTx(em);
EmbeddedOwnerPC owner = new EmbeddedOwnerPC(10, 20);
em.persist(owner);
EmbeddedPC embedded = new EmbeddedPC();
embedded.setIntField(4);
embedded.setStringField("foo");
owner.setEmbedded(embedded);
EmbeddedPC embedded2 = new EmbeddedPC();
embedded2.setIntField(8);
embedded2.setStringField("bar");
ComplexEmbeddedPC complex = new ComplexEmbeddedPC();
complex.setStringField("complex");
complex.setEmbedded(embedded2);
owner.setComplexEmbedded(complex);
endTx(em);
oid = em.getObjectId(owner);
em.close();
}
private void prepareEMF(OpenJPAEntityManagerFactory emf) {
// do this to ensure that the SELECT DISTINCT gets performed here.
OpenJPAEntityManager em = emf.createEntityManager();
//FIXME jthomas commenting this since setOptimistic is not available for userTx
//em.getTransaction().setOptimistic(false);
startTx(em);
try {
EmbeddedOwnerPC pc = (EmbeddedOwnerPC) em.getObjectId(oid);
} finally {
rollbackTx(em);
em.close();
}
}
public void testEmbeddedFieldsWithLockedParent() {
OpenJPAEntityManager em =(OpenJPAEntityManager)currentEntityManager();
prepareEMF(em.getEntityManagerFactory());
((FetchPlan) em.getFetchPlan()).addField(EmbeddedOwnerPC.class, "embedded");
//FIXME jthomas commenting this since setOptimistic is not available for userTx
// pm.currentTransaction().setOptimistic(false);
startTx(em);
try {
sql.clear();
EmbeddedOwnerPC pc = (EmbeddedOwnerPC) em.getObjectId(oid);
assertEquals(1, sql.size());
pc.getEmbedded().setStringField
(pc.getEmbedded().getStringField() + "bar");
// should not go to the db for another lock; we use <=, since
// some databases (like HSQL) don't support locking at all
assertTrue(sql.size() <= 1);
} finally {
rollbackTx(em);
em.close();
}
}
public void testEmbeddedFieldsWithUnlockedParent() {
OpenJPAEntityManager em =(OpenJPAEntityManager)currentEntityManager();
prepareEMF(em.getEntityManagerFactory());
((FetchPlan) em.getFetchPlan()).addField(EmbeddedOwnerPC.class, "embedded");
//FIXME jthomas commenting this since setOptimistic is not available for userTx
// pm.currentTransaction().setOptimistic(false);
startTx(em);
try {
//FIXME jthomas - no equivalent found for LockLevels.LOCK_NONE
//((FetchPlan) pm.getFetchPlan()).setReadLockMode(LockLevels.LOCK_NONE);
sql.clear();
EmbeddedOwnerPC pc = (EmbeddedOwnerPC) em.getObjectId(oid);
EmbeddedPC embedded = pc.getEmbedded();
assertNull(getStateManager(pc, em).getLock());
assertNull(getStateManager(embedded, em).getLock());
assertEquals(1, sql.size());
sql.clear();
embedded.setStringField(embedded.getStringField() + "bar");
// should not go to the db for another lock -- should have gotten
// one along with the embedded field's lock
assertTrue(sql.size() <= 1);
assertNotNull(getStateManager(pc, em).getLock());
// embeddeds don't get locks at all.
assertNull(getStateManager(embedded, em).getLock());
// owner is dirtied when embedded record is changed
assertTrue(getStateManager(pc, em).isDirty());
assertTrue(getStateManager(embedded, em).isDirty());
pc.setStringField(pc.getStringField() + "bar");
// should not go to the db for another lock.
assertTrue(sql.size() <= 1);
} finally {
rollbackTx(em);
em.close();
}
}
public void testComplexEmbeddedFieldsWithLockedParent() {
OpenJPAEntityManager em =(OpenJPAEntityManager)currentEntityManager();
prepareEMF(em.getEntityManagerFactory());
em.getFetchPlan().setMaxFetchDepth(-1);
((FetchPlan) em.getFetchPlan()).addField(EmbeddedOwnerPC.class, "complexEmbedded");
((FetchPlan) em.getFetchPlan()).addField(RecursivelyEmbeddedPC.class, "embedded");
//FIXME jthomas commenting this since setOptimistic is not available for userTx
// pm.currentTransaction().setOptimistic(false);
startTx(em);
try {
sql.clear();
EmbeddedOwnerPC pc = (EmbeddedOwnerPC) em.getObjectId(oid);
assertEquals(1, sql.size());
pc.getComplexEmbedded().getEmbedded().setStringField
(pc.getComplexEmbedded().getEmbedded().getStringField() +
"bar");
// should not go to the db for another lock.
assertTrue(sql.size() <= 1);
} finally {
rollbackTx(em);
em.close();
}
}
public void testComplexEmbeddedFieldsWithUnlockedParent() {
// doing this because setting the read lock level
// does not seem to be disabling FOR UPDATE.
OpenJPAEntityManager em =(OpenJPAEntityManager)currentEntityManager();
prepareEMF(em.getEntityManagerFactory());
em.getFetchPlan().setMaxFetchDepth(-1);
((FetchPlan) em.getFetchPlan()).addField(EmbeddedOwnerPC.class, "complexEmbedded");
((FetchPlan) em.getFetchPlan()).addField(RecursivelyEmbeddedPC.class, "embedded");
//FIXME jthomas commenting this since setOptimistic is not available for userTx
// pm.currentTransaction().setOptimistic(false);
startTx(em);
try {
//FIXME jthomas FetchPlan.LOCK_NONE??
//((FetchPlan) em.getFetchPlan()).setReadLockLevel
// (FetchPlan.LOCK_NONE);
sql.clear();
EmbeddedOwnerPC pc = (EmbeddedOwnerPC) em.getObjectId(oid);
ComplexEmbeddedPC complex = pc.getComplexEmbedded();
EmbeddedPC embedded = complex.getEmbedded();
assertNull(getStateManager(pc, em).getLock());
assertNull(getStateManager(complex, em).getLock());
assertNull(getStateManager(embedded, em).getLock());
assertEquals(1, sql.size());
sql.clear();
embedded.setStringField(embedded.getStringField() + "bar");
// should not go to the db for another lock -- should have gotten
// one along with the embedded field's lock
assertTrue(sql.size() <= 1);
assertNotNull(getStateManager(pc, em).getLock());
// embeddeds don't get locks at all.
assertNull(getStateManager(complex, em).getLock());
assertNull(getStateManager(embedded, em).getLock());
// owner is dirtied when embedded record is changed
assertTrue(getStateManager(pc, em).isDirty());
assertTrue(getStateManager(complex, em).isDirty());
assertTrue(getStateManager(embedded, em).isDirty());
complex.setStringField(complex.getStringField() + "bar");
// should not go to the db for another lock.
assertTrue(sql.size() <= 1);
pc.setStringField(pc.getStringField() + "bar");
// should not go to the db for another lock.
assertTrue(sql.size() <= 1);
} finally {
rollbackTx(em);
em.close();
}
}
private Map getProps() {
Map props=new HashMap();
props.put("openjpa.DataCache", "true");
props.put("openjpa.RemoteCommitProvider", "sjvm");
props.put("openjpa.FlushBeforeQueries", "true");
props.put("javax.jdo.option.IgnoreCache", "false");
//propsMap.put("openjpa.BrokerImpl", "kodo.datacache.CacheTestBroker");//CacheTestBroker.class.getName ());
return props;
}
}