/* * Copyright 2009-2016 Tilmann Zaeschke. All rights reserved. * * This file is part of ZooDB. * * ZooDB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ZooDB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ZooDB. If not, see <http://www.gnu.org/licenses/>. * * See the README and COPYING files for further information. */ package org.zoodb.test.jdo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.Collection; import java.util.HashSet; import java.util.Set; import javax.jdo.Constants; import javax.jdo.JDOHelper; import javax.jdo.JDOUserException; import javax.jdo.ObjectState; import javax.jdo.PersistenceManager; import javax.jdo.PersistenceManagerFactory; import javax.jdo.Query; import javax.jdo.listener.DetachLifecycleListener; import javax.jdo.listener.InstanceLifecycleEvent; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.zoodb.jdo.ZooJdoHelper; import org.zoodb.jdo.ZooJdoProperties; import org.zoodb.schema.ZooClass; import org.zoodb.schema.ZooHandle; import org.zoodb.schema.ZooSchema; import org.zoodb.test.testutil.TestTools; public class Test_130_DetachAllOnCommit { @BeforeClass public static void setUp() { TestTools.createDb(); TestTools.defineSchema(TestClass.class); } @Before public void before() { TestTools.dropInstances(TestClass.class); } @Test public void testPropertyPropagation() { ZooJdoProperties props = new ZooJdoProperties(TestTools.getDbName()); PersistenceManagerFactory pmf; PersistenceManager pm; //all false, vary pm assertEquals("false", props.getProperty(Constants.PROPERTY_DETACH_ALL_ON_COMMIT)); pmf = JDOHelper.getPersistenceManagerFactory(props); assertFalse(pmf.getDetachAllOnCommit()); pm = pmf.getPersistenceManager(); assertFalse(pm.getDetachAllOnCommit()); pm.setDetachAllOnCommit(true); assertTrue(pm.getDetachAllOnCommit()); pm.setDetachAllOnCommit(false); assertFalse(pm.getDetachAllOnCommit()); pm.close(); //pmf true, vary pm pmf = JDOHelper.getPersistenceManagerFactory(props); pmf.setDetachAllOnCommit(true); assertTrue(pmf.getDetachAllOnCommit()); pm = pmf.getPersistenceManager(); assertTrue(pm.getDetachAllOnCommit()); pm.setDetachAllOnCommit(false); assertFalse(pm.getDetachAllOnCommit()); pm.setDetachAllOnCommit(true); assertTrue(pm.getDetachAllOnCommit()); pm.close(); //props true props.setDetachAllOnCommit(true); assertEquals("true", props.getProperty(Constants.PROPERTY_DETACH_ALL_ON_COMMIT)); pmf = JDOHelper.getPersistenceManagerFactory(props); assertTrue(pmf.getDetachAllOnCommit()); } @Test public void testDetachNewNoTx() { PersistenceManager pm = TestTools.openPM(); pm.setDetachAllOnCommit(true); pm.currentTransaction().begin(); TestClass tc1 = new TestClass(); TestClass tc1b = new TestClass(); pm.makePersistent(tc1); pm.makePersistent(tc1b); tc1.setInt(5); tc1.setRef2(tc1b); tc1b.setInt(6); //transitive pers. TestClass tc2 = new TestClass(); TestClass tc2b = new TestClass(); pm.makePersistent(tc2); tc2.setInt(7); tc2.setRef2(tc2b); tc2b.setInt(8); pm.currentTransaction().commit(); //should work outside TX assertEquals(5, tc1.getInt()); assertEquals(6, tc1b.getInt()); assertEquals(7, tc2.getInt()); assertEquals(8, tc2b.getInt()); TestTools.closePM(); //should work outside session assertEquals(5, tc1.getInt()); assertEquals(6, tc1b.getInt()); assertEquals(7, tc2.getInt()); assertEquals(8, tc2b.getInt()); } @Test public void testDetachNewNoSession() { PersistenceManager pm = TestTools.openPM(); pm.setDetachAllOnCommit(true); pm.currentTransaction().begin(); TestClass tc1 = new TestClass(); TestClass tc1b = new TestClass(); pm.makePersistent(tc1); pm.makePersistent(tc1b); tc1.setInt(5); tc1.setRef2(tc1b); tc1b.setInt(6); //transitive pers. TestClass tc2 = new TestClass(); TestClass tc2b = new TestClass(); pm.makePersistent(tc2); tc2.setInt(7); tc2.setRef2(tc2b); tc2b.setInt(8); pm.currentTransaction().commit(); TestTools.closePM(); //should work outside session assertEquals(5, tc1.getInt()); assertEquals(6, tc1b.getInt()); assertEquals(7, tc2.getInt()); assertEquals(8, tc2b.getInt()); } @Test public void testDetachNewNoTxRefs() { PersistenceManager pm = TestTools.openPM(); pm.setDetachAllOnCommit(true); pm.currentTransaction().begin(); TestClass tc1 = new TestClass(); TestClass tc1b = new TestClass(); pm.makePersistent(tc1); pm.makePersistent(tc1b); tc1.setInt(5); tc1.setRef2(tc1b); tc1b.setInt(6); //transitive pers. TestClass tc2 = new TestClass(); TestClass tc2b = new TestClass(); pm.makePersistent(tc2); tc2.setInt(7); tc2.setRef2(tc2b); tc2b.setInt(8); pm.currentTransaction().commit(); //should work outside TX assertEquals(5, tc1.getInt()); assertEquals(6, tc1.getRef2().getInt()); assertEquals(7, tc2.getInt()); assertEquals(8, tc2.getRef2().getInt()); TestTools.closePM(); //should work outside session assertEquals(5, tc1.getInt()); assertEquals(6, tc1.getRef2().getInt()); assertEquals(7, tc2.getInt()); assertEquals(8, tc2.getRef2().getInt()); } @Test public void testDetachNewNoSessionRefs() { PersistenceManager pm = TestTools.openPM(); pm.setDetachAllOnCommit(true); pm.currentTransaction().begin(); TestClass tc1 = new TestClass(); TestClass tc1b = new TestClass(); pm.makePersistent(tc1); pm.makePersistent(tc1b); tc1.setInt(5); tc1.setRef2(tc1b); tc1b.setInt(6); //transitive pers. TestClass tc2 = new TestClass(); TestClass tc2b = new TestClass(); pm.makePersistent(tc2); tc2.setInt(7); tc2.setRef2(tc2b); tc2b.setInt(8); pm.currentTransaction().commit(); TestTools.closePM(); //should work outside session assertEquals(5, tc1.getInt()); assertEquals(6, tc1.getRef2().getInt()); assertEquals(7, tc2.getInt()); assertEquals(8, tc2.getRef2().getInt()); } @Test public void testDetachPersNoTxRefs() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); TestClass tc1 = new TestClass(); TestClass tc1b = new TestClass(); pm.makePersistent(tc1); pm.makePersistent(tc1b); tc1.setInt(5); tc1.setRef2(tc1b); tc1b.setInt(6); TestClass tc2 = new TestClass(); TestClass tc2b = new TestClass(); pm.makePersistent(tc2); tc2.setInt(7); pm.currentTransaction().commit(); pm.setDetachAllOnCommit(true); pm.currentTransaction().begin(); //dirty some of them tc2.setRef2(tc2b); tc2b.setInt(8); pm.currentTransaction().commit(); //should work outside TX assertEquals(5, tc1.getInt()); assertEquals(6, tc1.getRef2().getInt()); assertEquals(7, tc2.getInt()); assertEquals(8, tc2.getRef2().getInt()); TestTools.closePM(); //should work outside session assertEquals(5, tc1.getInt()); assertEquals(6, tc1.getRef2().getInt()); assertEquals(7, tc2.getInt()); assertEquals(8, tc2.getRef2().getInt()); } @Test public void testDetachPersNoSessionRefs() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); TestClass tc1 = new TestClass(); TestClass tc1b = new TestClass(); pm.makePersistent(tc1); pm.makePersistent(tc1b); tc1.setInt(5); tc1.setRef2(tc1b); tc1b.setInt(6); //transitive pers. TestClass tc2 = new TestClass(); TestClass tc2b = new TestClass(); pm.makePersistent(tc2); tc2.setInt(7); pm.currentTransaction().commit(); pm.setDetachAllOnCommit(true); pm.currentTransaction().begin(); tc2.setRef2(tc2b); tc2b.setInt(8); pm.currentTransaction().commit(); TestTools.closePM(); //should work outside session assertEquals(5, tc1.getInt()); assertEquals(6, tc1.getRef2().getInt()); assertEquals(7, tc2.getInt()); assertEquals(8, tc2.getRef2().getInt()); } @Test public void testMakePersistent() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); TestClass tc1 = new TestClass(); TestClass tc1b = new TestClass(); pm.makePersistent(tc1); pm.makePersistent(tc1b); tc1.setInt(5); tc1.setRef2(tc1b); tc1b.setInt(6); //transitive pers. TestClass tc2 = new TestClass(); TestClass tc2b = new TestClass(); pm.makePersistent(tc2); tc2.setInt(7); pm.currentTransaction().commit(); pm.setDetachAllOnCommit(true); pm.currentTransaction().begin(); tc2.setRef2(tc2b); tc2b.setInt(8); pm.currentTransaction().commit(); tc1.setInt(50); tc1b.setInt(60); tc2.setInt(70); tc2b.setInt(80); pm.setDetachAllOnCommit(false); pm.currentTransaction().begin(); pm.makePersistent(tc1); pm.makePersistent(tc2); Object o1 = JDOHelper.getObjectId(tc1); Object o2 = JDOHelper.getObjectId(tc2); pm.currentTransaction().commit(); TestTools.closePM(); pm = TestTools.openPM(); pm.currentTransaction().begin(); TestClass tc11 = (TestClass) pm.getObjectById(o1); TestClass tc21 = (TestClass) pm.getObjectById(o2); //should work outside session assertEquals(50, tc11.getInt()); assertEquals(60, tc11.getRef2().getInt()); assertEquals(70, tc21.getInt()); assertEquals(80, tc21.getRef2().getInt()); pm.currentTransaction().rollback(); TestTools.closePM(); } /** * Test that makePersistent works transitively. */ @Test public void testMakePersistentTransitive() { PersistenceManager pm = TestTools.openPM(); pm.setDetachAllOnCommit(true); pm.currentTransaction().begin(); TestClass tc1 = new TestClass(); TestClass tc1b = new TestClass(); pm.makePersistent(tc1); pm.makePersistent(tc1b); tc1.setInt(5); tc1.setRef2(tc1b); tc1b.setInt(6); //transitive pers. TestClass tc2 = new TestClass(); TestClass tc2b = new TestClass(); pm.makePersistent(tc2); tc2.setInt(7); //detach all pm.currentTransaction().commit(); pm.currentTransaction().begin(); //No modify and check that everything gets stored tc1b.setInt(18); tc2.setRef2(tc2b); tc2b.setInt(28); //add new instances TestClass tc1c = new TestClass(); tc1c.setInt(188); tc1b.setRef2(tc1c); TestClass tc2c = new TestClass(); tc2c.setInt(288); tc2b.setRef2(tc2c); //reattach pm.makePersistent(tc1); pm.makePersistent(tc2); Object o1 = JDOHelper.getObjectId(tc1); Object o2 = JDOHelper.getObjectId(tc2); pm.currentTransaction().commit(); TestTools.closePM(); pm = TestTools.openPM(); pm.currentTransaction().begin(); TestClass tc11 = (TestClass) pm.getObjectById(o1); TestClass tc21 = (TestClass) pm.getObjectById(o2); assertEquals(5, tc11.getInt()); assertEquals(18, tc11.getRef2().getInt()); assertEquals(188, tc11.getRef2().getRef2().getInt()); assertEquals(7, tc21.getInt()); assertEquals(28, tc21.getRef2().getInt()); assertEquals(288, tc21.getRef2().getRef2().getInt()); pm.currentTransaction().rollback(); TestTools.closePM(); } /** * Test that makePersistent does duplicate objects. * Duplication is intended (well, tolerated) behaviour, see issue 75 */ @SuppressWarnings("unchecked") @Test public void testDuplication_Issue_075() { PersistenceManager pm = TestTools.openPM(); pm.setDetachAllOnCommit(true); pm.currentTransaction().begin(); TestClass tc1 = new TestClass(); TestClass tc1b = new TestClass(); pm.makePersistent(tc1); pm.makePersistent(tc1b); tc1.setInt(5); tc1.setRef2(tc1b); tc1b.setInt(6); //detach all pm.currentTransaction().commit(); pm.currentTransaction().begin(); Query q = pm.newQuery(TestClass.class); q.setUnique(true); q.setFilter("_int == 5"); q.execute(); q.setFilter("_int == 6"); TestClass x2 = (TestClass) q.execute(); TestClass x3 = new TestClass(); pm.makePersistent(x3); x3.setInt(56); //make Persistent via reachability x3.setRef2(x2); //No modify and check that everything gets stored tc1b.setInt(18); //reattach pm.makePersistent(tc1); pm.makePersistent(tc1b); pm.currentTransaction().commit(); TestTools.closePM(); pm = TestTools.openPM(); pm.currentTransaction().begin(); Query q2 = pm.newQuery(TestClass.class); Collection<TestClass> c = (Collection<TestClass>) q2.execute(); // detach causes duplication, apparently this is intended, see issue 75"); assertEquals(5, c.size()); pm.currentTransaction().rollback(); TestTools.closePM(); } @Test public void testCacheIsEmpty() { PersistenceManager pm = TestTools.openPM(); pm.setDetachAllOnCommit(true); pm.currentTransaction().begin(); TestClass tc1 = new TestClass(); TestClass tc1b = new TestClass(); pm.makePersistent(tc1); pm.makePersistent(tc1b); tc1.setInt(5); tc1.setRef2(tc1b); tc1b.setInt(6); Set<?> cache = pm.getManagedObjects(); assertTrue(cache.contains(tc1)); assertTrue(cache.contains(tc1b)); //detach pm.currentTransaction().commit(); pm.currentTransaction().begin(); cache = pm.getManagedObjects(); assertFalse(cache.contains(tc1)); assertFalse(cache.contains(tc1b)); pm.currentTransaction().commit(); TestTools.closePM(); } @Test public void testNoDetachSchema() { PersistenceManager pm = TestTools.openPM(); pm.setDetachAllOnCommit(true); pm.currentTransaction().begin(); ZooSchema s = ZooJdoHelper.schema(pm); s.addClass(TestClassTiny.class); pm.currentTransaction().commit(); pm.currentTransaction().begin(); assertNotNull(s.getClass(TestClassTiny.class)); try { s.addClass(TestClassTiny.class); fail(); } catch (JDOUserException e) { //good, is already defined } pm.currentTransaction().commit(); TestTools.closePM(); } @Test public void testNoDetachGenericObjects() { PersistenceManager pm = TestTools.openPM(); pm.setDetachAllOnCommit(true); pm.currentTransaction().begin(); ZooSchema s = ZooJdoHelper.schema(pm); ZooClass c = s.getClass(TestClass.class); pm.currentTransaction().commit(); pm.currentTransaction().begin(); ZooHandle h = c.newInstance(); Object oid = h.getOid(); pm.currentTransaction().commit(); pm.currentTransaction().begin(); assertNotNull(pm.getObjectById(oid)); pm.currentTransaction().commit(); TestTools.closePM(); } private static class ListenerDetach implements DetachLifecycleListener { Set<TestClass> instances = new HashSet<>(); int preDetach = 0; int postDetach = 0; @Override public void preDetach(InstanceLifecycleEvent arg0) { assertEquals(InstanceLifecycleEvent.DETACH, arg0.getEventType()); instances.add((TestClass) arg0.getDetachedInstance()); preDetach++; } @Override public void postDetach(InstanceLifecycleEvent arg0) { assertEquals(InstanceLifecycleEvent.DETACH, arg0.getEventType()); instances.add((TestClass) arg0.getDetachedInstance()); postDetach++; } } @Test public void testCallbacks() { PersistenceManager pm = TestTools.openPM(); pm.setDetachAllOnCommit(true); ListenerDetach l = new ListenerDetach(); pm.addInstanceLifecycleListener(l, TestClass.class); pm.currentTransaction().begin(); TestClass tc1 = new TestClass(); TestClass tc1b = new TestClass(); pm.makePersistent(tc1); tc1.setInt(5); tc1.setRef2(tc1b); tc1b.setInt(6); //detach pm.currentTransaction().commit(); assertEquals(2, l.preDetach); assertEquals(2, l.postDetach); assertTrue(l.instances.contains(tc1)); assertTrue(l.instances.contains(tc1b)); TestTools.closePM(); } @Test public void testTransitionToDetachedDirty() { PersistenceManager pm = TestTools.openPM(); pm.setDetachAllOnCommit(true); pm.currentTransaction().begin(); TestClass tc1 = new TestClass(); TestClass tc1b = new TestClass(); pm.makePersistent(tc1); pm.makePersistent(tc1b); tc1.setInt(5); tc1.setRef2(tc1b); tc1b.setInt(6); //detach pm.currentTransaction().commit(); TestTools.closePM(); assertEquals(ObjectState.DETACHED_CLEAN, JDOHelper.getObjectState(tc1)); assertEquals(ObjectState.DETACHED_CLEAN, JDOHelper.getObjectState(tc1b)); tc1.setRef2(null); tc1b.setInt(60); assertEquals(ObjectState.DETACHED_DIRTY, JDOHelper.getObjectState(tc1)); assertEquals(ObjectState.DETACHED_DIRTY, JDOHelper.getObjectState(tc1b)); } @After public void afterTest() { TestTools.closePM(); } @AfterClass public static void tearDown() { TestTools.removeDb(); } }