You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pc...@apache.org on 2007/07/28 21:53:14 UTC

svn commit: r560601 - in /openjpa/trunk: openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/

Author: pcl
Date: Sat Jul 28 12:53:13 2007
New Revision: 560601

URL: http://svn.apache.org/viewvc?view=rev&rev=560601
Log:
OPENJPA-293. Fixed problem with transactional state maintenance that was preventing lifecycle tests from passing.

Modified:
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SaveFieldManager.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java?view=diff&rev=560601&r1=560600&r2=560601
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java Sat Jul 28 12:53:13 2007
@@ -1584,7 +1584,7 @@
             Collection saved = save.rollback(_savepoints.values());
             if (_savepointCache != null)
                 _savepointCache.clear();
-            if (_transCache != null) {
+            if (hasTransactionalObjects()) {
                 // build up a new collection of states
                 TransactionalCache oldTransCache = _transCache;
                 TransactionalCache newTransCache = new TransactionalCache
@@ -2156,8 +2156,10 @@
         _fc.setWriteLockLevel(LOCK_NONE);
         _fc.setLockTimeout(-1);
 
-        Collection transStates = _transCache;
-        if (transStates == null)
+        Collection transStates;
+        if (hasTransactionalObjects())
+            transStates = _transCache;
+        else
             transStates = Collections.EMPTY_LIST;
 
         // fire after rollback/commit event
@@ -3750,16 +3752,26 @@
      * Return a copy of all transactional state managers.
      */
     protected Collection getTransactionalStates() {
-        if (_transCache == null)
+        if (!hasTransactionalObjects())
             return Collections.EMPTY_LIST;
         return _transCache.copy();
     }
 
     /**
+     * Whether or not there are any transactional objects in the current
+     * persistence context. If there are any instances with untracked state,
+     * this method will cause those instances to be scanned.
+     */
+    private boolean hasTransactionalObjects() {
+        _cache.dirtyCheck();
+        return _transCache != null;
+    }
+
+    /**
      * Return a copy of all dirty state managers.
      */
     protected Collection getDirtyStates() {
-        if (_transCache == null)
+        if (!hasTransactionalObjects())
             return Collections.EMPTY_LIST;
 
         return _transCache.copyDirty();
@@ -3823,7 +3835,7 @@
 
         lock();
         try {
-            if (_transCache == null)
+            if (!hasTransactionalObjects())
                 _transCache = new TransactionalCache(_orderDirty);
             _transCache.addClean(sm);
         } finally {
@@ -3839,6 +3851,8 @@
         lock();
         try {
             if (_transCache != null)
+                // intentional direct access; we don't want to recompute
+                // dirtiness while removing instances from the transaction
                 _transCache.remove(sm);
             if (_derefCache != null && !sm.isPersistent())
                 _derefCache.remove(sm);
@@ -3866,7 +3880,7 @@
             lock();
             try {
                 // cache dirty instance
-                if (_transCache == null)
+                if (!hasTransactionalObjects())
                     _transCache = new TransactionalCache(_orderDirty);
                 _transCache.addDirty(sm);
 
@@ -4427,6 +4441,12 @@
          * Call this method when a new state manager initializes itself.
          */
         public void add(StateManagerImpl sm) {
+            if (!sm.isIntercepting()) {
+                if (_untracked == null)
+                    _untracked = new HashSet();
+                _untracked.add(sm);
+            }
+
             if (!sm.isPersistent() || sm.isEmbedded()) {
                 if (_embeds == null)
                     _embeds = new ReferenceHashSet(ReferenceHashSet.WEAK);
@@ -4453,12 +4473,6 @@
                     (orig.getManagedInstance()))).
                     setFailedObject(sm.getManagedInstance());
             }
-
-            if (!sm.isIntercepting()) {
-                if (_untracked == null)
-                    _untracked = new HashSet();
-                _untracked.add(sm);
-            }
         }
 
         /**
@@ -4623,6 +4637,14 @@
         public void clearNew() {
             if (_news != null)
                 _news.clear();
+        }
+
+        private void dirtyCheck() {
+            if (_untracked == null)
+                return;
+
+            for (Iterator iter = _untracked.iterator(); iter.hasNext(); )
+                ((StateManagerImpl) iter.next()).dirtyCheck();
         }
     }
 

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SaveFieldManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SaveFieldManager.java?view=diff&rev=560601&r1=560600&r2=560601
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SaveFieldManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SaveFieldManager.java Sat Jul 28 12:53:13 2007
@@ -177,12 +177,13 @@
         // if the field is not available, assume that it has changed.
         if (_saved == null || !_saved.get(field))
             return false;
-        if (!(_state.pcGetStateManager() instanceof OpenJPAStateManager))
+        if (!(_state.pcGetStateManager() instanceof StateManagerImpl))
             return false;
 
-        OpenJPAStateManager sm = (OpenJPAStateManager)
-            _state.pcGetStateManager();
-        Object old = sm.fetch(field);
+        StateManagerImpl sm = (StateManagerImpl) _state.pcGetStateManager();
+        SingleFieldManager single = new SingleFieldManager(sm, sm.getBroker());
+        sm.provideField(_state, single, field);
+        Object old = single.fetchObjectField(field);
         return current == old || current != null && current.equals(old);
     }
 

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java?view=diff&rev=560601&r1=560600&r2=560601
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java Sat Jul 28 12:53:13 2007
@@ -795,8 +795,8 @@
         for (int i = 0; i < fmds.length; i++) {
             // pk and version fields cannot be mutated; don't mark them
             // as such. ##### validate?
-            if (!fmds[i].isPrimaryKey()
-                && !fmds[i].isVersion()) {
+            if (!fmds[i].isPrimaryKey() && !fmds[i].isVersion()
+                && _loaded.get(i)) {
                 if (!saved.isFieldEqual(i, fetch(i))) {
                     dirty(i);
                 }
@@ -810,9 +810,6 @@
         if (isDeleted())
             return false;
         if (isNew() && !isFlushed())
-            return false;
-        if (getMetaData().getAccessType() != ClassMetaData.ACCESS_FIELD
-            && !(isNew() && isFlushed()))
             return false;
         return true;
     }

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java?view=diff&rev=560601&r1=560600&r2=560601
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java Sat Jul 28 12:53:13 2007
@@ -33,6 +33,8 @@
 import org.apache.openjpa.kernel.OpenJPAStateManager;
 import org.apache.openjpa.meta.ClassMetaData;
 import org.apache.openjpa.util.ImplHelper;
+import org.apache.openjpa.event.AbstractLifecycleListener;
+import org.apache.openjpa.event.LifecycleEvent;
 
 public abstract class AbstractUnenhancedClassTest
     extends SingleEMFTestCase {
@@ -60,6 +62,11 @@
 
     protected abstract UnenhancedSubtype newUnenhancedSubclassInstance();
 
+    private UnenhancedType newInstance(boolean sub) {
+        return sub ? newUnenhancedSubclassInstance()
+            : newUnenhancedInstance();
+    }
+
     public void testMetaData() {
         ClassMetaData meta = OpenJPAPersistence.getMetaData(emf,
             getUnenhancedClass());
@@ -136,15 +143,23 @@
         assertNotNull(em.getObjectId(un));
     }
 
-    public void testOperations() {
-        opsHelper(false);
+    public void testOperationsOnUserDefined() {
+        opsHelper(false, true);
+    }
+
+    public void testSubclassOperationsOnUserDefined() {
+        opsHelper(true, true);
     }
 
-    public void testSubclassOperations() {
-        opsHelper(true);
+    public void testOperationsOnOpenJPADefined() {
+        opsHelper(false, false);
     }
 
-    private void opsHelper(boolean sub) {
+    public void testSubclassOperationsOnOpenJPADefined() {
+        opsHelper(true, false);
+    }
+
+    private void opsHelper(boolean sub, boolean userDefined) {
         OpenJPAEntityManager em = null;
         try {
             UnenhancedType un = newInstance(sub);
@@ -154,22 +169,30 @@
             em.persist(un);
             un.setStringField("bar");
             assertEquals("bar", un.getStringField());
+            assertPersistenceContext(em, un, true, true, sub);
             em.flush();
+            assertPersistenceContext(em, un, true, true, sub);
             assertTrue(un.getId() != 0);
             UnenhancedType un2 = em.find(getUnenhancedClass(), un.getId());
             assertSame(un, un2);
             em.getTransaction().commit();
+            assertPersistenceContext(em, un, false, false, sub);
             un2 = em.find(getUnenhancedClass(), un.getId());
             assertSame(un, un2);
-            em.close();
 
-            em = emf.createEntityManager();
+            if (!userDefined) {
+                em.close();
+                em = emf.createEntityManager();
+            }
+
             un = em.find(getUnenhancedClass(), un.getId());
             assertNotNull(un);
-            assertTrue(un instanceof PersistenceCapable);
+            if (!userDefined)
+                assertTrue(un instanceof PersistenceCapable);
             assertEquals("bar", un.getStringField());
             em.getTransaction().begin();
             un.setStringField("baz");
+            assertPersistenceContext(em, un, true, true, sub);
             assertEquals("baz", un.getStringField());
 
             if (sub)
@@ -178,6 +201,11 @@
             assertTrue(em.isDirty(un));
             
             em.getTransaction().commit();
+
+            // make sure that the values are still up-to-date after
+            // the commit happens
+            assertEquals("baz", un.getStringField());
+            
             em.close();
 
             em = emf.createEntityManager();
@@ -196,6 +224,17 @@
         }
     }
 
+    private void assertPersistenceContext(OpenJPAEntityManager em,
+        UnenhancedType un, boolean transactional, boolean dirty, boolean sub) {
+        assertEquals(transactional, em.getTransactionalObjects().contains(un));
+        assertEquals(dirty, em.getDirtyObjects().contains(un));
+        if (dirty) {
+            Class cls = sub ? getUnenhancedSubclass() : getUnenhancedClass();
+            assertTrue(em.getUpdatedClasses().contains(cls)
+                || em.getPersistedClasses().contains(cls));
+        }
+    }
+
     public void testRelations() {
         OpenJPAEntityManager em = emf.createEntityManager();
         em.getTransaction().begin();
@@ -480,9 +519,51 @@
         em.getTransaction().commit();
     }
 
-    private UnenhancedType newInstance(boolean sub) {
-        return sub ? newUnenhancedSubclassInstance()
-            : newUnenhancedInstance();
+    public void testListenersOnUserDefinedInstance()
+        throws IOException, ClassNotFoundException, CloneNotSupportedException {
+        listenerHelper(true, false);
+    }
+
+    public void testListenersOnUserDefinedSubclassInstance()
+        throws IOException, ClassNotFoundException, CloneNotSupportedException {
+        listenerHelper(true, true);
+    }
+
+    public void testListenersOnOpenJPADefinedInstance()
+        throws IOException, ClassNotFoundException, CloneNotSupportedException {
+        listenerHelper(false, false);
+    }
+
+    public void testListenersOnOpenJPADefinedSubclassInstance()
+        throws IOException, ClassNotFoundException, CloneNotSupportedException {
+        listenerHelper(false, true);
+    }
+
+    private void listenerHelper(boolean userDefined, boolean sub)
+        throws IOException, ClassNotFoundException, CloneNotSupportedException {
+        ListenerImpl listener = new ListenerImpl();
+        emf.addLifecycleListener(listener, (Class[]) null);
+        OpenJPAEntityManager em = emf.createEntityManager();
+        UnenhancedType un = newInstance(sub);
+        em.getTransaction().begin();
+        em.persist(un);
+        em.getTransaction().commit();
+
+        if (!userDefined) {
+            em.close();
+            em = emf.createEntityManager();
+        }
+
+        listener.invoked = false;
+
+        un = em.find(getUnenhancedClass(), un.getId());
+        em.getTransaction().begin();
+        un.setStringField("updated");
+        em.getTransaction().commit();
+        assertTrue(listener.invoked);
+        em.close();
+
+        assertEquals("updated", listener.stringField);
     }
 
     public void testGetMetaDataOfSubtype() {
@@ -498,5 +579,18 @@
             emf.getConfiguration(),
             Collections.singleton(getUnenhancedSubclass()), null);
         assertSame(meta, OpenJPAPersistence.getMetaData(emf, subs.get(0)));
+    }
+
+    private class ListenerImpl
+        extends AbstractLifecycleListener {
+
+        String stringField;
+        boolean invoked;
+
+        @Override
+        public void afterStore(LifecycleEvent event) {
+            invoked = true;
+            stringField = ((UnenhancedType) event.getSource()).getStringField();
+        }
     }
 }