/* * 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.annotations; import java.lang.reflect.Array; import org.apache.openjpa.jdbc.meta.ClassMapping; import org.apache.openjpa.jdbc.meta.strats.MultiColumnVersionStrategy; import org.apache.openjpa.persistence.OpenJPAEntityManager; import org.apache.openjpa.persistence.test.SingleEMFTestCase; /** * Tests numeric version spanning multiple columns and those columns spanning * multiple tables. * * @author Pinaki Poddar */ public class TestMultiColumnVersion extends SingleEMFTestCase { public void setUp() { setUp(MultiColumnVersionPC.class, MultiColumnSecondaryVersionPC.class, CLEAR_TABLES); } public void testVersionStrategyIsSet() { assertStrategy(MultiColumnVersionPC.class); assertStrategy(MultiColumnSecondaryVersionPC.class); } public void assertStrategy(Class cls) { ClassMapping mapping = getMapping(cls); assertNotNull(mapping.getVersion()); assertTrue(mapping.getVersion().getStrategy() instanceof MultiColumnVersionStrategy); } public void testVersionOnPersistAndUpdateForSingleTable() { OpenJPAEntityManager em = emf.createEntityManager(); em.getTransaction().begin(); MultiColumnVersionPC pc = new MultiColumnVersionPC(); assertEquals(null, em.getVersion(pc)); em.persist(pc); em.getTransaction().commit(); assertVersionEquals(new Number[]{1,1, 1.0f}, em.getVersion(pc)); em.getTransaction().begin(); pc.setName("updated"); em.merge(pc); em.getTransaction().commit(); assertVersionEquals(new Number[]{2,2, 2.0f}, em.getVersion(pc)); em.close(); } public void testConcurrentOptimisticUpdateFailsForSingleTable() { OpenJPAEntityManager em1 = emf.createEntityManager(); em1.getTransaction().begin(); OpenJPAEntityManager em2 = emf.createEntityManager(); em2.getTransaction().begin(); MultiColumnVersionPC pc1 = new MultiColumnVersionPC(); em1.persist(pc1); em1.getTransaction().commit(); em1.getTransaction().begin(); Object oid = em1.getObjectId(pc1); MultiColumnVersionPC pc2 = em2.find(MultiColumnVersionPC.class, oid); assertVersionEquals(em1.getVersion(pc1), em2.getVersion(pc2)); pc1.setName("Updated in em1"); pc2.setName("Updated in em2"); em1.getTransaction().commit(); em1.close(); try { em2.getTransaction().commit(); fail("Optimistic fail"); } catch (Exception e) { } finally { em2.close(); } } public void testConcurrentOptimisticReadSucceedsForSingleTable() { OpenJPAEntityManager em1 = emf.createEntityManager(); em1.getTransaction().begin(); OpenJPAEntityManager em2 = emf.createEntityManager(); em2.getTransaction().begin(); MultiColumnVersionPC pc1 = new MultiColumnVersionPC(); em1.persist(pc1); em1.getTransaction().commit(); em1.getTransaction().begin(); Object oid = em1.getObjectId(pc1); MultiColumnVersionPC pc2 = em2.find(MultiColumnVersionPC.class, oid); assertVersionEquals(em1.getVersion(pc1), em2.getVersion(pc2)); em1.getTransaction().commit(); em1.close(); em2.getTransaction().commit(); em2.close(); } public void testVersionOnPersistAndUpdateForMultiTable() { OpenJPAEntityManager em = emf.createEntityManager(); em.getTransaction().begin(); MultiColumnSecondaryVersionPC pc = new MultiColumnSecondaryVersionPC(); assertEquals(null, em.getVersion(pc)); em.persist(pc); em.getTransaction().commit(); assertVersionEquals(new Number[]{1,1,1,1}, em.getVersion(pc)); em.getTransaction().begin(); pc.setName("updated"); em.merge(pc); em.getTransaction().commit(); assertVersionEquals(new Number[]{2,2,2,2}, em.getVersion(pc)); em.close(); } public void testConcurrentOptimisticUpdateFailsForMultiTable() { OpenJPAEntityManager em1 = emf.createEntityManager(); em1.getTransaction().begin(); OpenJPAEntityManager em2 = emf.createEntityManager(); em2.getTransaction().begin(); MultiColumnSecondaryVersionPC pc1 = new MultiColumnSecondaryVersionPC(); em1.persist(pc1); em1.getTransaction().commit(); em1.getTransaction().begin(); Object oid = em1.getObjectId(pc1); MultiColumnSecondaryVersionPC pc2 = em2.find(MultiColumnSecondaryVersionPC.class, oid); assertVersionEquals(em1.getVersion(pc1), em2.getVersion(pc2)); pc1.setName("Updated in em1"); pc2.setName("Updated in em2"); em1.getTransaction().commit(); em1.close(); try { em2.getTransaction().commit(); fail("Optimistic fail"); } catch (Exception e) { } finally { em2.close(); } } public void testConcurrentOptimisticReadSucceedsForMultiTable() { OpenJPAEntityManager em1 = emf.createEntityManager(); em1.getTransaction().begin(); OpenJPAEntityManager em2 = emf.createEntityManager(); em2.getTransaction().begin(); MultiColumnSecondaryVersionPC pc1 = new MultiColumnSecondaryVersionPC(); em1.persist(pc1); em1.getTransaction().commit(); em1.getTransaction().begin(); Object oid = em1.getObjectId(pc1); MultiColumnSecondaryVersionPC pc2 = em2.find(MultiColumnSecondaryVersionPC.class, oid); assertVersionEquals(em1.getVersion(pc1), em2.getVersion(pc2)); em1.getTransaction().commit(); em1.close(); em2.getTransaction().commit(); em2.close(); } static void assertVersionEquals(Object expected, Object actual) { assertTrue(expected.getClass().isArray()); assertTrue(actual.getClass().isArray()); assertEquals(Array.getLength(expected), Array.getLength(actual)); int n = Array.getLength(expected); for (int i = 0; i < n; i++) { Object v1 = Array.get(expected, i); Object v2 = Array.get(actual, i); // exact equality may fail on non-integral values assertTrue("element " + i + " mismatch. Expeceted: " + v1 + " actual: " + v2, Math.abs(((Number)v1).doubleValue() - ((Number)v2).doubleValue()) < 0.01); } } }