This Bugzilla instance is deprecated, and most Eclipse projects now use GitHub or Eclipse GitLab. Please see the deprecation plan for details.
View | Details | Raw Unified | Return to bug 259993 | Differences between
and this patch

Collapse All | Expand All

(-)foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/WriteLockManager.java (-2 / +10 lines)
Lines 9-14 Link Here
9
 *
9
 *
10
 * Contributors:
10
 * Contributors:
11
 *     Oracle - initial API and implementation from Oracle TopLink
11
 *     Oracle - initial API and implementation from Oracle TopLink
12
 *     02/11/2009-1.1 Michael O'Brien 
13
 *        - 259993: As part 2) During mergeClonesAfterCompletion() 
14
 *           If the the acquire and release threads are different 
15
 *           switch back to the stored acquire thread stored on the mergeManager.
12
 ******************************************************************************/  
16
 ******************************************************************************/  
13
package org.eclipse.persistence.internal.helper;
17
package org.eclipse.persistence.internal.helper;
14
18
Lines 126-133 Link Here
126
            } else {
130
            } else {
127
                objectForClone = cacheKey.getObject();
131
                objectForClone = cacheKey.getObject();
128
                if (lockedObjects.containsKey(objectForClone)) {
132
                if (lockedObjects.containsKey(objectForClone)) {
129
                    // This is a check for loss of identity, the orignal check in
133
                    // This is a check for loss of identity, the original check in
130
                    // checkAndLockObject() will shortcircut in the usual case.
134
                    // checkAndLockObject() will shortcircuit in the usual case.
131
                    cacheKey.releaseReadLock();
135
                    cacheKey.releaseReadLock();
132
                    return null;
136
                    return null;
133
                }
137
                }
Lines 234-239 Link Here
234
238
235
        //while that thread has locks to acquire continue to loop.
239
        //while that thread has locks to acquire continue to loop.
236
        try {
240
        try {
241
            // initialize the MergeManager during this commit or merge for insert/updates only
242
            // this call is not required in acquireLocksForClone() or acquireLockAndRelatedLocks()
243
            mergeManager.setLockThread(Thread.currentThread());
244
            
237
            AbstractSession session = mergeManager.getSession();
245
            AbstractSession session = mergeManager.getSession();
238
            if (session.isUnitOfWork()) {
246
            if (session.isUnitOfWork()) {
239
                session = ((UnitOfWorkImpl)session).getParent();
247
                session = ((UnitOfWorkImpl)session).getParent();
(-)foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/localization/i18n/TraceLocalizationResource.java (-1 / +2 lines)
Lines 306-312 Link Here
306
                                            { "registered_mbean", "Registered MBean: {0}" },
306
                                            { "registered_mbean", "Registered MBean: {0}" },
307
                                            { "unregistering_mbean", "Unregistering MBean: {0}" },
307
                                            { "unregistering_mbean", "Unregistering MBean: {0}" },
308
                                            { "mbean_get_application_name", "The applicationName for the MBean attached to session [{0}] is [{1}]" },
308
                                            { "mbean_get_application_name", "The applicationName for the MBean attached to session [{0}] is [{1}]" },
309
                                            { "mbean_get_module_name", "The moduleName for the MBean attached to session [{0}] is [{1}]" }                                            
309
                                            { "mbean_get_module_name", "The moduleName for the MBean attached to session [{0}] is [{1}]" },
310
                                            { "active_thread_is_different_from_current_thread", "Forcing the activeThread \"{0}\" on the mergeManager \"{1}\" to be the currentThread \"{2}\" because they are different." }                                            
310
    };
311
    };
311
312
312
    /**
313
    /**
(-)foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/MergeManager.java (-1 / +23 lines)
Lines 9-14 Link Here
9
 *
9
 *
10
 * Contributors:
10
 * Contributors:
11
 *     Oracle - initial API and implementation from Oracle TopLink
11
 *     Oracle - initial API and implementation from Oracle TopLink
12
 *     02/11/2009-1.1 Michael O'Brien 
13
 *        - 259993: As part 2) During mergeClonesAfterCompletion() 
14
 *        If the the acquire and release threads are different 
15
 *        switch back to the stored acquire thread stored on the mergeManager.
12
 ******************************************************************************/  
16
 ******************************************************************************/  
13
package org.eclipse.persistence.internal.sessions;
17
package org.eclipse.persistence.internal.sessions;
14
18
Lines 88-93 Link Here
88
    /** records that deferred locks have been employed for the merge process */
92
    /** records that deferred locks have been employed for the merge process */
89
    protected boolean isTransitionedToDeferredLocks = false;
93
    protected boolean isTransitionedToDeferredLocks = false;
90
94
95
    /** save the currentThread for later comparison to the activeThread in case they don't match */
96
    protected Thread lockThread;
97
    
91
    public MergeManager(AbstractSession session) {
98
    public MergeManager(AbstractSession session) {
92
        this.session = session;
99
        this.session = session;
93
        this.mergedNewObjects = new IdentityHashMap();
100
        this.mergedNewObjects = new IdentityHashMap();
Lines 1046-1052 Link Here
1046
                }
1053
                }
1047
            }
1054
            }
1048
        }
1055
        }
1056
    }
1049
1057
1058
    /**
1059
     * INTERNAL:
1060
     * @return lockThread
1061
     */
1062
    public Thread getLockThread() {
1063
        return lockThread;
1050
    }
1064
    }
1051
    
1065
1066
    /**
1067
     * INTERNAL:
1068
     * Save the currentThread for later comparison to the activeThread in case they don't match
1069
     * @param lockThread
1070
     */
1071
    public void setLockThread(Thread lockThread) {
1072
        this.lockThread = lockThread;
1073
    }
1052
}
1074
}
(-)foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/UnitOfWorkImpl.java (-6 / +72 lines)
Lines 14-19 Link Here
14
 *        The class was amended to allow it to instantiate ValueHolders after release method has been called
14
 *        The class was amended to allow it to instantiate ValueHolders after release method has been called
15
 *        (internalExecuteQuery method no longer throws exception if the uow is dead).
15
 *        (internalExecuteQuery method no longer throws exception if the uow is dead).
16
 *        Note that release method clears change sets but keeps the cache.
16
 *        Note that release method clears change sets but keeps the cache.
17
 *     02/11/2009-1.1 Michael O'Brien 
18
 *        - 259993: 1) Defer a full clear(true) call from entityManager.clear() to release() 
19
 *          only if uow lifecycle is 1,2 or 4 (*Pending) and perform a clear of the cache only in this case.
20
 *          2) During mergeClonesAfterCompletion() If the the acquire and release threads are different 
21
 *          switch back to the stored acquire thread stored on the mergeManager.
17
 ******************************************************************************/  
22
 ******************************************************************************/  
18
package org.eclipse.persistence.internal.sessions;
23
package org.eclipse.persistence.internal.sessions;
19
24
Lines 33-38 Link Here
33
import org.eclipse.persistence.internal.sequencing.Sequencing;
38
import org.eclipse.persistence.internal.sequencing.Sequencing;
34
import org.eclipse.persistence.sessions.coordination.MergeChangeSetCommand;
39
import org.eclipse.persistence.sessions.coordination.MergeChangeSetCommand;
35
import org.eclipse.persistence.sessions.factories.ReferenceMode;
40
import org.eclipse.persistence.sessions.factories.ReferenceMode;
41
import org.eclipse.persistence.logging.AbstractSessionLog;
36
import org.eclipse.persistence.logging.SessionLog;
42
import org.eclipse.persistence.logging.SessionLog;
37
import org.eclipse.persistence.mappings.DatabaseMapping;
43
import org.eclipse.persistence.mappings.DatabaseMapping;
38
import org.eclipse.persistence.internal.localization.LoggingLocalization;
44
import org.eclipse.persistence.internal.localization.LoggingLocalization;
Lines 3195-3200 Link Here
3195
     * for synchronized units of work, merge changes into parent
3201
     * for synchronized units of work, merge changes into parent
3196
     */
3202
     */
3197
    public void mergeClonesAfterCompletion() {
3203
    public void mergeClonesAfterCompletion() {
3204
        // Before we merge
3205
        // Check that the current thread is the active thread on all lock managers by checking the cached lockThread on the mergeManager.
3206
        // If we find that these 2 threads are different - then all threads in the acquired locks list are different.
3207
        // Switch the activeThread on the mutex to this current thread for each lock
3208
        Thread currentThread = Thread.currentThread();
3209
        if(null != this.getMergeManager()) { // mergeManager may be null in a com.ibm.tx.jta.RegisteredSyncs.coreDistributeAfter() afterCompletion() callback
3210
            Thread lockThread = this.getMergeManager().getLockThread();
3211
            if(currentThread != lockThread) {
3212
                ArrayList<CacheKey> locks = this.getMergeManager().getAcquiredLocks();        
3213
                if(null != locks) {                
3214
                    Iterator<CacheKey> locksIterator = locks.iterator();
3215
                    AbstractSessionLog.getLog().log(SessionLog.FINER, "active_thread_is_different_from_current_thread", 
3216
                        lockThread, this.getMergeManager(), currentThread);                                
3217
                    while(locksIterator.hasNext()) {
3218
                        ConcurrencyManager lockMutex = locksIterator.next().getMutex();
3219
                        if(null != lockMutex) {
3220
                            Thread activeThread = lockMutex.getActiveThread();
3221
                            // check for different acquire and release threads
3222
                            if(currentThread != activeThread) {
3223
                                // Switch activeThread to currentThread - we will release the lock later
3224
                                lockMutex.setActiveThread(currentThread);
3225
                            }
3226
                        }
3227
                    }
3228
                }
3229
            }
3230
        }
3231
        
3198
        mergeChangesIntoParent();
3232
        mergeChangesIntoParent();
3199
        // CR#... call event and log.
3233
        // CR#... call event and log.
3200
        getEventManager().postCommitUnitOfWork();
3234
        getEventManager().postCommitUnitOfWork();
Lines 3952-3957 Link Here
3952
     * Return if the object was deleted previously (in a flush).
3986
     * Return if the object was deleted previously (in a flush).
3953
     */
3987
     */
3954
    public boolean wasDeleted(Object original) {
3988
    public boolean wasDeleted(Object original) {
3989
        // Implemented by subclass
3955
        return false;
3990
        return false;
3956
    }
3991
    }
3957
    
3992
    
Lines 5289-5305 Link Here
5289
        this.optimisticReadLockObjects = null;
5324
        this.optimisticReadLockObjects = null;
5290
        this.batchReadObjects = null;
5325
        this.batchReadObjects = null;
5291
        if(shouldClearCache) {
5326
        if(shouldClearCache) {
5292
            this.getIdentityMapAccessor().initializeIdentityMaps();
5327
            clearIdentityMapCache();
5293
            if (this.getParent() instanceof IsolatedClientSession) {
5294
                this.getParent().getIdentityMapAccessor().initializeIdentityMaps();
5295
            }
5296
        }
5328
        }
5297
    }
5329
    }
5298
    
5330
    
5299
    /**
5331
    /**
5300
     * INTERNAL:
5332
     * INTERNAL:
5301
     * Call this method if the uow will no longer used for committing transactions:
5333
     * Clear the identityMaps
5302
     * all the changes sets will be dereferenced, and (optionally) the cache cleared.
5334
     */
5335
    private void clearIdentityMapCache() {
5336
        this.getIdentityMapAccessor().initializeIdentityMaps();
5337
        if (this.getParent() instanceof IsolatedClientSession) {
5338
            this.getParent().getIdentityMapAccessor().initializeIdentityMaps();
5339
        }
5340
    }
5341
        
5342
    /**
5343
     * INTERNAL:
5344
     * Call this method if the uow will no longer be used for committing transactions:
5345
     * all the change sets will be dereferenced, and (optionally) the cache cleared.
5303
     * If the uow is not released, but rather kept around for ValueHolders, then identity maps shouldn't be cleared:
5346
     * If the uow is not released, but rather kept around for ValueHolders, then identity maps shouldn't be cleared:
5304
     * the parameter value should be 'false'. The lifecycle set to Birth so that uow ValueHolder still could be used.
5347
     * the parameter value should be 'false'. The lifecycle set to Birth so that uow ValueHolder still could be used.
5305
     * Alternatively, if called from release method then everything should go and therefore parameter value should be 'true'.
5348
     * Alternatively, if called from release method then everything should go and therefore parameter value should be 'true'.
Lines 5307-5314 Link Here
5307
     * The reason for calling this method from release is to free maximum memory right away:
5350
     * The reason for calling this method from release is to free maximum memory right away:
5308
     * the uow might still be referenced by objects using UOWValueHolders (though they shouldn't be around
5351
     * the uow might still be referenced by objects using UOWValueHolders (though they shouldn't be around
5309
     * they still might).
5352
     * they still might).
5353
     * We defer a clear() call to release() if the uow lifecycle is 1,2 or 4 (*Pending).
5310
     */
5354
     */
5311
    public void clearForClose(boolean shouldClearCache) {
5355
    public void clearForClose(boolean shouldClearCache) {
5356
        //     259993: WebSphere 7.0 during a JPAEMPool.putEntityManager() afterCompletion callback
5357
        // may attempt to clear an entityManager in lifecyle/state 4 with a transaction commit active  
5358
        // that is in the middle of a commit for an insert or update by calling em.clear(true).  
5359
        //     We only clear the entityManager if we are in the states 
5360
        // (Birth == 0, WriteChangesFailed==3, Death==5 or AfterExternalTransactionRolledBack==6).
5361
        // If we are in one of the following *Pending states (1,2 and 4) we defer the clear() to the release() call later.
5362
        // Note: the single state CommitTransactionPending==2 may never happen as a result of an em.cler
5363
        if(this.getLifecycle() == this.CommitPending 
5364
                || this.getLifecycle() == this.CommitTransactionPending 
5365
                || this.getLifecycle() == this.MergePending) {
5366
            // Perform a partial clear() by clearing the identityMaps but leaving all other fields and lifecycle set.
5367
            // Later in release a clear(false) will clear everything else except the identityMaps.
5368
            // Certain application servers like WebSphere 7 will call em.clear() during commit()
5369
            // in order that the entityManager is cleared before returning the em to their server pool.
5370
            // Any entities that were managed will still be in the shared cache and database.            
5371
            if(shouldClearCache) {
5372
                clearIdentityMapCache();
5373
            }
5374
            // We must exit before we perform a full clear
5375
            return;
5376
        }
5377
        
5312
        clear(shouldClearCache);
5378
        clear(shouldClearCache);
5313
        if(isActive()) {
5379
        if(isActive()) {
5314
            //Reset lifecycle
5380
            //Reset lifecycle
(-)jpa/eclipselink.jpa.test/build.xml (-1 / +7 lines)
Lines 35-41 Link Here
35
        - test-static-weave : runs JPA LRG using static weaving
35
        - test-static-weave : runs JPA LRG using static weaving
36
36
37
        - server-start : starts the JEE server
37
        - server-start : starts the JEE server
38
        - server-stop : stops the JEE server
38
        - server-stop : stops the JEE server
39
        - server-restart : stops and restarts the JEE server (match the restart command in Eclipse)
39
        - server-test : runs the JPA LRG tests in the server
40
        - server-test : runs the JPA LRG tests in the server
40
        - server-test-lrg : runs the JPA LRG tests in the server
41
        - server-test-lrg : runs the JPA LRG tests in the server
41
        - server-test-sessionbean : runs the SessionBean tests in the server
42
        - server-test-sessionbean : runs the SessionBean tests in the server
Lines 853-858 Link Here
853
    <target name="server-stop" depends="detect-os">
854
    <target name="server-stop" depends="detect-os">
854
        <ant antfile="${eclipselink.jpa.test}/${server.name}.xml" target="${server.name}-stop" inheritRefs="true"/>
855
        <ant antfile="${eclipselink.jpa.test}/${server.name}.xml" target="${server.name}-stop" inheritRefs="true"/>
855
    </target>
856
    </target>
857
858
    <target name="server-restart" depends="detect-os">
859
        <ant antfile="${eclipselink.jpa.test}/${server.name}.xml" target="${server.name}-stop" inheritRefs="true"/>
860
        <ant antfile="${eclipselink.jpa.test}/${server.name}.xml" target="${server.name}-start" inheritRefs="true"/>
861
    </target>
856
862
857
    <target name="server-deploy">
863
    <target name="server-deploy">
858
        <ant antfile="${eclipselink.jpa.test}/${server.name}.xml" target="${server.name}-deploy" inheritRefs="true">
864
        <ant antfile="${eclipselink.jpa.test}/${server.name}.xml" target="${server.name}-deploy" inheritRefs="true">
(-)jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/advanced/concurrency/LifecycleJUnitTest.java (+337 lines)
Line 0 Link Here
1
/*******************************************************************************
2
 * Copyright (c) 1998, 2008 Oracle. All rights reserved.
3
 * This program and the accompanying materials are made available under the 
4
 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
5
 * which accompanies this distribution. 
6
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
7
 * and the Eclipse Distribution License is available at 
8
 * http://www.eclipse.org/org/documents/edl-v10.php.
9
 *
10
 * Contributors:
11
 *     Oracle - initial API and implementation from Oracle TopLink
12
 ******************************************************************************/  
13
package org.eclipse.persistence.testing.tests.jpa.advanced.concurrency;
14
15
import java.util.Map;
16
17
import javax.persistence.EntityManager;
18
import javax.persistence.EntityManagerFactory;
19
20
import junit.framework.AssertionFailedError;
21
import junit.framework.Test;
22
import junit.framework.TestSuite;
23
24
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
25
import org.eclipse.persistence.jpa.JpaEntityManager;
26
import org.eclipse.persistence.testing.framework.junit.JUnitTestCase;
27
import org.eclipse.persistence.testing.models.jpa.advanced.Department;
28
import org.eclipse.persistence.testing.models.jpa.advanced.AdvancedTableCreator;
29
30
/**
31
 *  This test suite verifies that the state/lifecycle on a unitOfWork does not reset to 0 (Birth)
32
 *  when a clearForClose() call is attempted in the middle of a *Pending state (1,2,4).
33
 *  
34
 *  Note: These tests verify internal API state that JPA functionality depends on.
35
 *  The tests are tightly coupled to the implementation of the following functions.
36
 *  Any change to the behavior of these functions may need to be reflected in these tests
37
 *  
38
 *     UnitOfWorkImpl.getCloneToOriginals()
39
 *     UnitOfWorkImpl.setPendingMerge()
40
 *     UnitOfWorkImpl.clearForClose()
41
 *     
42
 *  The server level JTA tests that verify that test this fix are the following   
43
 *   
44
 *     02/10/2009-1.1 Michael O'Brien 
45
 *        - 259993: Defer a clear() call to release() if uow lifecycle is 1,2 or 4 (*Pending).
46
 */
47
public class LifecycleJUnitTest extends JUnitTestCase {
48
49
    public LifecycleJUnitTest() {
50
        super();
51
    }
52
    
53
    public LifecycleJUnitTest(String name) {
54
        super(name);
55
    }
56
    
57
    public static Test suite() {
58
        TestSuite suite = new TestSuite("LifecycleJUnitTestSuite");
59
        suite.addTest(new LifecycleJUnitTest("testSetup"));
60
        suite.addTest(new LifecycleJUnitTest("testClearWhileEntityManagerInFakeMergePendingState4"));        
61
        suite.addTest(new LifecycleJUnitTest("testClearWhileEntityManagerInFakeBirthState0"));        
62
        suite.addTest(new LifecycleJUnitTest("testClearWhileEntityManagerInCommitPendingStateWithClearAfterCommit"));
63
        suite.addTest(new LifecycleJUnitTest("testClearWhileEntityManagerInCommitPendingStateWithNoClearAfterCommit"));        
64
        suite.addTest(new LifecycleJUnitTest("testClearAfterEntityManagerCommitFinished"));
65
                
66
        return suite;
67
    }
68
    
69
    // RESOURCE_LOCAL non container managed uow
70
    private UnitOfWorkImpl getUnitOfWorkFromEntityManager(EntityManager em) {
71
        return ((UnitOfWorkImpl)((JpaEntityManager)em).getActiveSession()).acquireUnitOfWork();    
72
    }
73
    
74
    public void testSetup() {
75
        clearCache();
76
        new AdvancedTableCreator().replaceTables(JUnitTestCase.getServerSession());
77
    }
78
79
    public void finalize() {
80
    }
81
    
82
    // This test is a pure unit test that directly sets and tries to clear the uow state
83
    // There are no actual entities managed in this example
84
    public void testClearWhileEntityManagerInFakeMergePendingState4() {    
85
        EntityManagerFactory emf = getEntityManagerFactory();
86
        EntityManager em = null;
87
        UnitOfWorkImpl  uow = null;
88
        Map cloneToOriginalsMap = null;
89
        Department dept = null;   
90
        
91
        try {
92
            em = emf.createEntityManager();
93
            // get the underlying uow
94
            uow = getUnitOfWorkFromEntityManager(em);
95
                        
96
            // force a get on the map to lazy initialize an empty map
97
            cloneToOriginalsMap = uow.getCloneToOriginals();
98
            // verify size 0
99
            // we don't have access to the protected function uow.hasCloneToOriginals();
100
            assertEquals("cloneToOriginalsMap must be size 0", 0, cloneToOriginalsMap.size());
101
            // Verify that cloneToOriginals is null and not lazy initialized
102
            dept = new Department();
103
            cloneToOriginalsMap.put(null, dept);
104
            // verify size 1
105
            assertEquals("cloneToOriginalsMap must be size 1", 1, cloneToOriginalsMap.size());
106
            
107
            // verify we are in birth state
108
            int lifecycleBefore = uow.getLifecycle();
109
            assertEquals("Birth state 0 is not set ", 0, lifecycleBefore);            
110
            // setup the uow in a simulated state
111
            uow.setPendingMerge(); // set state to 4 = MergePending
112
113
            // (via backdoor function) verify we are in PendingMerge state
114
            int lifecycleInMerge = uow.getLifecycle();
115
            assertEquals("MergePending state 4 is not set ", 4, lifecycleInMerge);
116
            // simulate a clear() call in the middle of a merge
117
            uow.clearForClose(false);
118
119
            // verify that the uow ignored the clear call
120
            int lifecycleAfter = uow.getLifecycle();
121
            assertEquals("Unchanged MergePending state 4 is not set ", 4, lifecycleAfter);            
122
            // verify that a map previously set on the uow was cleared to null by the
123
            // verify size 0
124
            assertNotNull("cloneToOriginals Map must not be null after a clear in *Pending state", cloneToOriginalsMap);
125
            assertEquals("cloneToOriginalsMap must be size 1", 1, cloneToOriginalsMap.size());
126
            
127
        } catch (AssertionFailedError e) {
128
            e.printStackTrace();
129
        } finally {
130
            closeEntityManager(em);
131
        }
132
    }
133
134
    public void testClearWhileEntityManagerInFakeBirthState0() {
135
        EntityManagerFactory emf = getEntityManagerFactory();
136
        EntityManager em = null;
137
        UnitOfWorkImpl  uow = null;
138
        Map cloneToOriginalsMap = null;
139
        Department dept = null;   
140
        try {
141
            em = emf.createEntityManager();
142
            // get the underlying uow
143
            uow = getUnitOfWorkFromEntityManager(em);
144
                        
145
            // force a get on the map to lazy initialize an empty map
146
            cloneToOriginalsMap = uow.getCloneToOriginals();
147
            // verify size 0
148
            // we don't have access to the protected function uow.hasCloneToOriginals();
149
            assertEquals("cloneToOriginalsMap must be size 0", 0, cloneToOriginalsMap.size());
150
            // Verify that cloneToOriginals is null and not lazy initialized
151
            dept = new Department();
152
            cloneToOriginalsMap.put(null, dept);
153
            // verify size 1
154
            assertEquals("cloneToOriginalsMap must be size 1", 1, cloneToOriginalsMap.size());
155
            
156
            // verify we are in birth state
157
            int lifecycleBefore = uow.getLifecycle();
158
            assertEquals("Birth state 0 is not set ", 0, lifecycleBefore);            
159
160
            // simulate a clear() call in the middle of a merge
161
            uow.clearForClose(false);
162
163
            // verify that the uow ignored the clear call
164
            int lifecycleAfter = uow.getLifecycle();
165
            assertEquals("Unchanged Birth state 4 is not set ", 0, lifecycleAfter);            
166
            // verify that a map previously set on the uow was cleared to null by the
167
            // verify size 0
168
            cloneToOriginalsMap = uow.getCloneToOriginals();
169
            assertNotNull("cloneToOriginals Map must not be null after a clear in Birth state", cloneToOriginalsMap);
170
            assertEquals("cloneToOriginalsMap must be size 1", 0, cloneToOriginalsMap.size());
171
            
172
        } catch (AssertionFailedError e) {
173
            e.printStackTrace();
174
        } finally {
175
            closeEntityManager(em);
176
        }
177
    }
178
    public void testClearWhileEntityManagerInFakeAfterExternalTransactionRolledBackState6() {
179
        
180
    }
181
    
182
    /**
183
     * This test simulates EE container callbacks that could occur that affect em lifecycle state.
184
     * Specifically it tests whether we handle an attempt to clear an entityManager 
185
     * that is in the middle of a commit.
186
     * We only clear the entityManager if we are in the states 
187
     * (Birth == 0, WriteChangesFailed==3, Death==5 or AfterExternalTransactionRolledBack==6).
188
     * If we are in one of the following *Pending states we defer the clear() to the release() call later  
189
     */
190
    public void testClearWhileEntityManagerInCommitPendingStateWithClearAfterCommit() {
191
        EntityManagerFactory emf = getEntityManagerFactory();
192
        EntityManager em = emf.createEntityManager();
193
        Department dept = null;   
194
        //Equipment equip = null;
195
        try {
196
            em.getTransaction().begin();
197
            dept = new Department();
198
            // A merge will not populate the @Id field
199
            //em.merge(dept);
200
            // A persist will populate the @Id field
201
            em.persist(dept);
202
        
203
            // simulate an attempt to call close() while we are in the middle of a commit
204
            UnitOfWorkImpl uow = getUnitOfWorkFromEntityManager(em);
205
206
            // get lifecycle state
207
            int lifecycleBefore = uow.getLifecycle();
208
            assertEquals("Birth state 0 is not set ", 0, lifecycleBefore);            
209
            
210
            uow.clearForClose(false);
211
            int lifecycleAfter = uow.getLifecycle();
212
            assertEquals("Birth state 0 is not set after a clear on state Birth  ", 0, lifecycleAfter);            
213
        
214
            //em.flush();
215
            em.getTransaction().commit();
216
217
            // clear em
218
            uow.clearForClose(false);
219
            
220
            int lifecycleAfterCommit = uow.getLifecycle();
221
            assertEquals("Birth state 0 is not set after commit ", 0, lifecycleAfterCommit);
222
        } catch (RuntimeException ex){
223
            if (isTransactionActive(em)){
224
                rollbackTransaction(em);
225
            }
226
            closeEntityManager(em);
227
            throw ex;
228
        } finally {
229
            // return database to previous state
230
            //em = emf.createEntityManager();
231
            em.getTransaction().begin();
232
            // a find should goto the database
233
            // Execute query ReadObjectQuery(referenceClass=Department sql="SELECT ID, NAME FROM CMP3_DEPT WHERE (ID = ?)")
234
            // The remove operation has been performed on: org.eclipse.persistence.testing.models.jpa.advanced.Department@34ea34ea
235
            em.remove(em.find(Department.class, dept.getId()));
236
            // Execute query DeleteObjectQuery(org.eclipse.persistence.testing.models.jpa.advanced.Department@d5c0d5c)
237
            // Execute query DataModifyQuery(sql="DELETE FROM CMP3_DEPT_CMP3_EMPLOYEE WHERE (ADV_DEPT_ID = ?)")
238
            em.getTransaction().commit();
239
        }
240
    }
241
242
    public void testClearWhileEntityManagerInCommitPendingStateWithNoClearAfterCommit() {
243
        EntityManagerFactory emf = getEntityManagerFactory();
244
        EntityManager em = emf.createEntityManager();
245
        Department dept = null;   
246
        //Equipment equip = null;
247
        try {
248
            em.getTransaction().begin();
249
            dept = new Department();
250
            // A merge will not populate the @Id field and will result in a PK null exception in any find later
251
            //em.merge(dept);
252
            // A persist will populate the @Id field
253
            em.persist(dept);
254
        
255
            // simulate an attempt to call close() while we are in the middle of a commit
256
            UnitOfWorkImpl uow = getUnitOfWorkFromEntityManager(em);
257
258
            // get lifecycle state
259
            int lifecycleBefore = uow.getLifecycle();
260
            assertEquals("Birth state 0 is not set ", 0, lifecycleBefore);            
261
            
262
            uow.clearForClose(false);
263
            int lifecycleAfter = uow.getLifecycle();
264
            assertEquals("Birth state 0 is not set after a clear on state Birth  ", 0, lifecycleAfter);            
265
        
266
            //em.flush();
267
            em.getTransaction().commit();
268
269
            // don't clear em
270
            //uow.clearForClose(false);
271
            
272
            int lifecycleAfterCommit = uow.getLifecycle();
273
            assertEquals("Birth state 0 is not set after commit ", 0, lifecycleAfterCommit);
274
        } catch (RuntimeException ex){
275
            if (isTransactionActive(em)){
276
                rollbackTransaction(em);
277
            }
278
            closeEntityManager(em);
279
            throw ex;
280
        } finally {
281
            // return database to previous state
282
            //em = emf.createEntityManager();
283
            em.getTransaction().begin();
284
            // perform the following
285
            // Execute query ReadObjectQuery(referenceClass=Department sql="SELECT ID, NAME FROM CMP3_DEPT WHERE (ID = ?)")
286
            // The remove operation has been performed on: org.eclipse.persistence.testing.models.jpa.advanced.Department@34ea34ea
287
            em.remove(em.find(Department.class, dept.getId()));
288
            // Execute query DeleteObjectQuery(org.eclipse.persistence.testing.models.jpa.advanced.Department@d5c0d5c)
289
            // Execute query DataModifyQuery()
290
            em.getTransaction().commit();
291
        }
292
    }
293
    
294
    // This clear should pass because the state is always 0 Begin except for inside the commit()
295
    public void testClearAfterEntityManagerCommitFinished() {
296
        EntityManagerFactory emf = getEntityManagerFactory();
297
        EntityManager em = emf.createEntityManager();
298
        Department dept = null;   
299
        //Equipment equip = null;
300
        try {
301
            em.getTransaction().begin();
302
            dept = new Department();
303
            em.persist(dept);
304
        
305
            // simulate an attempt to call close() while we are in the middle of a commit
306
            UnitOfWorkImpl uow = getUnitOfWorkFromEntityManager(em);
307
308
            // get lifecycle state
309
            int lifecycleBefore = uow.getLifecycle();
310
            assertEquals("Birth state 0 is not set ", 0, lifecycleBefore);            
311
            
312
            uow.clearForClose(false);
313
            int lifecycleAfter = uow.getLifecycle();
314
            assertEquals("Birth state 0 is not set after a clear on state Birth  ", 0, lifecycleAfter);            
315
        
316
            em.getTransaction().commit();
317
                
318
            uow.clearForClose(false);
319
            int lifecycleAfterCommit = uow.getLifecycle();
320
            assertEquals("Birth state 0 is not set after commit ", 0, lifecycleAfterCommit);
321
        } catch (RuntimeException ex){
322
            if (isTransactionActive(em)){
323
                rollbackTransaction(em);
324
            }
325
            closeEntityManager(em);
326
            throw ex;
327
        } finally {
328
            // return database to previous state
329
            em = emf.createEntityManager();
330
            em.getTransaction().begin();
331
            // If you get a PK null exception in any find then the entity was only merged and not persisted
332
            em.remove(em.find(Department.class, dept.getId()));
333
            //em.remove(em.find(Equipment.class, equip.getId()));
334
            em.getTransaction().commit();
335
        }
336
    }
337
}
(-)jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/advanced/EntityManagerJUnitTestSuite.java (-6 / +25 lines)
Lines 6966-6976 Link Here
6966
        project.getTeamMembers().add(employee);
6966
        project.getTeamMembers().add(employee);
6967
        commitTransaction(em);
6967
        commitTransaction(em);
6968
6968
6969
        verifyObject(project);
6969
6970
        verifyObject(employee);
6970
        // 264768: Certain application servers like WebSphere 7 will call em.clear() during commit()
6971
        // in order that the entityManager is cleared before returning the em to their server pool.
6972
        // We will want to verify that the entity is managed before accessing its properties and causing 
6973
        // the object to be rebuilt with any non-direct fields uninstantiated.
6974
        // Note: even in this case the entity should still be in the shared cache and database below
6975
        if(em.contains(employee)) {
6976
            verifyObject(project);
6977
            verifyObject(employee);
6978
        }
6979
        
6971
        clearCache();
6980
        clearCache();
6972
        verifyObject(project);
6981
        if(em.contains(employee)) {
6973
        verifyObject(employee);
6982
            verifyObject(project);
6983
            verifyObject(employee);
6984
        }
6974
    }
6985
    }
6975
    
6986
    
6976
    /**
6987
    /**
Lines 7022-7029 Link Here
7022
                fail("commit fetched object.");
7033
                fail("commit fetched object.");
7023
            }
7034
            }
7024
        }
7035
        }
7025
        if (employee.getVersion() != version) {
7036
        
7026
            fail("un-fetched object was updated");
7037
        // 264768: Certain application servers like WebSphere 7 will call em.clear() during commit()
7038
        // in order that the entityManager is cleared before returning the em to their server pool.
7039
        // We will want to verify that the entity is managed before accessing its properties and causing 
7040
        // the object to be rebuilt with any non-direct fields uninstantiated.
7041
        // Note: even in this case the entity should still be in the shared cache and database below
7042
        if(em.contains(employee)) {
7043
            if (employee.getVersion() != version) {
7044
                fail("un-fetched object was updated");
7045
            }
7027
        }
7046
        }
7028
7047
7029
        verifyObjectInCacheAndDatabase(newEmployee);
7048
        verifyObjectInCacheAndDatabase(newEmployee);
(-)jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/FullRegressionTestSuite.java (+2 lines)
Lines 29-34 Link Here
29
import org.eclipse.persistence.testing.tests.jpa.advanced.OptimisticConcurrencyJUnitTestSuite;
29
import org.eclipse.persistence.testing.tests.jpa.advanced.OptimisticConcurrencyJUnitTestSuite;
30
import org.eclipse.persistence.testing.tests.jpa.advanced.compositepk.AdvancedCompositePKJunitTest;
30
import org.eclipse.persistence.testing.tests.jpa.advanced.compositepk.AdvancedCompositePKJunitTest;
31
import org.eclipse.persistence.testing.tests.jpa.advanced.concurrency.ConcurrencyTest;
31
import org.eclipse.persistence.testing.tests.jpa.advanced.concurrency.ConcurrencyTest;
32
import org.eclipse.persistence.testing.tests.jpa.advanced.concurrency.LifecycleJUnitTest;
32
import org.eclipse.persistence.testing.tests.jpa.advanced.ReportQueryAdvancedJUnitTest;
33
import org.eclipse.persistence.testing.tests.jpa.advanced.ReportQueryAdvancedJUnitTest;
33
34
34
import org.eclipse.persistence.testing.tests.jpa.inheritance.LifecycleCallbackJunitTest;
35
import org.eclipse.persistence.testing.tests.jpa.inheritance.LifecycleCallbackJunitTest;
Lines 78-83 Link Here
78
        // Advanced model
79
        // Advanced model
79
        TestSuite suite = new TestSuite();
80
        TestSuite suite = new TestSuite();
80
        suite.setName("advanced");
81
        suite.setName("advanced");
82
        suite.addTest(LifecycleJUnitTest.suite());        
81
        suite.addTest(ConcurrencyTest.suite());
83
        suite.addTest(ConcurrencyTest.suite());
82
        suite.addTest(NamedNativeQueryJUnitTest.suite());
84
        suite.addTest(NamedNativeQueryJUnitTest.suite());
83
        suite.addTest(CacheImplJUnitTest.suite());
85
        suite.addTest(CacheImplJUnitTest.suite());

Return to bug 259993