| /* |
| * 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.kernel; |
| |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.TreeMap; |
| |
| import org.apache.openjpa.conf.OpenJPAConfiguration; |
| import org.apache.openjpa.conf.OpenJPAConfigurationImpl; |
| import org.apache.openjpa.enhance.PCEnhancer; |
| import org.apache.openjpa.enhance.PersistenceCapable; |
| import org.apache.openjpa.kernel.DetachedStateManager; |
| import org.apache.openjpa.lib.util.Options; |
| import org.apache.openjpa.persistence.DetachStateType; |
| import org.apache.openjpa.persistence.OpenJPAEntityManager; |
| import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory; |
| import org.apache.openjpa.persistence.kernel.common.apps.AttachA; |
| import org.apache.openjpa.persistence.kernel.common.apps.AttachB; |
| import org.apache.openjpa.persistence.kernel.common.apps.AttachD; |
| import org.apache.openjpa.persistence.kernel.common.apps.AttachE; |
| import org.apache.openjpa.persistence.kernel.common.apps.DetachSMPC; |
| |
| public class TestDetachedStateManager extends BaseKernelTest { |
| |
| private static boolean enhanced = false; |
| |
| private int oid; |
| private int doid; |
| |
| /** |
| * Creates a new instance of TestDetachedStateManager |
| */ |
| public TestDetachedStateManager(String name) { |
| super(name); |
| } |
| |
| private void deleteAll() { |
| deleteAll(AttachA.class); |
| deleteAll(AttachD.class); |
| } |
| |
| @Override |
| public OpenJPAEntityManager getPM() { |
| OpenJPAEntityManager pm = super.getPM(); |
| //FIXME jthomas |
| //pm.currentTransaction().setRestoreValues(false); |
| return pm; |
| } |
| |
| @Override |
| public void setUp() throws Exception { |
| super.setUp(); |
| |
| deleteAll(); |
| |
| OpenJPAEntityManager pm = getPM(); |
| startTx(pm); |
| AttachB b = new AttachB(); |
| pm.persist(b); |
| b.setAint(5); |
| b.setBstr("5"); |
| b.getStringIntMap().put("5", 5); |
| |
| AttachE e = new AttachE(); |
| e.setEstr("E"); |
| e.setEint(5); |
| |
| AttachD d = new AttachD(); |
| d.setDint(5); |
| d.setEmbeddedE(e); |
| b.getDs().add(d); |
| |
| pm.persist(d); |
| |
| oid = b.getId(); |
| doid = d.getId(); |
| endTx(pm); |
| endEm(pm); |
| } |
| |
| public void testDetach() { |
| OpenJPAEntityManager pm = getPM(); |
| AttachB b = pm.find(AttachB.class, oid); |
| |
| assertNotNull("b is null in testDetach", b); |
| |
| b = (AttachB) pm.detachCopy(b); |
| endEm(pm); |
| |
| assertTrue(pm.isDetached(b)); |
| assertEquals(5, b.getAint()); |
| assertEquals("5", b.getBstr()); |
| assertNull(b.getStringIntMap()); |
| |
| b.setAint(12); |
| b.setBstr("12"); |
| TreeMap map = new TreeMap(); |
| map.put("12", 12); |
| b.setStringIntMap(map); |
| |
| pm = getPM(); |
| startTx(pm); |
| AttachB attached = (AttachB) pm.merge(b); |
| assertEquals(12, attached.getAint()); |
| assertEquals("12", attached.getBstr()); |
| assertNull(attached.getStringIntMap().get("12")); |
| assertEquals(5, attached.getStringIntMap().get("5")); |
| endTx(pm); |
| endEm(pm); |
| |
| pm = getPM(); |
| b = pm.find(AttachB.class, oid); |
| assertEquals(12, b.getAint()); |
| assertEquals("12", b.getBstr()); |
| assertNull(b.getStringIntMap().get("12")); |
| assertEquals(5, b.getStringIntMap().get("5")); |
| endEm(pm); |
| } |
| |
| public void testDetachWithGroups() { |
| OpenJPAEntityManager pm = getPM(); |
| //FIXME jthomas |
| // pm.getFetchPlan().setDetachmentOptions( |
| // FetchPlanImpl.DETACH_LOAD_FIELDS | FetchPlanImpl.DETACH_UNLOAD_FIELDS); |
| pm.setDetachState(DetachStateType.FETCH_GROUPS); |
| pm.getFetchPlan().addFetchGroup("all"); |
| AttachB b = pm.find(AttachB.class, oid); |
| |
| assertNotNull("b is null in testDetachWithGroups", b); |
| |
| b = (AttachB) pm.detachCopy(b); |
| endEm(pm); |
| |
| assertTrue(pm.isDetached(b)); |
| assertEquals("b.getAint() not 5", 5, b.getAint()); |
| assertEquals("b.getAint() not 5str", "5", b.getBstr()); |
| assertEquals("b.getStringIntMap().size() not equal to 1", 1, |
| b.getStringIntMap().size()); |
| |
| b.setAint(12); |
| b.setBstr("12"); |
| b.getStringIntMap().put("12", 12); |
| |
| pm = getPM(); |
| startTx(pm); |
| AttachB attached = (AttachB) pm.merge(b); |
| assertEquals("not 12", 12, attached.getAint()); |
| assertEquals("not 12str", "12", attached.getBstr()); |
| assertEquals("not newInteger(12)", 12, |
| attached.getStringIntMap().get("12")); |
| assertEquals("not newInteger(5)", 5, |
| attached.getStringIntMap().get("5")); |
| endTx(pm); |
| endEm(pm); |
| |
| pm = getPM(); |
| b = (AttachB) pm.find(AttachB.class, oid); |
| assertEquals("not equal 12", 12, b.getAint()); |
| assertEquals("not equal 12str", "12", b.getBstr()); |
| assertEquals("not equal newinteger(12)", 12, |
| b.getStringIntMap().get("12")); |
| assertEquals("not equal newInteger(5)", 5, |
| b.getStringIntMap().get("5")); |
| endEm(pm); |
| } |
| |
| public void testDetachNoOverwrite() { |
| OpenJPAEntityManager pm = getPM(); |
| AttachB b = (AttachB) pm.find(AttachB.class, oid); |
| b = (AttachB) pm.detachCopy(b); |
| endEm(pm); |
| |
| b.setBstr("12"); |
| |
| pm = getPM(); |
| startTx(pm); |
| AttachB orig = pm.find(AttachB.class, oid); |
| orig.setAint(50); |
| |
| AttachB attached = (AttachB) pm.merge(b); |
| assertEquals(attached, orig); |
| assertEquals(50, attached.getAint()); |
| assertEquals("12", attached.getBstr()); |
| endTx(pm); |
| endEm(pm); |
| |
| pm = getPM(); |
| b = (AttachB) pm.find(AttachB.class, oid); |
| assertEquals(50, b.getAint()); |
| assertEquals("12", b.getBstr()); |
| endEm(pm); |
| } |
| |
| public void testOptimisticLock() { |
| OpenJPAEntityManager pm = getPM(); |
| AttachB b = (AttachB) pm.find(AttachB.class, oid); |
| |
| assertNotNull("b is null in testOptimisticLock", b); |
| |
| b = (AttachB) pm.detachCopy(b); |
| endEm(pm); |
| |
| b.setAint(12); |
| b.setBstr("12"); |
| TreeMap map = new TreeMap(); |
| map.put("12", 12); |
| b.setStringIntMap(map); |
| |
| pm = getPM(); |
| startTx(pm); |
| AttachB b2 = (AttachB) pm.find(AttachB.class, oid); |
| b2.setAint(15); |
| endTx(pm); |
| endEm(pm); |
| |
| pm = getPM(); |
| startTx(pm); |
| try { |
| pm.merge(b); |
| endTx(pm); |
| fail("OL expected."); |
| } catch (Exception jove) { |
| rollbackTx(pm); |
| } |
| endEm(pm); |
| } |
| |
| public void testEmbedded() { |
| OpenJPAEntityManager pm = getPM(); |
| AttachD d = pm.find(AttachD.class, doid); |
| |
| assertNotNull("d is null in testEmbedded", d); |
| |
| d.getEmbeddedE().getEstr(); |
| d = (AttachD) pm.detachCopy(d); |
| endEm(pm); |
| |
| d.getEmbeddedE().setEstr("E12"); |
| pm = getPM(); |
| startTx(pm); |
| AttachD d2 = (AttachD) pm.merge(d); |
| assertNotEquals(d.getEmbeddedE(), d2.getEmbeddedE()); |
| assertEquals("E12", d2.getEmbeddedE().getEstr()); |
| assertEquals(5, d2.getEmbeddedE().getEint()); |
| endTx(pm); |
| endEm(pm); |
| |
| pm = getPM(); |
| d2 = (AttachD) pm.find(AttachD.class, doid); |
| |
| assertNotNull("d2 is null in testEmbedded", d2); |
| |
| assertEquals("E12", d2.getEmbeddedE().getEstr()); |
| assertEquals(5, d2.getEmbeddedE().getEint()); |
| endEm(pm); |
| } |
| |
| public void testNullEmbedded() { |
| OpenJPAEntityManager pm = getPM(); |
| AttachD d = (AttachD) pm.find(AttachD.class, doid); |
| |
| assertNotNull("d is null in testNullEmbedded", d); |
| d.getEmbeddedE().getEstr(); |
| d = (AttachD) pm.detachCopy(d); |
| endEm(pm); |
| |
| d.setEmbeddedE(null); |
| pm = getPM(); |
| startTx(pm); |
| AttachD d2 = (AttachD) pm.merge(d); |
| assertNull(d2.getEmbeddedE()); |
| endTx(pm); |
| endEm(pm); |
| |
| pm = getPM(); |
| d2 = (AttachD) pm.find(AttachD.class, doid); |
| |
| assertNotNull("d2 is null in testNullEmbedded", d2); |
| // no null ind |
| if (d2.getEmbeddedE() != null) { |
| assertNull(d2.getEmbeddedE().getEstr()); |
| assertEquals(0, d2.getEmbeddedE().getEint()); |
| } |
| endEm(pm); |
| } |
| |
| public void testNullEmbeddedRelated() { |
| OpenJPAEntityManager pm = getPM(); |
| AttachD d = (AttachD) pm.find(AttachD.class, doid); |
| |
| assertNotNull("d is null in testNullEmbeddedRelated", d); |
| |
| d.getEmbeddedE().getEstr(); |
| d = (AttachD) pm.detachCopy(d); |
| endEm(pm); |
| |
| d.getEmbeddedE().setEstr(null); |
| pm = getPM(); |
| startTx(pm); |
| AttachD d2 = (AttachD) pm.merge(d); |
| assertNull("d2.getEmbeddedE().getEstr() is not null", |
| d2.getEmbeddedE().getEstr()); |
| assertEquals("d2.getEmbeddedE().getEint() is not equal to 5", 5, |
| d2.getEmbeddedE().getEint()); |
| endTx(pm); |
| endEm(pm); |
| |
| pm = getPM(); |
| d2 = (AttachD) pm.find(AttachD.class, doid); |
| assertNull("d2.getEmbeddedE().getEstr() is not null", |
| d2.getEmbeddedE().getEstr()); |
| assertEquals("d2.getEmbeddedE().getEint() is not 5", 5, |
| d2.getEmbeddedE().getEint()); |
| endEm(pm); |
| } |
| |
| public void testNullCollection() { |
| OpenJPAEntityManager pm = getPM(); |
| AttachB b = (AttachB) pm.find(AttachB.class, oid); |
| b.getDs(); |
| b = (AttachB) pm.detachCopy(b); |
| endEm(pm); |
| |
| assertEquals(1, b.getDs().size()); |
| b.setDs(null); |
| |
| pm = getPM(); |
| startTx(pm); |
| b = (AttachB) pm.merge(b); |
| assertNull(b.getDs()); |
| endTx(pm); |
| endEm(pm); |
| |
| pm = getPM(); |
| b = (AttachB) pm.find(AttachB.class, oid); |
| assertTrue(b.getDs() == null || b.getDs().size() == 0); |
| endEm(pm); |
| } |
| |
| public void testCollectionAdd() { |
| doCollectionTest(false); |
| } |
| |
| public void testCollectionChanges() { |
| doCollectionTest(true); |
| } |
| |
| private void doCollectionTest(boolean remove) { |
| OpenJPAEntityManager pm = getPM(); |
| AttachB b = (AttachB) pm.find(AttachB.class, oid); |
| |
| assertNotNull("b is null in doCollectionTest", b); |
| b.getDs(); |
| b = (AttachB) pm.detachCopy(b); |
| endEm(pm); |
| |
| assertEquals("b is null in doCollectionTest", 1, b.getDs().size()); |
| if (remove) { |
| for (Iterator it = b.getDs().iterator(); it.hasNext();) { |
| it.next(); |
| it.remove(); |
| } |
| } |
| AttachD d = new AttachD(); |
| d.setDint(12); |
| b.getDs().add(d); |
| |
| pm = getPM(); |
| startTx(pm); |
| b = (AttachB) pm.merge(b); |
| assertSize(remove ? 1 : 2, b.getDs()); |
| endTx(pm); |
| endEm(pm); |
| |
| pm = getPM(); |
| b = (AttachB) pm.find(AttachB.class, oid); |
| assertSize(remove ? 1 : 2, b.getDs()); |
| boolean found1 = false; |
| boolean found2 = false; |
| for (Iterator it = b.getDs().iterator(); it.hasNext();) { |
| d = (AttachD) it.next(); |
| switch (d.getDint()) { |
| case 5: |
| if (found1) |
| fail("Refound."); |
| found1 = true; |
| break; |
| case 12: |
| if (found2) |
| fail("Refound."); |
| found2 = true; |
| break; |
| default: |
| fail("Unknown d:" + d.getDint()); |
| } |
| } |
| |
| if (remove) |
| assertFalse(found1); |
| |
| endEm(pm); |
| } |
| |
| /* |
| //### |
| // No time to get these working right now. Have to figure out how to |
| // enhance certain classes with different DetachState settings in autobuild. |
| public void testSerialization () |
| throws Exception |
| { |
| doSerializationTest (false); |
| } |
| |
| |
| public void testSerializationAuto () |
| throws Exception |
| { |
| doSerializationTest (true); |
| } |
| */ |
| |
| private void doSerializationTest(boolean auto) throws Exception { |
| enhance(); |
| Map props = new HashMap(); |
| props.put("openjpa.DetachState", "DetachedStateField=true"); |
| |
| OpenJPAEntityManagerFactory factory = |
| (OpenJPAEntityManagerFactory) getEmf(props); |
| OpenJPAEntityManager pm = |
| (OpenJPAEntityManager) factory.createEntityManager(); |
| |
| startTx(pm); |
| DetachSMPC pc = new DetachSMPC(); |
| pc.setIntField(1); |
| DetachSMPC rel = new DetachSMPC(); |
| rel.setIntField(2); |
| pc.getRelSet().add(rel); |
| pc.getStringIntMap().put("a", 99); |
| pm.persist(pc); |
| endTx(pm); |
| Object pcoid = pm.getObjectId(pc); |
| endEm(pm); |
| |
| pm = (OpenJPAEntityManager) factory.createEntityManager(); |
| pc = (DetachSMPC) pm.find(DetachSMPC.class, pcoid); |
| pc.getRelSet(); |
| pc.getStringIntMap(); |
| if (!auto) { |
| pc = (DetachSMPC) pm.detachCopy(pc); |
| assertDetachedSM(pc); |
| } |
| pc = (DetachSMPC) roundtrip(pc, false); |
| assertDetachedSM(pc); |
| endEm(pm); |
| |
| assertDetachedSM(pc); |
| assertSize(1, pc.getRelSet()); |
| assertEquals(1, pc.getStringIntMap().size()); |
| |
| pc.setIntField(3); |
| ((DetachSMPC) pc.getRelSet().iterator().next()).setIntField(4); |
| pc.getStringIntMap().put("b", 100); |
| |
| pc = (DetachSMPC) roundtrip(pc, false); |
| |
| assertDetachedSM(pc); |
| assertEquals(3, pc.getIntField()); |
| assertSize(1, pc.getRelSet()); |
| //assertDetachedSM (b.getDs ().iterator ().next ()); |
| assertEquals(4, ((DetachSMPC) pc.getRelSet().iterator().next()) |
| .getIntField()); |
| assertEquals(100, pc.getStringIntMap().get("b")); |
| |
| pm = (OpenJPAEntityManager) factory.createEntityManager(); |
| startTx(pm); |
| pc = (DetachSMPC) pm.merge(pc); |
| assertEquals(3, pc.getIntField()); |
| assertSize(1, pc.getRelSet()); |
| assertEquals(4, ((DetachSMPC) pc.getRelSet().iterator().next()) |
| .getIntField()); |
| assertEquals(2, pc.getStringIntMap().size()); |
| assertEquals(100, pc.getStringIntMap().get("b")); |
| endTx(pm); |
| endEm(pm); |
| |
| pm = (OpenJPAEntityManager) factory.createEntityManager(); |
| pc = (DetachSMPC) pm.find(DetachSMPC.class, pcoid); |
| assertEquals(3, pc.getIntField()); |
| assertSize(1, pc.getRelSet()); |
| assertEquals(4, ((DetachSMPC) pc.getRelSet().iterator().next()) |
| .getIntField()); |
| assertEquals(2, pc.getStringIntMap().size()); |
| assertEquals(100, pc.getStringIntMap().get("b")); |
| |
| startTx(pm); |
| deleteAll(DetachSMPC.class, pm); |
| endTx(pm); |
| endEm(pm); |
| factory.close(); |
| } |
| |
| private void enhance() throws Exception { |
| Properties props = getProperties(new String[]{ |
| "openjpa.DetachState", "DetachedStateField=true", |
| }); |
| OpenJPAConfiguration conf = new OpenJPAConfigurationImpl(true, false); |
| conf.fromProperties(props); |
| |
| Options opts = new Options(); |
| opts.put("jdo", "true"); |
| PCEnhancer.run(conf, new String[]{ |
| "org.apache.openjpa.persistence.kernel.noenhance.DetachSMPC" }, |
| opts); |
| } |
| |
| private void assertDetachedSM(Object obj) { |
| OpenJPAEntityManager pm = getPM(); |
| assertTrue(pm.isDetached(obj)); |
| PersistenceCapable pc = (PersistenceCapable) obj; |
| assertEquals(DetachedStateManager.class, |
| pc.pcGetStateManager().getClass()); |
| endEm(pm); |
| } |
| } |