From d826caf71175811a23214b4e23545aee7625d7ed Mon Sep 17 00:00:00 2001 From: "Kevin W. Sutter" Date: Fri, 2 Feb 2007 21:12:35 +0000 Subject: [PATCH] OPENJPA-119. Needed to allow the EM.clear operation to perform without doing an implicit flush. Introduced a new boolean parameter to indicate whether a flush is desired or not. This allows both the new (correct) behaviour for JPA as well as the old behaviour for other persistence personalities (JDO, etc). I also introduced a new testcase for this scenario, and updated a couple of other tests. git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@502751 13f79535-47bb-0310-9956-ffa450edef68 --- .../openjpa/kernel/AbstractBrokerFactory.java | 2 + .../org/apache/openjpa/kernel/Broker.java | 13 ++- .../org/apache/openjpa/kernel/BrokerImpl.java | 9 +- .../openjpa/kernel/DelegatingBroker.java | 8 ++ .../simple/TestEntityManagerClear.java | 104 ++++++++++++++++++ ...stEntityManagerMethodsThrowAfterClose.java | 2 +- .../persistence/simple/TestPersistence.java | 20 ---- .../persistence/EntityManagerImpl.java | 2 +- 8 files changed, 136 insertions(+), 24 deletions(-) create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestEntityManagerClear.java diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java index 5f1c5b6fb..9ae336108 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java @@ -287,6 +287,8 @@ public abstract class AbstractBrokerFactory Broker broker; for (Iterator itr = _brokers.iterator(); itr.hasNext();) { broker = (Broker) itr.next(); + /* Check for null here because _brokers is a weak reference + collection */ if ((broker != null) && (!broker.isClosed())) broker.close(); } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Broker.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Broker.java index e6795238c..18d716efd 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Broker.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Broker.java @@ -473,10 +473,21 @@ public interface Broker public void evictAll(Extent extent, OpCallbacks call); /** - * Detach all objects in place. + * Detach all objects in place. A flush will be performed before + * detaching the entities. */ public void detachAll(OpCallbacks call); + /** + * Detach all objects in place, with the option of performing a + * flush before doing the detachment. + * @param call Persistence operation callbacks + * @param flush boolean value to indicate whether to perform a + * flush before detaching the entities (true, do the flush; + * false, don't do the flush) + */ + public void detachAll(OpCallbacks call, boolean flush); + /** * Detach the specified object from the broker. * diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java index a89550bf4..0aca96146 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java @@ -3088,9 +3088,16 @@ public class BrokerImpl } public void detachAll(OpCallbacks call) { + detachAll(call, true); + } + + public void detachAll(OpCallbacks call, boolean flush) { beginOperation(true); try { - if ((_flags & FLAG_FLUSH_REQUIRED) != 0) + /* If a flush is desired (based on input parm), then check if the + * "dirty" flag is set before calling flush(). + */ + if ((flush) && ((_flags & FLAG_FLUSH_REQUIRED) != 0)) flush(); detachAllInternal(call); } catch (OpenJPAException ke) { diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java index 71d5344c9..1eb597a5d 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java @@ -1115,6 +1115,14 @@ public class DelegatingBroker } } + public void detachAll(OpCallbacks call, boolean flush) { + try { + _broker.detachAll(call, flush); + } catch (RuntimeException re) { + throw translate(re); + } + } + public Object attach(Object obj, boolean copyNew, OpCallbacks call) { try { return _broker.attach(obj, copyNew, call); diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestEntityManagerClear.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestEntityManagerClear.java new file mode 100644 index 000000000..46c895d64 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestEntityManagerClear.java @@ -0,0 +1,104 @@ +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed 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.simple; + +import java.util.HashMap; +import java.util.Map; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +import junit.framework.TestCase; +import junit.textui.TestRunner; + +/** + * Test case to ensure that the proper JPA clear semantics are processed. + * + * @author Kevin Sutter + */ +public class TestEntityManagerClear + extends TestCase { + + private EntityManagerFactory emf; + private EntityManager em; + + public void setUp() { + Map props = new HashMap(System.getProperties()); + props.put("openjpa.MetaDataFactory", + "jpa(Types=" + AllFieldTypes.class.getName() + ")"); + emf = Persistence.createEntityManagerFactory("test", props); + } + + public void tearDown() { + if (emf == null) + return; + try { + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + em.createQuery("delete from AllFieldTypes").executeUpdate(); + em.getTransaction().commit(); + em.close(); + emf.close(); + } catch (Exception e) { + } + } + public void testClear() { + try { + // Create EntityManager and Start a transaction (1) + em = emf.createEntityManager(); + em.getTransaction().begin(); + + // Insert a new object and flush + AllFieldTypes testObject1 = new AllFieldTypes(); + testObject1.setStringField("my test object1"); + em.persist(testObject1); + em.flush(); + + // Clear the PC for new object 2 + AllFieldTypes testObject2 = new AllFieldTypes(); + testObject1.setStringField("my test object2"); + em.persist(testObject2); + em.clear(); + + // Commit the transaction (only object 1 should be in database) + em.getTransaction().commit(); + + // Start a new transaction + em.getTransaction().begin(); + + // Attempt retrieve of Object1 from previous PC (should exist) + assertEquals(1, em.createQuery + ("select x from AllFieldTypes x where x.stringField = 'my test object1'"). + getResultList().size()); + + // Attempt retrieve of Object2 from previous PC (should not exist) + assertEquals(0, em.createQuery + ("select x from AllFieldTypes x where x.stringField = 'my test object2'"). + getResultList().size()); + + // Rollback the transaction and close everything + em.getTransaction().rollback(); + em.close(); + } catch (Exception ex) { + fail("Unexpected Exception ex = " + ex); + } + } + + public static void main(String[] args) { + TestRunner.run(TestEntityManagerClear.class); + } +} + diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestEntityManagerMethodsThrowAfterClose.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestEntityManagerMethodsThrowAfterClose.java index 3529dbeeb..9b61f5178 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestEntityManagerMethodsThrowAfterClose.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestEntityManagerMethodsThrowAfterClose.java @@ -271,7 +271,7 @@ public class TestEntityManagerMethodsThrowAfterClose } public static void main(String[] args) { - TestRunner.run(TestPersistence.class); + TestRunner.run(TestEntityManagerMethodsThrowAfterClose.class); } } diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestPersistence.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestPersistence.java index 3b6d69a31..62063dd35 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestPersistence.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestPersistence.java @@ -107,26 +107,6 @@ public class TestPersistence em.close(); } - /** - * Ensures that an IllegalStateException is thrown if getDelegate is called - * after closing the EntityManager. - */ - public void testGetDelegateAfterClose() { - EntityManager em = emf.createEntityManager(); - - em.close(); - - try { - Object o = em.getDelegate(); - fail(); - } - catch(IllegalStateException ise) { - /* - * An IllegalStateException is expected. Nothing to do here. - */ - } - } - public static void main(String[] args) { TestRunner.run(TestPersistence.class); } diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java index ce73c78fd..61632b7a9 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java @@ -853,7 +853,7 @@ public class EntityManagerImpl public void clear() { assertNotCloseInvoked(); - _broker.detachAll(this); + _broker.detachAll(this, false); } public Object getDelegate() {