/* | |
* 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; | |
} | |
} |