| /* |
| * Copyright (c) 2011-2013, 2015 Eike Stepper (Berlin, Germany) and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Caspar De Groot - initial API and implementation |
| */ |
| package org.eclipse.emf.cdo.tests; |
| |
| import org.eclipse.emf.cdo.CDOObject; |
| import org.eclipse.emf.cdo.common.branch.CDOBranch; |
| import org.eclipse.emf.cdo.common.id.CDOID; |
| import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation; |
| import org.eclipse.emf.cdo.common.lock.CDOLockOwner; |
| import org.eclipse.emf.cdo.common.lock.CDOLockState; |
| import org.eclipse.emf.cdo.common.lock.CDOLockUtil; |
| import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch; |
| import org.eclipse.emf.cdo.eresource.CDOResource; |
| import org.eclipse.emf.cdo.session.CDOSession; |
| import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; |
| import org.eclipse.emf.cdo.tests.model1.Company; |
| import org.eclipse.emf.cdo.tests.util.TestListener2; |
| import org.eclipse.emf.cdo.transaction.CDOTransaction; |
| import org.eclipse.emf.cdo.util.CDOUtil; |
| import org.eclipse.emf.cdo.util.CommitException; |
| import org.eclipse.emf.cdo.view.CDOView; |
| import org.eclipse.emf.cdo.view.CDOViewLocksChangedEvent; |
| |
| import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; |
| import org.eclipse.net4j.util.event.IEvent; |
| |
| import java.util.List; |
| |
| /** |
| * @author Caspar De Groot |
| */ |
| public class LockingNotificationsTest extends AbstractLockingTest |
| { |
| private CDOView openViewWithLockNotifications(CDOSession session, CDOBranch branch) |
| { |
| CDOView view = branch != null ? session.openView(branch) : session.openView(); |
| view.options().setLockNotificationEnabled(true); |
| return view; |
| } |
| |
| /** |
| * FIXME Disabled until bug 358603 is addressed. |
| */ |
| public void _testSameBranchDifferentSession_explicitRelease() throws CommitException |
| { |
| sameBranchDifferentSession(LockReleaseMode.EXPLICIT); |
| } |
| |
| public void testSameBranchDifferentSession_autoRelease() throws CommitException |
| { |
| sameBranchDifferentSession(LockReleaseMode.AUTO); |
| } |
| |
| private void sameBranchDifferentSession(LockReleaseMode mode) throws CommitException |
| { |
| CDOSession session1 = openSession(); |
| CDOSession session2 = openSession(); |
| CDOView controlView = openViewWithLockNotifications(session2, null); |
| if (mode == LockReleaseMode.EXPLICIT) |
| { |
| withExplicitRelease(session1, controlView, true); |
| } |
| else if (mode == LockReleaseMode.AUTO) |
| { |
| withAutoRelease(session1, controlView, true); |
| } |
| |
| session1.close(); |
| session2.close(); |
| } |
| |
| public void testSameBranchSameSession_explicitRelease() throws CommitException |
| { |
| sameBranchSameSession(LockReleaseMode.EXPLICIT); |
| } |
| |
| public void testSameBranchSameSession_autoRelease() throws CommitException |
| { |
| sameBranchSameSession(LockReleaseMode.AUTO); |
| } |
| |
| private void sameBranchSameSession(LockReleaseMode mode) throws CommitException |
| { |
| CDOSession session1 = openSession(); |
| CDOView controlView = openViewWithLockNotifications(session1, null); |
| if (mode == LockReleaseMode.EXPLICIT) |
| { |
| withExplicitRelease(session1, controlView, true); |
| } |
| else if (mode == LockReleaseMode.AUTO) |
| { |
| withAutoRelease(session1, controlView, true); |
| } |
| |
| session1.close(); |
| } |
| |
| @Requires(IRepositoryConfig.CAPABILITY_BRANCHING) |
| public void testDifferentBranchDifferentSession() throws CommitException |
| { |
| differentBranchDifferentSession(LockReleaseMode.EXPLICIT); |
| } |
| |
| @Requires(IRepositoryConfig.CAPABILITY_BRANCHING) |
| public void testDifferentBranchDifferentSession_autoRelease() throws CommitException |
| { |
| differentBranchDifferentSession(LockReleaseMode.AUTO); |
| } |
| |
| private void differentBranchDifferentSession(LockReleaseMode mode) throws CommitException |
| { |
| CDOSession session1 = openSession(); |
| CDOBranch subBranch = session1.getBranchManager().getMainBranch().createBranch("sub1"); |
| CDOSession session2 = openSession(); |
| CDOView controlView = openViewWithLockNotifications(session2, subBranch); |
| if (mode == LockReleaseMode.EXPLICIT) |
| { |
| withExplicitRelease(session1, controlView, false); |
| } |
| else if (mode == LockReleaseMode.AUTO) |
| { |
| withAutoRelease(session1, controlView, false); |
| } |
| |
| session1.close(); |
| session2.close(); |
| } |
| |
| @Requires(IRepositoryConfig.CAPABILITY_BRANCHING) |
| public void testDifferentBranchSameSession() throws CommitException |
| { |
| differentBranchSameSession(LockReleaseMode.EXPLICIT); |
| } |
| |
| @Requires(IRepositoryConfig.CAPABILITY_BRANCHING) |
| public void testDifferentBranchSameSession_autoRelease() throws CommitException |
| { |
| differentBranchSameSession(LockReleaseMode.AUTO); |
| } |
| |
| private void differentBranchSameSession(LockReleaseMode mode) throws CommitException |
| { |
| CDOSession session1 = openSession(); |
| CDOBranch subBranch = session1.getBranchManager().getMainBranch().createBranch("sub2"); |
| CDOView controlView = openViewWithLockNotifications(session1, subBranch); |
| if (mode == LockReleaseMode.EXPLICIT) |
| { |
| withExplicitRelease(session1, controlView, false); |
| } |
| else if (mode == LockReleaseMode.AUTO) |
| { |
| withAutoRelease(session1, controlView, false); |
| } |
| |
| session1.close(); |
| } |
| |
| private void withExplicitRelease(CDOSession session1, CDOView controlView, boolean mustReceiveNotifications) |
| throws CommitException |
| { |
| TestListener2 controlViewListener = new TestListener2(CDOViewLocksChangedEvent.class); |
| controlView.addListener(controlViewListener); |
| |
| CDOTransaction tx1 = session1.openTransaction(); |
| CDOResource res1 = tx1.getOrCreateResource(getResourcePath("r1")); |
| TestListener2 transactionListener = new TestListener2(CDOViewLocksChangedEvent.class); |
| tx1.addListener(transactionListener); |
| res1.getContents().clear(); |
| Company company = getModel1Factory().createCompany(); |
| res1.getContents().add(company); |
| tx1.commit(); |
| |
| CDOObject cdoCompany = CDOUtil.getCDOObject(company); |
| |
| CDOObject cdoCompanyInControlView = null; |
| if (mustReceiveNotifications) |
| { |
| cdoCompanyInControlView = controlView.getObject(cdoCompany.cdoID()); |
| } |
| |
| /* Test write lock */ |
| |
| cdoCompany.cdoWriteLock().lock(); |
| if (mustReceiveNotifications) |
| { |
| controlViewListener.waitFor(1); |
| assertEquals(1, controlViewListener.getEvents().size()); |
| |
| CDOViewLocksChangedEvent event = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(0); |
| assertLockOwner(tx1, event.getLockOwner()); |
| |
| CDOLockState[] lockStates = event.getLockStates(); |
| assertEquals(1, lockStates.length); |
| assertLockedObject(cdoCompany, lockStates[0].getLockedObject()); |
| assertLockOwner(tx1, lockStates[0].getWriteLockOwner()); |
| assertEquals(cdoCompanyInControlView.cdoLockState(), lockStates[0]); |
| } |
| |
| cdoCompany.cdoWriteLock().unlock(); |
| if (mustReceiveNotifications) |
| { |
| controlViewListener.waitFor(2); |
| |
| assertEquals(2, controlViewListener.getEvents().size()); |
| |
| CDOViewLocksChangedEvent event = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(1); |
| assertLockOwner(tx1, event.getLockOwner()); |
| |
| CDOLockState[] lockStates = event.getLockStates(); |
| assertEquals(1, lockStates.length); |
| assertLockedObject(cdoCompany, lockStates[0].getLockedObject()); |
| assertNull(lockStates[0].getWriteLockOwner()); |
| assertEquals(cdoCompanyInControlView.cdoLockState(), lockStates[0]); |
| } |
| |
| /* Test read lock */ |
| |
| cdoCompany.cdoReadLock().lock(); |
| if (mustReceiveNotifications) |
| { |
| controlViewListener.waitFor(3); |
| assertEquals(3, controlViewListener.getEvents().size()); |
| |
| CDOViewLocksChangedEvent event = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(2); |
| assertLockOwner(tx1, event.getLockOwner()); |
| |
| CDOLockState[] lockStates = event.getLockStates(); |
| assertEquals(1, lockStates.length); |
| assertLockedObject(cdoCompany, lockStates[0].getLockedObject()); |
| assertEquals(1, lockStates[0].getReadLockOwners().size()); |
| CDOLockOwner tx1Lo = CDOLockUtil.createLockOwner(tx1); |
| assertEquals(true, lockStates[0].getReadLockOwners().contains(tx1Lo)); |
| assertEquals(cdoCompanyInControlView.cdoLockState(), lockStates[0]); |
| } |
| |
| cdoCompany.cdoReadLock().unlock(); |
| if (mustReceiveNotifications) |
| { |
| controlViewListener.waitFor(4); |
| |
| assertEquals(4, controlViewListener.getEvents().size()); |
| |
| CDOViewLocksChangedEvent event = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(3); |
| assertLockOwner(tx1, event.getLockOwner()); |
| |
| CDOLockState[] lockStates = event.getLockStates(); |
| assertEquals(1, lockStates.length); |
| assertEquals(0, lockStates[0].getReadLockOwners().size()); |
| assertEquals(cdoCompanyInControlView.cdoLockState(), lockStates[0]); |
| } |
| |
| /* Test write option */ |
| |
| cdoCompany.cdoWriteOption().lock(); |
| if (mustReceiveNotifications) |
| { |
| controlViewListener.waitFor(5); |
| assertEquals(5, controlViewListener.getEvents().size()); |
| |
| CDOViewLocksChangedEvent event = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(4); |
| assertLockOwner(tx1, event.getLockOwner()); |
| |
| CDOLockState[] lockStates = event.getLockStates(); |
| assertEquals(1, lockStates.length); |
| assertLockedObject(cdoCompany, lockStates[0].getLockedObject()); |
| assertLockOwner(tx1, lockStates[0].getWriteOptionOwner()); |
| assertEquals(cdoCompanyInControlView.cdoLockState(), lockStates[0]); |
| } |
| |
| cdoCompany.cdoWriteOption().unlock(); |
| if (mustReceiveNotifications) |
| { |
| controlViewListener.waitFor(6); |
| |
| assertEquals(6, controlViewListener.getEvents().size()); |
| |
| CDOViewLocksChangedEvent event = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(5); |
| assertLockOwner(tx1, event.getLockOwner()); |
| |
| CDOLockState[] lockStates = event.getLockStates(); |
| assertEquals(1, lockStates.length); |
| assertLockedObject(cdoCompany, lockStates[0].getLockedObject()); |
| assertNull(lockStates[0].getWriteOptionOwner()); |
| assertEquals(cdoCompanyInControlView.cdoLockState(), lockStates[0]); |
| } |
| |
| List<IEvent> events = transactionListener.getEvents(); |
| assertEquals(6, events.size()); |
| |
| if (!mustReceiveNotifications) |
| { |
| assertEquals(0, controlViewListener.getEvents().size()); |
| } |
| } |
| |
| private void withAutoRelease(CDOSession session1, CDOView controlView, boolean mustReceiveNotifications) |
| throws CommitException |
| { |
| TestListener2 controlViewListener = new TestListener2(CDOViewLocksChangedEvent.class); |
| controlView.addListener(controlViewListener); |
| |
| CDOTransaction tx1 = session1.openTransaction(); |
| tx1.options().setAutoReleaseLocksEnabled(true); |
| CDOResource res1 = tx1.getOrCreateResource(getResourcePath("r1")); |
| res1.getContents().clear(); |
| Company company = getModel1Factory().createCompany(); |
| res1.getContents().add(company); |
| tx1.commit(); |
| |
| implicitRelease(company, LockType.WRITE, tx1, controlViewListener, mustReceiveNotifications); |
| implicitRelease(company, LockType.READ, tx1, controlViewListener, mustReceiveNotifications); |
| implicitRelease(company, LockType.OPTION, tx1, controlViewListener, mustReceiveNotifications); |
| } |
| |
| private void implicitRelease(Company company, LockType type, CDOTransaction tx, TestListener2 controlViewListener, |
| boolean mustReceiveNotifications) throws CommitException |
| { |
| CDOViewLocksChangedEvent e; |
| CDOObject cdoCompany = CDOUtil.getCDOObject(company); |
| |
| company.setName(company.getName() + "x"); // Make name field dirty |
| cdoCompany.cdoWriteLock().lock(); |
| |
| if (mustReceiveNotifications) |
| { |
| controlViewListener.waitFor(1); |
| e = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(0); |
| assertEquals(Operation.LOCK, e.getOperation()); |
| assertEquals(LockType.WRITE, e.getLockType()); |
| } |
| |
| tx.commit(); |
| |
| if (mustReceiveNotifications) |
| { |
| controlViewListener.waitFor(2); |
| e = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(1); |
| assertEquals(Operation.UNLOCK, e.getOperation()); |
| assertNull(e.getLockType()); |
| } |
| |
| if (!mustReceiveNotifications) |
| { |
| assertEquals(0, controlViewListener.getEvents().size()); |
| } |
| } |
| |
| private void assertLockedObject(CDOObject obj, Object lockedObject) |
| { |
| if (lockedObject instanceof CDOIDAndBranch) |
| { |
| CDOIDAndBranch idAndBranch = (CDOIDAndBranch)lockedObject; |
| assertEquals(obj.cdoID(), idAndBranch.getID()); |
| assertEquals(obj.cdoView().getBranch().getID(), idAndBranch.getBranch().getID()); |
| } |
| else if (lockedObject instanceof CDOID) |
| { |
| assertEquals(obj.cdoID(), lockedObject); |
| } |
| } |
| |
| private void assertLockOwner(CDOView view, CDOLockOwner lockOwner) |
| { |
| CDOLockOwner lo = CDOLockUtil.createLockOwner(view); |
| assertEquals(lo, lockOwner); |
| } |
| |
| public void testEnableDisableNotifications() throws CommitException |
| { |
| CDOSession session1 = openSession(); |
| CDOSession session2 = openSession(); |
| CDOView controlView = session2.openView(); |
| withExplicitRelease(session1, controlView, false); |
| |
| controlView.options().setLockNotificationEnabled(true); |
| withExplicitRelease(session1, controlView, true); |
| |
| controlView.options().setLockNotificationEnabled(false); |
| withExplicitRelease(session1, controlView, false); |
| |
| session1.close(); |
| session2.close(); |
| } |
| |
| public void testLockStateHeldByDurableView() throws CommitException |
| { |
| skipStoreWithoutDurableLocking(); |
| |
| { |
| CDOSession session1 = openSession(); |
| CDOTransaction tx1 = session1.openTransaction(); |
| tx1.enableDurableLocking(); |
| CDOResource res1 = tx1.createResource(getResourcePath("r1")); |
| Company company1 = getModel1Factory().createCompany(); |
| res1.getContents().add(company1); |
| tx1.commit(); |
| |
| CDOUtil.getCDOObject(company1).cdoWriteLock().lock(); |
| tx1.close(); |
| session1.close(); |
| } |
| |
| CDOSession session2 = openSession(); |
| CDOView controlView = session2.openView(); |
| CDOResource resource = controlView.getResource(getResourcePath("r1")); |
| Company company1 = (Company)resource.getContents().get(0); |
| CDOObject cdoObj = CDOUtil.getCDOObject(company1); |
| assertEquals(true, cdoObj.cdoWriteLock().isLockedByOthers()); |
| assertEquals(true, cdoObj.cdoLockState().getWriteLockOwner().isDurableView()); |
| session2.close(); |
| } |
| |
| public void testLockStateNewAndTransient() throws CommitException |
| { |
| Company company1 = getModel1Factory().createCompany(); |
| CDOObject cdoObj = CDOUtil.getCDOObject(company1); |
| assertTransient(cdoObj); |
| assertNull(cdoObj.cdoLockState()); |
| |
| CDOSession session1 = openSession(); |
| CDOTransaction tx1 = session1.openTransaction(); |
| CDOResource res1 = tx1.createResource(getResourcePath("r1")); |
| res1.getContents().add(company1); |
| assertNew(cdoObj, tx1); |
| assertNotNull(cdoObj.cdoLockState()); |
| |
| res1.getContents().remove(company1); |
| assertTransient(cdoObj); |
| assertNull(cdoObj.cdoLockState()); |
| |
| res1.getContents().add(company1); |
| tx1.commit(); |
| assertClean(cdoObj, tx1); |
| assertNotNull(cdoObj.cdoLockState()); |
| |
| res1.getContents().remove(company1); |
| assertTransient(cdoObj); |
| assertNull(cdoObj.cdoLockState()); |
| |
| session1.close(); |
| } |
| |
| /** |
| * @author Caspar De Groot |
| */ |
| private static enum LockReleaseMode |
| { |
| EXPLICIT, AUTO |
| } |
| } |