summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCaspar De Groot2011-08-17 22:24:31 (EDT)
committerCaspar De Groot2011-08-17 22:24:31 (EDT)
commitb7e84a0e190445f303dc8fa918cd5a7c6c0670f6 (patch)
tree776782d6099f9228e8764ce57b692914e9b80812
parent8c9b3bb2192a53b7ee1eff6035462f04c20ba842 (diff)
downloadcdo-b7e84a0e190445f303dc8fa918cd5a7c6c0670f6.zip
cdo-b7e84a0e190445f303dc8fa918cd5a7c6c0670f6.tar.gz
cdo-b7e84a0e190445f303dc8fa918cd5a7c6c0670f6.tar.bz2
[353691] Add lock notifications and lock caching
https://bugs.eclipse.org/bugs/show_bug.cgi?id=353691
-rw-r--r--plugins/org.eclipse.emf.cdo.common/META-INF/MANIFEST.MF2
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockChangeInfo.java62
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockOwner.java55
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockState.java56
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockUtil.java97
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/IDurableLockingManager.java44
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataInput.java18
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataOutput.java18
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOProtocolConstants.java25
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockChangeInfoImpl.java65
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockOwnerImpl.java76
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockStateImpl.java171
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataInputImpl.java78
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataOutputImpl.java83
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/lock/InternalCDOLockState.java31
-rw-r--r--plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/AbstractOfflineExampleServer.java16
-rw-r--r--plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/OfflineExampleClient.java77
-rw-r--r--plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/OfflineExampleMaster.java8
-rw-r--r--plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java84
-rw-r--r--plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CommitTransactionRequest.java15
-rw-r--r--plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/EnableLockNotificationRequest.java47
-rw-r--r--plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockDelegationRequest.java43
-rw-r--r--plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockNotificationIndication.java38
-rw-r--r--plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockObjectsRequest.java53
-rw-r--r--plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockStateRequest.java61
-rw-r--r--plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/UnlockDelegationRequest.java42
-rw-r--r--plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/UnlockObjectsRequest.java47
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java12
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java23
-rw-r--r--plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java25
-rw-r--r--plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CommitTransactionIndication.java23
-rw-r--r--plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/EnableLockNotificationIndication.java45
-rw-r--r--plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockDelegationIndication.java94
-rw-r--r--plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockNotificationRequest.java37
-rw-r--r--plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockObjectsIndication.java145
-rw-r--r--plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockStateIndication.java90
-rw-r--r--plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/OpenViewIndication.java13
-rw-r--r--plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/UnlockDelegationIndication.java65
-rw-r--r--plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/UnlockObjectsIndication.java44
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/LockManager.java85
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java156
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java27
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java18
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java18
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java11
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/View.java25
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedClientSessionProtocol.java39
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedServerSessionProtocol.java7
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java27
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java10
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/SynchronizableRepository.java101
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java16
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/ISessionProtocol.java6
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockManager.java41
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockingManagerContext.java20
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java15
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java6
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java6
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalView.java10
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2Offline.java2
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java1
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsMEMOffline.java2
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/LockingNotificationsTest.java341
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineLockingTest.java67
-rw-r--r--plugins/org.eclipse.emf.cdo/.settings/.api_filters20
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOObject.java8
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOLocksChangedEvent.java24
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOView.java31
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java53
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java22
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLockImpl.java13
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java55
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java108
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java7
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java170
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java98
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOObject.java8
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSession.java6
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOView.java13
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ObjectUtil.java17
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/IRWOLockManager.java29
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWOLockManager.java110
82 files changed, 3588 insertions, 289 deletions
diff --git a/plugins/org.eclipse.emf.cdo.common/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.common/META-INF/MANIFEST.MF
index dcc75cd..0b80784 100644
--- a/plugins/org.eclipse.emf.cdo.common/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.cdo.common/META-INF/MANIFEST.MF
@@ -56,6 +56,7 @@ Export-Package: org.eclipse.emf.cdo.common;version="4.1.0",
org.eclipse.emf.cdo.server.net4j,
org.eclipse.emf.cdo.ui,
org.eclipse.emf.cdo.tests",
+ org.eclipse.emf.cdo.internal.common.lock;version="4.1.0";x-internal:=true,
org.eclipse.emf.cdo.internal.common.messages;version="4.1.0";x-internal:=true,
org.eclipse.emf.cdo.internal.common.model;version="4.1.0";
x-friends:="org.eclipse.emf.cdo.common,
@@ -97,5 +98,6 @@ Export-Package: org.eclipse.emf.cdo.common;version="4.1.0",
org.eclipse.emf.cdo.spi.common.branch;version="4.1.0",
org.eclipse.emf.cdo.spi.common.commit;version="4.1.0",
org.eclipse.emf.cdo.spi.common.id;version="4.1.0",
+ org.eclipse.emf.cdo.spi.common.lock;version="4.1.0",
org.eclipse.emf.cdo.spi.common.model;version="4.1.0",
org.eclipse.emf.cdo.spi.common.revision;version="4.1.0"
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockChangeInfo.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockChangeInfo.java
new file mode 100644
index 0000000..0307719
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockChangeInfo.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2004 - 2011 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.common.lock;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+
+/**
+ * Represents a change in the lock state of a set of objects. Instances are meant to be sent from the server to the
+ * client for the purpose of notifying the latter.
+ *
+ * @author Caspar De Groot
+ * @since 4.1
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface CDOLockChangeInfo extends CDOBranchPoint
+{
+ /**
+ * @return The branch at which the lock changes took place, same as <code>getView().getBranch()</code>.
+ */
+ public CDOBranch getBranch();
+
+ /**
+ * @return The repository time at which the lock changes took place. This is only an informal indication; no formal
+ * relation (e.g. an ordering) with commit timestamps is guaranteed.
+ */
+ public long getTimeStamp();
+
+ /**
+ * @return The view, represented as a {@link CDOLockOwner}, that authored the lock changes.
+ */
+ public CDOLockOwner getLockOwner();
+
+ /**
+ * @return The new lock states of the objects that were affected by the change
+ */
+ public CDOLockState[] getLockStates();
+
+ /**
+ * @return the type of lock operation that caused the lock changes
+ */
+ public Operation getOperation();
+
+ /**
+ * Enumerates the possible locking operations.
+ *
+ * @author Caspar De Groot
+ */
+ public enum Operation
+ {
+ LOCK, UNLOCK
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockOwner.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockOwner.java
new file mode 100644
index 0000000..012fc15
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockOwner.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2004 - 2011 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.common.lock;
+
+/**
+ * A client-side representation of a view owning locks.
+ * <p>
+ *
+ * @author Caspar De Groot
+ * @since 4.1
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface CDOLockOwner
+{
+ /**
+ * @return the ID identifying the session that owns the view
+ */
+ public int getSessionID();
+
+ /**
+ * @return the ID identifying the view within the session
+ */
+ public int getViewID();
+
+ /**
+ * A constant to represent on the client-side that a lock's owner cannot be represented as a viewID-sessionID pair.
+ */
+ public static final CDOLockOwner UNKNOWN = new CDOLockOwner()
+ {
+ public int getViewID()
+ {
+ return 0;
+ }
+
+ public int getSessionID()
+ {
+ return 0;
+ }
+
+ @Override
+ public String toString()
+ {
+ return CDOLockOwner.class.getSimpleName() + ".UNKNOWN";
+ }
+ };
+}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockState.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockState.java
new file mode 100644
index 0000000..0e470b2
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockState.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2004 - 2011 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.common.lock;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch;
+
+import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+
+import java.util.Set;
+
+/**
+ * A client-side representation of <i>all</i> the locks on a single CDOObject.
+ * <p>
+ * As an individual lock is always owned by view, which in turn is owned by a session, the methods on this interface
+ * return instances of {@link CDOLockOwner} which carry that information.
+ * <p>
+ *
+ * @author Caspar De Groot
+ * @since 4.1
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface CDOLockState
+{
+ /**
+ * Gets a unique identifier for the object that is locked; typically a {@link CDOID} or a {@link CDOIDAndBranch},
+ * depending on whether branching support is enabled or not
+ *
+ * @return the identifier
+ */
+ public Object getLockedObject();
+
+ /**
+ * If the 'others' argument is <code>false</code>, this method returns <code>true</code> if this lock is currently
+ * held by the <i>requesting</i> CDOView, <code>false</code> otherwise.
+ * <p>
+ * If the 'others' argument is <code>true</code>, this method returns <code>true</code> if this lock is currently held
+ * by <i>another</i> view (i.e. any view different from the requesting one), <code>false</code> otherwise.
+ */
+ public boolean isLocked(LockType lockType, CDOLockOwner lockOwner, boolean others);
+
+ public Set<CDOLockOwner> getReadLockOwners();
+
+ public CDOLockOwner getWriteLockOwner();
+
+ public CDOLockOwner getWriteOptionOwner();
+}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockUtil.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockUtil.java
new file mode 100644
index 0000000..d36d907
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockUtil.java
@@ -0,0 +1,97 @@
+/**
+ * Copyright (c) 2004 - 2011 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.common.lock;
+
+import org.eclipse.emf.cdo.common.CDOCommonSession;
+import org.eclipse.emf.cdo.common.CDOCommonView;
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation;
+import org.eclipse.emf.cdo.internal.common.lock.CDOLockChangeInfoImpl;
+import org.eclipse.emf.cdo.internal.common.lock.CDOLockOwnerImpl;
+import org.eclipse.emf.cdo.internal.common.lock.CDOLockStateImpl;
+import org.eclipse.emf.cdo.spi.common.lock.InternalCDOLockState;
+
+import org.eclipse.net4j.util.CheckUtil;
+import org.eclipse.net4j.util.concurrent.RWOLockManager.LockState;
+
+/**
+ * Various static methods that may help with classes related to CDO locks.
+ *
+ * @author Caspar De Groot
+ * @since 4.1
+ */
+public final class CDOLockUtil
+{
+ private CDOLockUtil()
+ {
+ }
+
+ public static CDOLockState createLockState(Object target)
+ {
+ return new CDOLockStateImpl(target);
+ }
+
+ public static CDOLockState createLockState(LockState<Object, ? extends CDOCommonView> lockState)
+ {
+ CheckUtil.checkArg(lockState, "lockState");
+
+ InternalCDOLockState cdoLockState = new CDOLockStateImpl(lockState.getLockedObject());
+
+ for (CDOCommonView view : lockState.getReadLockOwners())
+ {
+ int sessionID = view.getSession().getSessionID();
+ int viewID = view.getViewID();
+ CDOLockOwner owner = new CDOLockOwnerImpl(sessionID, viewID);
+ cdoLockState.addReadLockOwner(owner);
+ }
+
+ CDOCommonView writeLockOwner = lockState.getWriteLockOwner();
+ if (writeLockOwner != null)
+ {
+ CDOLockOwner owner = createLockOwner(writeLockOwner);
+ cdoLockState.setWriteLockOwner(owner);
+ }
+
+ CDOCommonView writeOptionOwner = lockState.getWriteOptionOwner();
+ if (writeOptionOwner != null)
+ {
+ CDOLockOwner owner = createLockOwner(writeOptionOwner);
+ cdoLockState.setWriteOptionOwner(owner);
+ }
+
+ return cdoLockState;
+ }
+
+ public static CDOLockOwner createLockOwner(CDOCommonView view)
+ {
+ CDOCommonSession session = view.getSession();
+ if (session != null)
+ {
+ int sessionID = session.getSessionID();
+ int viewID = view.getViewID();
+ return new CDOLockOwnerImpl(sessionID, viewID);
+ }
+ return CDOLockOwner.UNKNOWN;
+ }
+
+ public static CDOLockChangeInfo createLockChangeInfo(long timestamp, CDOLockOwner lockOwner, CDOBranch branch,
+ Operation op, CDOLockState[] cdoLockStates)
+ {
+ return new CDOLockChangeInfoImpl(branch.getPoint(timestamp), lockOwner, cdoLockStates, op);
+ }
+
+ public static CDOLockChangeInfo createLockChangeInfo(long timestamp, CDOCommonView view, CDOBranch viewedBranch,
+ Operation op, CDOLockState[] cdoLockStates)
+ {
+ CDOLockOwner lockOwner = createLockOwner(view);
+ return createLockChangeInfo(timestamp, lockOwner, viewedBranch, op, cdoLockStates);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/IDurableLockingManager.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/IDurableLockingManager.java
index 7d042af..5343f8f 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/IDurableLockingManager.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/IDurableLockingManager.java
@@ -24,8 +24,6 @@ import java.util.Map;
*
* @author Eike Stepper
* @since 4.0
- * @noextend This interface is not intended to be extended by clients.
- * @noimplement This interface is not intended to be implemented by clients.
*/
public interface IDurableLockingManager
{
@@ -104,6 +102,28 @@ public interface IDurableLockingManager
}
/**
+ * @author Caspar De Groot
+ * @since 4.1
+ */
+ public static class LockAreaAlreadyExistsException extends IllegalStateException
+ {
+ private static final long serialVersionUID = 1L;
+
+ private String durableLockingID;
+
+ public LockAreaAlreadyExistsException(String durableLockingID)
+ {
+ super("A lock area with ID=" + durableLockingID + " already exists");
+ this.durableLockingID = durableLockingID;
+ }
+
+ public String getDurableLockingID()
+ {
+ return durableLockingID;
+ }
+ }
+
+ /**
* Enumerates the possible combinations of read and write locks on a single CDO object.
*
* @author Eike Stepper
@@ -165,7 +185,8 @@ public interface IDurableLockingManager
public LockGrade getUpdated(LockType type, boolean on)
{
- int mask = type == LockType.READ ? 1 : 2;
+ int mask = getMask(type);
+
if (on)
{
return get(value | mask);
@@ -174,6 +195,23 @@ public interface IDurableLockingManager
return get(value & ~mask);
}
+ private int getMask(LockType type)
+ {
+ switch (type)
+ {
+ case READ:
+ return 1;
+
+ case WRITE:
+ return 2;
+
+ case OPTION:
+ return 4;
+ }
+
+ return 0;
+ }
+
public static LockGrade get(LockType type)
{
if (type == LockType.READ)
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataInput.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataInput.java
index 2cbbde9..acab6ac 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataInput.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataInput.java
@@ -19,6 +19,9 @@ import org.eclipse.emf.cdo.common.commit.CDOCommitData;
import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDReference;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockOwner;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.model.CDOClassifierRef;
import org.eclipse.emf.cdo.common.model.CDOPackageInfo;
import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
@@ -135,4 +138,19 @@ public interface CDODataInput extends ExtendedDataInput
// /////////////////////////////////////////////////////////////////////////////////////////////////
public LockType readCDOLockType() throws IOException;
+
+ /**
+ * @since 4.1
+ */
+ public CDOLockChangeInfo readCDOLockChangeInfo() throws IOException;
+
+ /**
+ * @since 4.1
+ */
+ public CDOLockOwner readCDOLockOwner() throws IOException;
+
+ /**
+ * @since 4.1
+ */
+ public CDOLockState readCDOLockState() throws IOException;
}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataOutput.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataOutput.java
index db036d7..9c040d4 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataOutput.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataOutput.java
@@ -20,6 +20,9 @@ import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDProvider;
import org.eclipse.emf.cdo.common.id.CDOIDReference;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockOwner;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.model.CDOClassifierRef;
import org.eclipse.emf.cdo.common.model.CDOPackageInfo;
import org.eclipse.emf.cdo.common.model.CDOPackageRegistry;
@@ -141,4 +144,19 @@ public interface CDODataOutput extends ExtendedDataOutput
// /////////////////////////////////////////////////////////////////////////////////////////////////
public void writeCDOLockType(LockType lockType) throws IOException;
+
+ /**
+ * @since 4.1
+ */
+ public void writeCDOLockChangeInfo(CDOLockChangeInfo lockChangeInfo) throws IOException;
+
+ /**
+ * @since 4.1
+ */
+ public void writeCDOLockState(CDOLockState lockState) throws IOException;
+
+ /**
+ * @since 4.1
+ */
+ public void writeCDOLockOwner(CDOLockOwner lockOwner) throws IOException;
}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOProtocolConstants.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOProtocolConstants.java
index ef2fbfe..722b158 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOProtocolConstants.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOProtocolConstants.java
@@ -217,6 +217,31 @@ public interface CDOProtocolConstants
*/
public static final short SIGNAL_HANDLE_REVISIONS = 48;
+ /**
+ * @since 4.1
+ */
+ public static final short SIGNAL_LOCK_DELEGATION = 49;
+
+ /**
+ * @since 4.1
+ */
+ public static final short SIGNAL_UNLOCK_DELEGATION = 50;
+
+ /**
+ * @since 4.1
+ */
+ public static final short SIGNAL_LOCK_NOTIFICATION = 51;
+
+ /**
+ * @since 4.1
+ */
+ public static final short SIGNAL_LOCK_STATE = 52;
+
+ /**
+ * @since 4.1
+ */
+ public static final short SIGNAL_ENABLE_LOCK_NOTIFICATION = 53;
+
// //////////////////////////////////////////////////////////////////////
// Session Refresh
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockChangeInfoImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockChangeInfoImpl.java
new file mode 100644
index 0000000..70c4c0a
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockChangeInfoImpl.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2004 - 2011 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.internal.common.lock;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockOwner;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
+
+/**
+ * @author Caspar De Groot
+ */
+public class CDOLockChangeInfoImpl implements CDOLockChangeInfo
+{
+ private final CDOBranchPoint branchPoint;
+
+ private final CDOLockOwner lockOwner;
+
+ private final CDOLockState[] lockStates;
+
+ private final Operation operation;
+
+ public CDOLockChangeInfoImpl(CDOBranchPoint branchPoint, CDOLockOwner lockOwner, CDOLockState[] lockStates,
+ Operation operation)
+ {
+ this.branchPoint = branchPoint;
+ this.lockOwner = lockOwner;
+ this.lockStates = lockStates;
+ this.operation = operation;
+ }
+
+ public CDOBranch getBranch()
+ {
+ return branchPoint.getBranch();
+ }
+
+ public long getTimeStamp()
+ {
+ return branchPoint.getTimeStamp();
+ }
+
+ public CDOLockOwner getLockOwner()
+ {
+ return lockOwner;
+ }
+
+ public CDOLockState[] getLockStates()
+ {
+ return lockStates;
+ }
+
+ public Operation getOperation()
+ {
+ return operation;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockOwnerImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockOwnerImpl.java
new file mode 100644
index 0000000..3509e5f
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockOwnerImpl.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2004 - 2011 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.internal.common.lock;
+
+import org.eclipse.emf.cdo.common.lock.CDOLockOwner;
+
+import org.eclipse.net4j.util.ObjectUtil;
+
+/**
+ * @author Caspar De Groot
+ */
+public class CDOLockOwnerImpl implements CDOLockOwner
+{
+ private final int sessionID;
+
+ private final int viewID;
+
+ public CDOLockOwnerImpl(int sessionID, int viewID)
+ {
+ this.sessionID = sessionID;
+ this.viewID = viewID;
+ }
+
+ public int getSessionID()
+ {
+ return sessionID;
+ }
+
+ public int getViewID()
+ {
+ return viewID;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return ObjectUtil.hashCode(sessionID, viewID);
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (obj instanceof CDOLockOwner)
+ {
+ CDOLockOwner that = (CDOLockOwner)obj;
+ return sessionID == that.getSessionID() && viewID == that.getViewID();
+ }
+
+ return false;
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder("CDOLockOwner[");
+ builder.append("session=");
+ builder.append(sessionID);
+ builder.append(", view=");
+ builder.append(viewID);
+ builder.append(']');
+ return builder.toString();
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockStateImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockStateImpl.java
new file mode 100644
index 0000000..3520709
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockStateImpl.java
@@ -0,0 +1,171 @@
+/**
+ * Copyright (c) 2004 - 2011 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.internal.common.lock;
+
+import org.eclipse.emf.cdo.common.lock.CDOLockOwner;
+import org.eclipse.emf.cdo.spi.common.lock.InternalCDOLockState;
+
+import org.eclipse.net4j.util.CheckUtil;
+import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Caspar De Groot
+ */
+public class CDOLockStateImpl implements InternalCDOLockState
+{
+ private final Object lockedObject;
+
+ private final Set<CDOLockOwner> readLockOwners = new HashSet<CDOLockOwner>();
+
+ private CDOLockOwner writeLockOwner;
+
+ private CDOLockOwner writeOptionOwner;
+
+ public CDOLockStateImpl(Object lockedObject)
+ {
+ CheckUtil.checkArg(lockedObject, "lockedObject");
+ this.lockedObject = lockedObject;
+ }
+
+ public boolean isLocked(LockType lockType, CDOLockOwner lockOwner, boolean others)
+ {
+ switch (lockType)
+ {
+ case READ:
+ return isReadLocked(lockOwner, others);
+
+ case WRITE:
+ return isWriteLocked(lockOwner, others);
+
+ case OPTION:
+ return isOptionLocked(lockOwner, others);
+ }
+
+ return false;
+ }
+
+ private boolean isReadLocked(CDOLockOwner by, boolean others)
+ {
+ if (readLockOwners.size() == 0)
+ {
+ return false;
+ }
+
+ return readLockOwners.contains(by) ^ others;
+ }
+
+ private boolean isWriteLocked(CDOLockOwner by, boolean others)
+ {
+ if (writeLockOwner == null)
+ {
+ return false;
+ }
+
+ return writeLockOwner.equals(by) ^ others;
+ }
+
+ private boolean isOptionLocked(CDOLockOwner by, boolean others)
+ {
+ if (writeOptionOwner == null)
+ {
+ return false;
+ }
+
+ return writeOptionOwner.equals(by) ^ others;
+ }
+
+ public Set<CDOLockOwner> getReadLockOwners()
+ {
+ return Collections.unmodifiableSet(readLockOwners);
+ }
+
+ public CDOLockOwner getWriteLockOwner()
+ {
+ return writeLockOwner;
+ }
+
+ public void setWriteLockOwner(CDOLockOwner lockOwner)
+ {
+ writeLockOwner = lockOwner;
+ }
+
+ public CDOLockOwner getWriteOptionOwner()
+ {
+ return writeOptionOwner;
+ }
+
+ public void setWriteOptionOwner(CDOLockOwner lockOwner)
+ {
+ writeOptionOwner = lockOwner;
+ }
+
+ public Object getLockedObject()
+ {
+ return lockedObject;
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder("CDOLockState[lockedObject=");
+ builder.append(lockedObject);
+
+ if (readLockOwners.size() > 0)
+ {
+ builder.append(", read=");
+ boolean first = true;
+ for (CDOLockOwner lockOwner : readLockOwners)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ builder.append(", ");
+ }
+
+ builder.append(lockOwner);
+ }
+
+ builder.deleteCharAt(builder.length() - 1);
+ }
+
+ if (writeLockOwner != null)
+ {
+ builder.append(", write=");
+ builder.append(writeLockOwner);
+ }
+
+ if (writeOptionOwner != null)
+ {
+ builder.append(", option=");
+ builder.append(writeOptionOwner);
+ }
+
+ builder.append(']');
+ return builder.toString();
+ }
+
+ public void addReadLockOwner(CDOLockOwner lockOwner)
+ {
+ readLockOwners.add(lockOwner);
+ }
+
+ public boolean removeReadLockOwner(CDOLockOwner lockOwner)
+ {
+ return readLockOwners.remove(lockOwner);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataInputImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataInputImpl.java
index 6da3c33..d64799e 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataInputImpl.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataInputImpl.java
@@ -26,6 +26,10 @@ import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.common.lob.CDOLob;
import org.eclipse.emf.cdo.common.lob.CDOLobStore;
import org.eclipse.emf.cdo.common.lob.CDOLobUtil;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
+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.model.CDOClassifierRef;
import org.eclipse.emf.cdo.common.model.CDOModelUtil;
import org.eclipse.emf.cdo.common.model.CDOPackageInfo;
@@ -52,6 +56,9 @@ import org.eclipse.emf.cdo.internal.common.id.CDOIDExternalImpl;
import org.eclipse.emf.cdo.internal.common.id.CDOIDObjectLongImpl;
import org.eclipse.emf.cdo.internal.common.id.CDOIDTempObjectExternalImpl;
import org.eclipse.emf.cdo.internal.common.id.CDOIDTempObjectImpl;
+import org.eclipse.emf.cdo.internal.common.lock.CDOLockChangeInfoImpl;
+import org.eclipse.emf.cdo.internal.common.lock.CDOLockOwnerImpl;
+import org.eclipse.emf.cdo.internal.common.lock.CDOLockStateImpl;
import org.eclipse.emf.cdo.internal.common.messages.Messages;
import org.eclipse.emf.cdo.internal.common.revision.CDOIDAndBranchImpl;
import org.eclipse.emf.cdo.internal.common.revision.CDOIDAndVersionImpl;
@@ -66,6 +73,7 @@ import org.eclipse.emf.cdo.internal.common.revision.delta.CDOSetFeatureDeltaImpl
import org.eclipse.emf.cdo.internal.common.revision.delta.CDOUnsetFeatureDeltaImpl;
import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager;
import org.eclipse.emf.cdo.spi.common.id.AbstractCDOID;
+import org.eclipse.emf.cdo.spi.common.lock.InternalCDOLockState;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
@@ -255,6 +263,73 @@ public abstract class CDODataInputImpl extends ExtendedDataInput.Delegating impl
return new FailureCommitInfo(timeStamp, previousTimeStamp);
}
+ public CDOLockChangeInfo readCDOLockChangeInfo() throws IOException
+ {
+ CDOBranchPoint branchPoint = readCDOBranchPoint();
+ CDOLockOwner lockOwner = readCDOLockOwner();
+ Operation operation = readEnum(Operation.class);
+
+ int n = readInt();
+ CDOLockState[] lockStates = new CDOLockState[n];
+ for (int i = 0; i < n; i++)
+ {
+ lockStates[i] = readCDOLockState();
+ }
+
+ return new CDOLockChangeInfoImpl(branchPoint, lockOwner, lockStates, operation);
+ }
+
+ public CDOLockOwner readCDOLockOwner() throws IOException
+ {
+ boolean isUnknown = !readBoolean();
+ if (isUnknown)
+ {
+ return CDOLockOwner.UNKNOWN;
+ }
+ int session = readInt();
+ int view = readInt();
+ return new CDOLockOwnerImpl(session, view);
+ }
+
+ public CDOLockState readCDOLockState() throws IOException
+ {
+ Object target;
+ boolean sendingBranchWithID = readBoolean();
+ if (!sendingBranchWithID)
+ {
+ target = readCDOID();
+ }
+ else
+ {
+ target = readCDOIDAndBranch();
+ }
+
+ InternalCDOLockState lockState = new CDOLockStateImpl(target);
+
+ int nReadLockOwners = readInt();
+ for (int i = 0; i < nReadLockOwners; i++)
+ {
+ CDOLockOwner lockOwner = readCDOLockOwner();
+ lockState.addReadLockOwner(lockOwner);
+ }
+
+ boolean hasWriteLock = readBoolean();
+ if (hasWriteLock)
+ {
+ CDOLockOwner lockOwner = readCDOLockOwner();
+ lockState.setWriteLockOwner(lockOwner);
+ }
+
+ boolean hasWriteOption = readBoolean();
+ if (hasWriteOption)
+ {
+ CDOLockOwner lockOwner = readCDOLockOwner();
+ lockState.setWriteOptionOwner(lockOwner);
+ }
+
+ return lockState;
+ }
+
public CDOID readCDOID() throws IOException
{
byte ordinal = readByte();
@@ -514,7 +589,8 @@ public abstract class CDODataInputImpl extends ExtendedDataInput.Delegating impl
public LockType readCDOLockType() throws IOException
{
- return readBoolean() ? LockType.WRITE : LockType.READ;
+ byte b = readByte();
+ return b == 0 ? null : LockType.values()[b - 1];
}
protected StringIO getPackageURICompressor()
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataOutputImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataOutputImpl.java
index 394aad8..9ceed91 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataOutputImpl.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataOutputImpl.java
@@ -19,6 +19,9 @@ import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDProvider;
import org.eclipse.emf.cdo.common.id.CDOIDReference;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockOwner;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.model.CDOClassifierRef;
import org.eclipse.emf.cdo.common.model.CDOModelUtil;
import org.eclipse.emf.cdo.common.model.CDOPackageInfo;
@@ -63,6 +66,7 @@ import org.eclipse.emf.ecore.util.FeatureMapUtil;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Collection;
+import java.util.Set;
/**
* @author Eike Stepper
@@ -218,6 +222,82 @@ public abstract class CDODataOutputImpl extends ExtendedDataOutput.Delegating im
}
}
+ public void writeCDOLockChangeInfo(CDOLockChangeInfo lockChangeInfo) throws IOException
+ {
+ writeCDOBranchPoint(lockChangeInfo);
+ writeCDOLockOwner(lockChangeInfo.getLockOwner());
+ writeEnum(lockChangeInfo.getOperation());
+
+ CDOLockState[] lockStates = lockChangeInfo.getLockStates();
+ writeInt(lockStates.length);
+ for (CDOLockState lockState : lockStates)
+ {
+ writeCDOLockState(lockState);
+ }
+ }
+
+ public void writeCDOLockOwner(CDOLockOwner lockOwner) throws IOException
+ {
+ if (lockOwner != CDOLockOwner.UNKNOWN)
+ {
+ writeBoolean(true);
+ writeInt(lockOwner.getSessionID());
+ writeInt(lockOwner.getViewID());
+ }
+ else
+ {
+ writeBoolean(false);
+ }
+ }
+
+ public void writeCDOLockState(CDOLockState lockState) throws IOException
+ {
+ Object o = lockState.getLockedObject();
+ if (o instanceof CDOID)
+ {
+ writeBoolean(false);
+ writeCDOID((CDOID)o);
+ }
+ else if (o instanceof CDOIDAndBranch)
+ {
+ writeBoolean(true);
+ writeCDOIDAndBranch((CDOIDAndBranch)o);
+ }
+ else
+ {
+ throw new AssertionError("Unexpected type: " + o.getClass().getSimpleName());
+ }
+
+ Set<CDOLockOwner> readLockOwners = lockState.getReadLockOwners();
+ writeInt(readLockOwners.size());
+ for (CDOLockOwner readLockOwner : readLockOwners)
+ {
+ writeCDOLockOwner(readLockOwner);
+ }
+
+ CDOLockOwner writeLockOwner = lockState.getWriteLockOwner();
+ if (writeLockOwner != null)
+ {
+ writeBoolean(true);
+ writeCDOLockOwner(writeLockOwner);
+ }
+ else
+ {
+ writeBoolean(false);
+ }
+
+ CDOLockOwner writeOptionOwner = lockState.getWriteOptionOwner();
+ if (writeOptionOwner != null)
+ {
+ writeBoolean(true);
+ writeCDOLockOwner(writeOptionOwner);
+ }
+ else
+ {
+ writeBoolean(false);
+ }
+ }
+
public void writeCDOID(CDOID id) throws IOException
{
if (id == null)
@@ -438,7 +518,8 @@ public abstract class CDODataOutputImpl extends ExtendedDataOutput.Delegating im
public void writeCDOLockType(LockType lockType) throws IOException
{
- writeBoolean(lockType == LockType.WRITE ? true : false);
+ int b = lockType == null ? 0 : lockType.ordinal() + 1;
+ writeByte(b);
}
public CDOPackageRegistry getPackageRegistry()
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/lock/InternalCDOLockState.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/lock/InternalCDOLockState.java
new file mode 100644
index 0000000..dddd9f7
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/lock/InternalCDOLockState.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2004 - 2011 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.spi.common.lock;
+
+import org.eclipse.emf.cdo.common.lock.CDOLockOwner;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
+
+/**
+ * @author Caspar De Groot
+ * @since 4.1
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface InternalCDOLockState extends CDOLockState
+{
+ public void addReadLockOwner(CDOLockOwner lockOwner);
+
+ public boolean removeReadLockOwner(CDOLockOwner lockOwner);
+
+ public void setWriteLockOwner(CDOLockOwner lockOwner);
+
+ public void setWriteOptionOwner(CDOLockOwner lockOwner);
+}
diff --git a/plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/AbstractOfflineExampleServer.java b/plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/AbstractOfflineExampleServer.java
index ac775d0..c7f3f64 100644
--- a/plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/AbstractOfflineExampleServer.java
+++ b/plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/AbstractOfflineExampleServer.java
@@ -124,10 +124,10 @@ public abstract class AbstractOfflineExampleServer
{
for (;;)
{
- // System.out.println();
- // System.out.println("Enter a command:");
- // showMenu();
- // System.out.println();
+ System.out.println();
+ System.out.println("Enter a command:");
+ showMenu();
+ System.out.println();
String command = new BufferedReader(new InputStreamReader(System.in)).readLine();
if (handleCommand(command))
@@ -144,6 +144,14 @@ public abstract class AbstractOfflineExampleServer
container.deactivate();
}
+ protected void showMenu()
+ {
+ System.out.println("0 - exit");
+ System.out.println("1 - connect repository to network");
+ System.out.println("2 - disconnect repository from network");
+ System.out.println("3 - dump repository infos");
+ }
+
protected boolean handleCommand(String command)
{
if ("1".equals(command))
diff --git a/plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/OfflineExampleClient.java b/plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/OfflineExampleClient.java
index a8a4484..52d1020 100644
--- a/plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/OfflineExampleClient.java
+++ b/plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/OfflineExampleClient.java
@@ -10,6 +10,7 @@
*/
package org.eclipse.emf.cdo.examples.server.offline;
+import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.common.CDOCommonRepository;
import org.eclipse.emf.cdo.common.CDOCommonRepository.State;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
@@ -21,6 +22,7 @@ import org.eclipse.emf.cdo.net4j.CDONet4jSessionConfiguration;
import org.eclipse.emf.cdo.net4j.CDONet4jUtil;
import org.eclipse.emf.cdo.session.CDORepositoryInfo;
import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.CDOUtil;
import org.eclipse.emf.cdo.util.CommitException;
import org.eclipse.net4j.Net4jUtil;
@@ -28,7 +30,10 @@ import org.eclipse.net4j.connector.IConnector;
import org.eclipse.net4j.util.container.IManagedContainer;
import org.eclipse.net4j.util.event.IEvent;
import org.eclipse.net4j.util.event.IListener;
+import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.spi.cdo.DefaultCDOMerger;
import java.io.BufferedReader;
@@ -67,6 +72,42 @@ public class OfflineExampleClient
}
}
+ private static void lockObject(CDOTransaction tx)
+ {
+ EList<EObject> contents = tx.getOrCreateResource("/r1").getContents();
+ int size = contents.size();
+ if (size < 1)
+ {
+ System.out.println("There are no objects; can't lock anything.");
+ }
+
+ System.out.println("Locking last object");
+ CDOObject firstObject = CDOUtil.getCDOObject(contents.get(size - 1));
+ firstObject.cdoWriteLock().lock();
+ System.out.println("Locked last object");
+ }
+
+ private static void unlockObject(CDOTransaction tx)
+ {
+ EList<EObject> contents = tx.getOrCreateResource("/r1").getContents();
+ int size = contents.size();
+ if (size < 1)
+ {
+ System.out.println("There are no objects; can't lock anything.");
+ }
+
+ System.out.println("Unlocking last object");
+ CDOObject firstObject = CDOUtil.getCDOObject(contents.get(size - 1));
+ firstObject.cdoWriteLock().unlock();
+ System.out.println("Unlocked last object");
+ }
+
+ private static void createBranch(CDOTransaction tx)
+ {
+ CDOBranch subBranch = tx.getBranch().createBranch("sub.1");
+ tx.setBranch(subBranch);
+ }
+
private static boolean isAutoMerge(String[] args)
{
for (int i = 0; i < args.length; i++)
@@ -150,12 +191,44 @@ public class OfflineExampleClient
System.out.println("Connected to " + repositoryInfo.getName());
tx = session.openTransaction();
+ tx.enableDurableLocking(true);
createSessionListener(session, autoMerging);
for (;;)
{
- new BufferedReader(new InputStreamReader(System.in)).readLine();
- addObject(tx);
+ System.out.println();
+ System.out.println("Enter a command:");
+ System.out.println("0 - exit");
+ System.out.println("1 - add an object to the repository");
+ System.out.println("2 - lock the last object in the repository");
+ System.out.println("3 - unlock the last object in the repository");
+ System.out.println("4 - create a branch");
+
+ String command = new BufferedReader(new InputStreamReader(System.in)).readLine();
+ if ("0".equals(command))
+ {
+ break;
+ }
+
+ if ("1".equals(command))
+ {
+ addObject(tx);
+ }
+ else if ("2".equals(command))
+ {
+ lockObject(tx);
+ }
+ else if ("3".equals(command))
+ {
+ unlockObject(tx);
+ }
+ else if ("4".equals(command))
+ {
+ createBranch(tx);
+ }
}
+
+ session.close();
+ LifecycleUtil.deactivate(container);
}
}
diff --git a/plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/OfflineExampleMaster.java b/plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/OfflineExampleMaster.java
index 20dcd4b..6147a90 100644
--- a/plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/OfflineExampleMaster.java
+++ b/plugins/org.eclipse.emf.cdo.examples/src/org/eclipse/emf/cdo/examples/server/offline/OfflineExampleMaster.java
@@ -40,14 +40,6 @@ public class OfflineExampleMaster extends AbstractOfflineExampleServer
return CDOServerUtil.createRepository(name, store, props);
}
- protected void showMenu()
- {
- System.out.println("0 - exit");
- System.out.println("1 - connect repository to network");
- System.out.println("2 - disconnect repository from network");
- System.out.println("3 - dump repository infos");
- }
-
public static void main(String[] args) throws Exception
{
System.out.println("Master repository starting...");
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java
index aeddc48..9ba6ae8 100644
--- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java
@@ -24,6 +24,7 @@ import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDProvider;
import org.eclipse.emf.cdo.common.lob.CDOLob;
import org.eclipse.emf.cdo.common.lob.CDOLobInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
@@ -66,6 +67,7 @@ import org.eclipse.emf.spi.cdo.InternalCDOXATransaction.InternalCDOXACommitConte
import java.io.IOException;
import java.util.Collection;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -218,15 +220,66 @@ public class CDOClientProtocol extends SignalProtocol<CDOSession> implements CDO
}
}
- public LockObjectsResult lockObjects(List<InternalCDORevision> viewedRevisions, int viewID, CDOBranch viewedBranch,
+ @Deprecated
+ public LockObjectsResult lockObjects(List<InternalCDORevision> revisions, int viewID, CDOBranch viewedBranch,
LockType lockType, long timeout) throws InterruptedException
{
+ List<CDORevisionKey> revisionKeys = new LinkedList<CDORevisionKey>();
+ for (InternalCDORevision rev : revisions)
+ {
+ revisionKeys.add(rev);
+ }
+
+ return lockObjects2(revisionKeys, viewID, viewedBranch, lockType, timeout);
+ }
+
+ public LockObjectsResult lockObjects2(List<CDORevisionKey> revisionKeys, int viewID, CDOBranch viewedBranch,
+ LockType lockType, long timeout) throws InterruptedException
+ {
+ InterruptedException interruptedException = null;
+ RuntimeException runtimeException = null;
+
+ try
+ {
+ return new LockObjectsRequest(this, revisionKeys, viewID, viewedBranch, lockType, timeout).send();
+ }
+ catch (RemoteException ex)
+ {
+ if (ex.getCause() instanceof RuntimeException)
+ {
+ runtimeException = (RuntimeException)ex.getCause();
+ }
+ else if (ex.getCause() instanceof InterruptedException)
+ {
+ interruptedException = (InterruptedException)ex.getCause();
+ }
+ else
+ {
+ runtimeException = WrappedException.wrap(ex);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw WrappedException.wrap(ex);
+ }
+
+ if (interruptedException != null)
+ {
+ throw interruptedException;
+ }
+
+ throw runtimeException;
+ }
+
+ public LockObjectsResult delegateLockObjects(String lockAreaID, List<CDORevisionKey> revisionKeys,
+ CDOBranch viewedBranch, LockType lockType, long timeout) throws InterruptedException
+ {
InterruptedException interruptedException = null;
RuntimeException runtimeException = null;
try
{
- return new LockObjectsRequest(this, viewedRevisions, viewID, viewedBranch, lockType, timeout).send();
+ return new LockDelegationRequest(this, lockAreaID, revisionKeys, viewedBranch, lockType, timeout).send();
}
catch (RemoteException ex)
{
@@ -256,9 +309,19 @@ public class CDOClientProtocol extends SignalProtocol<CDOSession> implements CDO
throw runtimeException;
}
- public void unlockObjects(CDOView view, Collection<? extends CDOObject> objects, LockType lockType)
+ public void unlockObjects(CDOView view, Collection<CDOID> objectIDs, LockType lockType)
{
- send(new UnlockObjectsRequest(this, view, objects, lockType));
+ send(new UnlockObjectsRequest(this, view.getViewID(), objectIDs, lockType));
+ }
+
+ public UnlockObjectsResult unlockObjects2(CDOView view, Collection<CDOID> objectIDs, LockType lockType)
+ {
+ return send(new UnlockObjectsRequest(this, view.getViewID(), objectIDs, lockType));
+ }
+
+ public UnlockObjectsResult delegateUnlockObjects(String lockAreaID, Collection<CDOID> objectIDs, LockType lockType)
+ {
+ return send(new UnlockDelegationRequest(this, lockAreaID, objectIDs, lockType));
}
public boolean isObjectLocked(CDOView view, CDOObject object, LockType lockType, boolean byOthers)
@@ -398,6 +461,9 @@ public class CDOClientProtocol extends SignalProtocol<CDOSession> implements CDO
case CDOProtocolConstants.SIGNAL_REMOTE_MESSAGE_NOTIFICATION:
return new RemoteMessageNotificationIndication(this);
+ case CDOProtocolConstants.SIGNAL_LOCK_NOTIFICATION:
+ return new LockNotificationIndication(this);
+
default:
return super.createSignalReactor(signalID);
}
@@ -447,4 +513,14 @@ public class CDOClientProtocol extends SignalProtocol<CDOSession> implements CDO
REVISION_LOADING.stop(request);
}
}
+
+ public CDOLockState[] getLockStates(int viewID, Collection<CDOID> ids)
+ {
+ return send(new LockStateRequest(this, viewID, ids));
+ }
+
+ public void enableLockNotifications(int viewID, boolean on)
+ {
+ send(new EnableLockNotificationRequest(this, viewID, on));
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CommitTransactionRequest.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CommitTransactionRequest.java
index 0076065..5da87ff 100644
--- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CommitTransactionRequest.java
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CommitTransactionRequest.java
@@ -26,6 +26,7 @@ import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.common.lob.CDOBlob;
import org.eclipse.emf.cdo.common.lob.CDOClob;
import org.eclipse.emf.cdo.common.lob.CDOLob;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
import org.eclipse.emf.cdo.common.protocol.CDODataInput;
import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
@@ -229,6 +230,7 @@ public class CommitTransactionRequest extends CDOClientRequestWithMonitoring<Com
result = confirmingResult(in);
confirmingMappingNewObjects(in, result);
+ confirmingNewLockStates(in, result);
return result;
}
@@ -290,4 +292,17 @@ public class CommitTransactionRequest extends CDOClientRequestWithMonitoring<Com
}
}
}
+
+ protected void confirmingNewLockStates(CDODataInput in, CommitTransactionResult result) throws IOException
+ {
+ int n = in.readInt();
+ CDOLockState[] newLockStates = new CDOLockState[n];
+
+ for (int i = 0; i < n; i++)
+ {
+ newLockStates[i] = in.readCDOLockState();
+ }
+
+ result.setNewLockStates(newLockStates);
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/EnableLockNotificationRequest.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/EnableLockNotificationRequest.java
new file mode 100644
index 0000000..47530f5
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/EnableLockNotificationRequest.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2004 - 2011 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.internal.net4j.protocol;
+
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
+
+import java.io.IOException;
+
+/**
+ * @author Caspar De Groot
+ */
+public class EnableLockNotificationRequest extends CDOClientRequest<Boolean>
+{
+ private int viewID;
+
+ private boolean on;
+
+ public EnableLockNotificationRequest(CDOClientProtocol protocol, int viewID, boolean on)
+ {
+ super(protocol, CDOProtocolConstants.SIGNAL_ENABLE_LOCK_NOTIFICATION);
+ this.viewID = viewID;
+ this.on = on;
+ }
+
+ @Override
+ protected void requesting(CDODataOutput out) throws IOException
+ {
+ out.writeInt(viewID);
+ out.writeBoolean(on);
+ }
+
+ @Override
+ protected Boolean confirming(CDODataInput in) throws IOException
+ {
+ return in.readBoolean();
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockDelegationRequest.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockDelegationRequest.java
new file mode 100644
index 0000000..08be5b6
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockDelegationRequest.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2004 - 2011 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.internal.net4j.protocol;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
+import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
+
+import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author Caspar De Groot
+ */
+public class LockDelegationRequest extends LockObjectsRequest
+{
+ private String lockAreaID;
+
+ public LockDelegationRequest(CDOClientProtocol protocol, String lockAreaID, List<CDORevisionKey> revisionKeys,
+ CDOBranch viewedBranch, LockType lockType, long timeout)
+ {
+ super(protocol, CDOProtocolConstants.SIGNAL_LOCK_DELEGATION, revisionKeys, 0, viewedBranch, lockType, timeout);
+ this.lockAreaID = lockAreaID;
+ }
+
+ @Override
+ protected void requesting(CDODataOutput out) throws IOException
+ {
+ out.writeString(lockAreaID);
+ super.requesting(out);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockNotificationIndication.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockNotificationIndication.java
new file mode 100644
index 0000000..2d4175c
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockNotificationIndication.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2004 - 2011 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.internal.net4j.protocol;
+
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
+
+import org.eclipse.emf.spi.cdo.InternalCDOSession;
+
+import java.io.IOException;
+
+/**
+ * @author Caspar De Groot
+ */
+public class LockNotificationIndication extends CDOClientIndication
+{
+ public LockNotificationIndication(CDOClientProtocol protocol)
+ {
+ super(protocol, CDOProtocolConstants.SIGNAL_LOCK_NOTIFICATION);
+ }
+
+ @Override
+ protected void indicating(CDODataInput in) throws IOException
+ {
+ CDOLockChangeInfo lockChangeInfo = in.readCDOLockChangeInfo();
+ InternalCDOSession session = getSession();
+ session.handleLockNotification(lockChangeInfo);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockObjectsRequest.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockObjectsRequest.java
index ffe3ca7..2d8e932 100644
--- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockObjectsRequest.java
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockObjectsRequest.java
@@ -12,13 +12,11 @@
package org.eclipse.emf.cdo.internal.net4j.protocol;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.protocol.CDODataInput;
import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.net4j.util.concurrent.IRWLockManager;
import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
@@ -39,22 +37,28 @@ public class LockObjectsRequest extends CDOClientRequest<LockObjectsResult>
private long timeout;
- private List<InternalCDORevision> viewedRevisions;
+ private List<CDORevisionKey> revisionKeys;
/**
* The branch being viewed
*/
private CDOBranch viewedBranch;
- public LockObjectsRequest(CDOClientProtocol protocol, List<InternalCDORevision> viewedRevisions, int viewID,
+ public LockObjectsRequest(CDOClientProtocol protocol, List<CDORevisionKey> revisionKeys, int viewID,
CDOBranch viewedBranch, LockType lockType, long timeout)
{
- super(protocol, CDOProtocolConstants.SIGNAL_LOCK_OBJECTS);
+ this(protocol, CDOProtocolConstants.SIGNAL_LOCK_OBJECTS, revisionKeys, viewID, viewedBranch, lockType, timeout);
+ }
+
+ protected LockObjectsRequest(CDOClientProtocol protocol, short signalID, List<CDORevisionKey> revisionKeys,
+ int viewID, CDOBranch viewedBranch, LockType lockType, long timeout)
+ {
+ super(protocol, signalID);
this.viewID = viewID;
this.lockType = lockType;
this.timeout = timeout;
- this.viewedRevisions = viewedRevisions;
+ this.revisionKeys = revisionKeys;
this.viewedBranch = viewedBranch;
}
@@ -66,10 +70,10 @@ public class LockObjectsRequest extends CDOClientRequest<LockObjectsResult>
out.writeLong(timeout);
out.writeCDOBranch(viewedBranch);
- out.writeInt(viewedRevisions.size());
- for (CDORevision revision : viewedRevisions)
+ out.writeInt(revisionKeys.size());
+ for (CDORevisionKey revKey : revisionKeys)
{
- out.writeCDORevisionKey(revision);
+ out.writeCDORevisionKey(revKey);
}
}
@@ -77,23 +81,9 @@ public class LockObjectsRequest extends CDOClientRequest<LockObjectsResult>
protected LockObjectsResult confirming(CDODataInput in) throws IOException
{
boolean succesful = in.readBoolean();
- if (succesful)
- {
- boolean clientMustWait = in.readBoolean();
- long requiredTimestamp = CDOBranchPoint.UNSPECIFIED_DATE;
- if (clientMustWait)
- {
- requiredTimestamp = in.readLong();
- }
-
- return new LockObjectsResult(true, false, clientMustWait, requiredTimestamp, null);
- }
-
- boolean timedOut = in.readBoolean();
- if (timedOut)
- {
- return new LockObjectsResult(false, true, false, 0, null);
- }
+ boolean timeout = in.readBoolean();
+ boolean waitForUpdate = in.readBoolean();
+ long requiredTimestamp = in.readLong();
int nStaleRevisions = in.readInt();
CDORevisionKey[] staleRevisions = new CDORevisionKey[nStaleRevisions];
@@ -102,6 +92,13 @@ public class LockObjectsRequest extends CDOClientRequest<LockObjectsResult>
staleRevisions[i] = in.readCDORevisionKey();
}
- return new LockObjectsResult(false, false, false, 0, staleRevisions);
+ int n = in.readInt();
+ CDOLockState[] newLockStates = new CDOLockState[n];
+ for (int i = 0; i < n; i++)
+ {
+ newLockStates[i] = in.readCDOLockState();
+ }
+
+ return new LockObjectsResult(succesful, timeout, waitForUpdate, requiredTimestamp, staleRevisions, newLockStates);
}
}
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockStateRequest.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockStateRequest.java
new file mode 100644
index 0000000..30e443d
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockStateRequest.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2004 - 2011 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.internal.net4j.protocol;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
+
+import java.io.IOException;
+import java.util.Collection;
+
+/**
+ * @author Caspar De Groot
+ */
+public class LockStateRequest extends CDOClientRequest<CDOLockState[]>
+{
+ private int viewID;
+
+ private Collection<CDOID> ids;
+
+ public LockStateRequest(CDOClientProtocol protocol, int viewID, Collection<CDOID> ids)
+ {
+ super(protocol, CDOProtocolConstants.SIGNAL_LOCK_STATE);
+ this.viewID = viewID;
+ this.ids = ids;
+ }
+
+ @Override
+ protected void requesting(CDODataOutput out) throws IOException
+ {
+ out.writeInt(viewID);
+ out.writeInt(ids.size());
+ for (CDOID id : ids)
+ {
+ out.writeCDOID(id);
+ }
+ }
+
+ @Override
+ protected CDOLockState[] confirming(CDODataInput in) throws IOException
+ {
+ int n = in.readInt();
+ CDOLockState[] lockStates = new CDOLockState[n];
+ for (int i = 0; i < n; i++)
+ {
+ lockStates[i] = in.readCDOLockState();
+ }
+
+ return lockStates;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/UnlockDelegationRequest.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/UnlockDelegationRequest.java
new file mode 100644
index 0000000..0249172
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/UnlockDelegationRequest.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2004 - 2011 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.internal.net4j.protocol;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
+
+import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+
+import java.io.IOException;
+import java.util.Collection;
+
+/**
+ * @author Caspar De Groot
+ */
+public class UnlockDelegationRequest extends UnlockObjectsRequest
+{
+ private String lockAreaID;
+
+ public UnlockDelegationRequest(CDOClientProtocol protocol, String lockAreaID, Collection<CDOID> objectIDs,
+ LockType lockType)
+ {
+ super(protocol, CDOProtocolConstants.SIGNAL_UNLOCK_DELEGATION, 0, objectIDs, lockType);
+ this.lockAreaID = lockAreaID;
+ }
+
+ @Override
+ protected void requesting(CDODataOutput out) throws IOException
+ {
+ out.writeString(lockAreaID);
+ super.requesting(out);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/UnlockObjectsRequest.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/UnlockObjectsRequest.java
index be03dfd..0eefb36 100644
--- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/UnlockObjectsRequest.java
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/UnlockObjectsRequest.java
@@ -10,52 +10,58 @@
**************************************************************************/
package org.eclipse.emf.cdo.internal.net4j.protocol;
-import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.protocol.CDODataInput;
import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
import org.eclipse.emf.cdo.internal.net4j.bundle.OM;
-import org.eclipse.emf.cdo.view.CDOView;
import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
import org.eclipse.net4j.util.om.trace.ContextTracer;
+import org.eclipse.emf.spi.cdo.CDOSessionProtocol.UnlockObjectsResult;
+
import java.io.IOException;
import java.util.Collection;
/**
* @author Simon McDuff
*/
-public class UnlockObjectsRequest extends CDOClientRequest<Boolean>
+public class UnlockObjectsRequest extends CDOClientRequest<UnlockObjectsResult>
{
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_PROTOCOL, UnlockObjectsRequest.class);
- private CDOView view;
+ private int viewID;
- private Collection<? extends CDOObject> objects;
+ private Collection<CDOID> objectIDs;
private LockType lockType;
- public UnlockObjectsRequest(CDOClientProtocol protocol, CDOView view, Collection<? extends CDOObject> objects,
+ public UnlockObjectsRequest(CDOClientProtocol protocol, int viewID, Collection<CDOID> objects, LockType lockType)
+ {
+ this(protocol, CDOProtocolConstants.SIGNAL_UNLOCK_OBJECTS, viewID, objects, lockType);
+ }
+
+ protected UnlockObjectsRequest(CDOClientProtocol protocol, short signalID, int viewID, Collection<CDOID> objectIDs,
LockType lockType)
{
- super(protocol, CDOProtocolConstants.SIGNAL_UNLOCK_OBJECTS);
- this.view = view;
- this.objects = objects;
+ super(protocol, signalID);
+ this.viewID = viewID;
+ this.objectIDs = objectIDs;
this.lockType = lockType;
}
@Override
protected void requesting(CDODataOutput out) throws IOException
{
- out.writeInt(view.getViewID());
+ out.writeInt(viewID);
out.writeCDOLockType(lockType);
- if (objects == null)
+ if (objectIDs == null)
{
if (TRACER.isEnabled())
{
- TRACER.format("Unlocking all objects for view {0}", view.getViewID()); //$NON-NLS-1$
+ TRACER.format("Unlocking all objects for view {0}", viewID); //$NON-NLS-1$
}
out.writeInt(CDOProtocolConstants.RELEASE_ALL_LOCKS);
@@ -65,13 +71,12 @@ public class UnlockObjectsRequest extends CDOClientRequest<Boolean>
if (TRACER.isEnabled())
{
TRACER.format("Unlocking of type {0} requested for view {1}", lockType == LockType.READ ? "read" //$NON-NLS-1$ //$NON-NLS-2$
- : "write", view.getViewID()); //$NON-NLS-1$
+ : "write", viewID); //$NON-NLS-1$
}
- out.writeInt(objects.size());
- for (CDOObject object : objects)
+ out.writeInt(objectIDs.size());
+ for (CDOID id : objectIDs)
{
- CDOID id = object.cdoID();
if (TRACER.isEnabled())
{
TRACER.format("Unlocking requested for object {0}", id); //$NON-NLS-1$
@@ -83,8 +88,14 @@ public class UnlockObjectsRequest extends CDOClientRequest<Boolean>
}
@Override
- protected Boolean confirming(CDODataInput in) throws IOException
+ protected UnlockObjectsResult confirming(CDODataInput in) throws IOException
{
- return in.readBoolean();
+ int n = in.readInt();
+ CDOLockState[] newLockStates = new CDOLockState[n];
+ for (int i = 0; i < n; i++)
+ {
+ newLockStates[i] = in.readCDOLockState();
+ }
+ return new UnlockObjectsResult(newLockStates);
}
}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java
index 8059979..dfad801 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java
@@ -37,7 +37,7 @@ import org.eclipse.emf.cdo.server.IQueryHandler;
import org.eclipse.emf.cdo.server.IRepository;
import org.eclipse.emf.cdo.server.ISession;
import org.eclipse.emf.cdo.server.IStoreAccessor;
-import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking;
+import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking2;
import org.eclipse.emf.cdo.server.ITransaction;
import org.eclipse.emf.cdo.server.db.CDODBUtil;
import org.eclipse.emf.cdo.server.db.IDBStore;
@@ -108,7 +108,7 @@ import java.util.TimerTask;
/**
* @author Eike Stepper
*/
-public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, DurableLocking
+public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, DurableLocking2
{
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, DBStoreAccessor.class);
@@ -1291,8 +1291,14 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor,
public LockArea createLockArea(String userID, CDOBranchPoint branchPoint, boolean readOnly,
Map<CDOID, LockGrade> locks)
{
+ return createLockArea(null, userID, branchPoint, readOnly, locks);
+ }
+
+ public LockArea createLockArea(String durableLockingID, String userID, CDOBranchPoint branchPoint, boolean readOnly,
+ Map<CDOID, LockGrade> locks)
+ {
DurableLockingManager manager = getStore().getDurableLockingManager();
- return manager.createLockArea(this, userID, branchPoint, readOnly, locks);
+ return manager.createLockArea(this, durableLockingID, userID, branchPoint, readOnly, locks);
}
public LockArea getLockArea(String durableLockingID) throws LockAreaNotFoundException
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java
index 594ff99..789e425 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java
@@ -14,6 +14,7 @@ import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea;
import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea.Handler;
+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockAreaAlreadyExistsException;
import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockAreaNotFoundException;
import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade;
import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
@@ -102,12 +103,28 @@ public class DurableLockingManager extends Lifecycle
this.store = store;
}
- public synchronized LockArea createLockArea(DBStoreAccessor accessor, String userID, CDOBranchPoint branchPoint,
- boolean readOnly, Map<CDOID, LockGrade> locks)
+ public synchronized LockArea createLockArea(DBStoreAccessor accessor, String durableLockingID, String userID,
+ CDOBranchPoint branchPoint, boolean readOnly, Map<CDOID, LockGrade> locks)
{
try
{
- String durableLockingID = getNextDurableLockingID(accessor);
+ if (durableLockingID == null)
+ {
+ durableLockingID = getNextDurableLockingID(accessor);
+ }
+ else
+ {
+ // If the caller is specifying the ID, make sure there is no area with this ID yet
+ //
+ try
+ {
+ getLockArea(accessor, durableLockingID);
+ throw new LockAreaAlreadyExistsException(durableLockingID);
+ }
+ catch (LockAreaNotFoundException good)
+ {
+ }
+ }
IPreparedStatementCache statementCache = accessor.getStatementCache();
PreparedStatement stmt = null;
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java
index 3f96f29..a0fc0cb 100644
--- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java
@@ -16,6 +16,7 @@ package org.eclipse.emf.cdo.server.internal.net4j.protocol;
import org.eclipse.emf.cdo.common.CDOCommonRepository;
import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
import org.eclipse.emf.cdo.server.IRepositoryProvider;
import org.eclipse.emf.cdo.server.internal.net4j.bundle.OM;
@@ -154,6 +155,18 @@ public class CDOServerProtocol extends SignalProtocol<InternalSession> implement
}
}
+ public void sendLockNotification(CDOLockChangeInfo lockChangeInfo) throws Exception
+ {
+ if (LifecycleUtil.isActive(getChannel()))
+ {
+ new LockNotificationRequest(this, lockChangeInfo).sendAsync();
+ }
+ else
+ {
+ handleInactiveSession();
+ }
+ }
+
protected void handleInactiveSession()
{
OM.LOG.warn("Session channel is inactive: " + this); //$NON-NLS-1$
@@ -251,6 +264,12 @@ public class CDOServerProtocol extends SignalProtocol<InternalSession> implement
case CDOProtocolConstants.SIGNAL_UNLOCK_OBJECTS:
return new UnlockObjectsIndication(this);
+ case CDOProtocolConstants.SIGNAL_LOCK_DELEGATION:
+ return new LockDelegationIndication(this);
+
+ case CDOProtocolConstants.SIGNAL_UNLOCK_DELEGATION:
+ return new UnlockDelegationIndication(this);
+
case CDOProtocolConstants.SIGNAL_OBJECT_LOCKED:
return new ObjectLockedIndication(this);
@@ -287,6 +306,12 @@ public class CDOServerProtocol extends SignalProtocol<InternalSession> implement
case CDOProtocolConstants.SIGNAL_HANDLE_REVISIONS:
return new HandleRevisionsIndication(this);
+ case CDOProtocolConstants.SIGNAL_LOCK_STATE:
+ return new LockStateIndication(this);
+
+ case CDOProtocolConstants.SIGNAL_ENABLE_LOCK_NOTIFICATION:
+ return new EnableLockNotificationIndication(this);
+
default:
return super.createSignalReactor(signalID);
}
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CommitTransactionIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CommitTransactionIndication.java
index 7aa169a..959e665 100644
--- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CommitTransactionIndication.java
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CommitTransactionIndication.java
@@ -15,10 +15,13 @@ package org.eclipse.emf.cdo.server.internal.net4j.protocol;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDReference;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
+import org.eclipse.emf.cdo.common.lock.CDOLockUtil;
import org.eclipse.emf.cdo.common.model.EMFUtil;
import org.eclipse.emf.cdo.common.protocol.CDODataInput;
import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
+import org.eclipse.emf.cdo.server.IView;
import org.eclipse.emf.cdo.server.internal.net4j.bundle.OM;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
@@ -29,6 +32,7 @@ import org.eclipse.emf.cdo.spi.server.InternalTransaction;
import org.eclipse.emf.cdo.spi.server.InternalView;
import org.eclipse.net4j.util.WrappedException;
+import org.eclipse.net4j.util.concurrent.RWOLockManager.LockState;
import org.eclipse.net4j.util.om.monitor.OMMonitor;
import org.eclipse.net4j.util.om.monitor.ProgressDistributor;
import org.eclipse.net4j.util.om.trace.ContextTracer;
@@ -256,6 +260,7 @@ public class CommitTransactionIndication extends CDOServerIndicationWithMonitori
{
respondingResult(out);
respondingMappingNewObjects(out);
+ respondingNewLockStates(out);
}
}
finally
@@ -312,6 +317,24 @@ public class CommitTransactionIndication extends CDOServerIndicationWithMonitori
out.writeCDOID(CDOID.NULL);
}
+ protected void respondingNewLockStates(CDODataOutput out) throws Exception
+ {
+ List<LockState<Object, IView>> newLockStates = commitContext.getPostCommmitLockStates();
+ if (newLockStates != null)
+ {
+ out.writeInt(newLockStates.size());
+ for (LockState<Object, IView> lockState : newLockStates)
+ {
+ CDOLockState cdoLockState = CDOLockUtil.createLockState(lockState);
+ out.writeCDOLockState(cdoLockState);
+ }
+ }
+ else
+ {
+ out.writeInt(0);
+ }
+ }
+
protected InternalTransaction getTransaction(int viewID)
{
InternalView view = getSession().getView(viewID);
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/EnableLockNotificationIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/EnableLockNotificationIndication.java
new file mode 100644
index 0000000..34ca52a
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/EnableLockNotificationIndication.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2004 - 2011 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.server.internal.net4j.protocol;
+
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
+import org.eclipse.emf.cdo.spi.server.InternalView;
+
+import java.io.IOException;
+
+/**
+ * @author Caspar De Groot
+ */
+public class EnableLockNotificationIndication extends CDOServerIndication
+{
+ public EnableLockNotificationIndication(CDOServerProtocol protocol)
+ {
+ super(protocol, CDOProtocolConstants.SIGNAL_ENABLE_LOCK_NOTIFICATION);
+ }
+
+ @Override
+ protected void indicating(CDODataInput in) throws IOException
+ {
+ int viewID = in.readInt();
+ boolean enable = in.readBoolean();
+
+ InternalView view = getSession().getView(viewID);
+ view.setLockNotificationEnabled(enable);
+ }
+
+ @Override
+ protected void responding(CDODataOutput out) throws IOException
+ {
+ out.writeBoolean(true);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockDelegationIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockDelegationIndication.java
new file mode 100644
index 0000000..eaa67fd
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockDelegationIndication.java
@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2004 - 2011 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.server.internal.net4j.protocol;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea;
+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockAreaNotFoundException;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
+import org.eclipse.emf.cdo.server.IView;
+import org.eclipse.emf.cdo.spi.server.InternalLockManager;
+import org.eclipse.emf.cdo.spi.server.InternalSession;
+import org.eclipse.emf.cdo.spi.server.InternalView;
+
+import org.eclipse.net4j.util.CheckUtil;
+
+import java.io.IOException;
+
+/**
+ * @author Caspar De Groot
+ */
+public class LockDelegationIndication extends LockObjectsIndication
+{
+ private InternalView view;
+
+ private String lockAreaID;
+
+ public LockDelegationIndication(CDOServerProtocol protocol)
+ {
+ super(protocol, CDOProtocolConstants.SIGNAL_LOCK_DELEGATION);
+ }
+
+ @Override
+ protected void indicating(CDODataInput in) throws IOException
+ {
+ lockAreaID = in.readString();
+ super.indicating(in);
+ }
+
+ @Override
+ protected void responding(CDODataOutput out) throws IOException
+ {
+ try
+ {
+ super.responding(out);
+ }
+ finally
+ {
+ view.close();
+ }
+ }
+
+ @Override
+ protected IView getView(int viewID, CDOBranch viewedBranch)
+ {
+ // The view needs a lockArea...
+ InternalLockManager lockManager = getRepository().getLockManager();
+ InternalSession session = getSession();
+ LockArea lockArea;
+
+ try
+ {
+ lockArea = lockManager.getLockArea(lockAreaID);
+
+ // If we get here, the lockArea already exists.
+ view = (InternalView)lockManager.openView(session, InternalSession.TEMP_VIEW_ID, true, lockAreaID);
+ }
+ catch (LockAreaNotFoundException e)
+ {
+ // If we get here, the lockArea does not yet exist on the master, so we open
+ // a view without a lockArea first, then create a lockArea with the given ID,
+ // and associate it with the view.
+ view = session.openView(InternalSession.TEMP_VIEW_ID, viewedBranch.getHead());
+ lockArea = lockManager.createLockArea(view, lockAreaID);
+ view.setDurableLockingID(lockAreaID);
+ }
+
+ // The viewID received as an argument, is the ID of the client's view, which
+ // does not exist on the master. So we ignore this argument and open a new
+ // view instead.
+ CheckUtil.checkState(lockAreaID.equals(lockArea.getDurableLockingID()), "lockAreaID has incorrect value");
+
+ return view;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockNotificationRequest.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockNotificationRequest.java
new file mode 100644
index 0000000..17314e9
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockNotificationRequest.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2004 - 2011 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.server.internal.net4j.protocol;
+
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
+
+import java.io.IOException;
+
+/**
+ * @author Caspar De Groot
+ */
+public class LockNotificationRequest extends CDOServerRequest
+{
+ private CDOLockChangeInfo lockChangeInfo;
+
+ public LockNotificationRequest(CDOServerProtocol serverProtocol, CDOLockChangeInfo lockChangeInfo)
+ {
+ super(serverProtocol, CDOProtocolConstants.SIGNAL_LOCK_NOTIFICATION);
+ this.lockChangeInfo = lockChangeInfo;
+ }
+
+ @Override
+ protected void requesting(CDODataOutput out) throws IOException
+ {
+ out.writeCDOLockChangeInfo(lockChangeInfo);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockObjectsIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockObjectsIndication.java
index 236c744..b61cc1c 100644
--- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockObjectsIndication.java
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockObjectsIndication.java
@@ -13,24 +13,20 @@
package org.eclipse.emf.cdo.server.internal.net4j.protocol;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.protocol.CDODataInput;
import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
import org.eclipse.emf.cdo.server.IView;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-import org.eclipse.emf.cdo.spi.server.InternalLockManager;
-import org.eclipse.emf.cdo.spi.server.InternalSession;
+import org.eclipse.emf.cdo.spi.server.InternalRepository;
+import org.eclipse.emf.cdo.spi.server.InternalView;
-import org.eclipse.net4j.util.WrappedException;
import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
-import org.eclipse.net4j.util.concurrent.TimeoutRuntimeException;
+
+import org.eclipse.emf.spi.cdo.CDOSessionProtocol.LockObjectsResult;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -39,138 +35,63 @@ import java.util.List;
*/
public class LockObjectsIndication extends CDOServerWriteIndication
{
- private List<CDORevisionKey> staleRevisions = new LinkedList<CDORevisionKey>();
-
- private boolean timedOut;
-
- private boolean passiveUpdatesEnabled;
-
- private long requiredTimestamp;
-
- private boolean staleNoUpdate;
+ private LockObjectsResult result;
public LockObjectsIndication(CDOServerProtocol protocol)
{
super(protocol, CDOProtocolConstants.SIGNAL_LOCK_OBJECTS);
}
+ protected LockObjectsIndication(CDOServerProtocol protocol, short signalID)
+ {
+ super(protocol, signalID);
+ }
+
@Override
protected void indicating(CDODataInput in) throws IOException
{
- InternalSession session = getSession();
- passiveUpdatesEnabled = session.isPassiveUpdateEnabled();
-
int viewID = in.readInt();
LockType lockType = in.readCDOLockType();
long timeout = in.readLong();
CDOBranch viewedBranch = in.readCDOBranch();
int nRevisions = in.readInt();
- CDORevisionKey[] revKeys = new CDORevisionKey[nRevisions];
+ List<CDORevisionKey> revisionKeys = new LinkedList<CDORevisionKey>();
for (int i = 0; i < nRevisions; i++)
{
- revKeys[i] = in.readCDORevisionKey();
+ revisionKeys.add(in.readCDORevisionKey());
}
- List<Object> objectsToBeLocked = new ArrayList<Object>();
- boolean isSupportingBranches = getRepository().isSupportingBranches();
- for (CDORevisionKey revKey : revKeys)
- {
- CDOID id = revKey.getID();
- if (isSupportingBranches)
- {
- objectsToBeLocked.add(CDOIDUtil.createIDAndBranch(id, viewedBranch));
- }
- else
- {
- objectsToBeLocked.add(id);
- }
- }
-
- IView view = session.getView(viewID);
- InternalLockManager lockManager = getRepository().getLockManager();
-
- try
- {
- lockManager.lock(true, lockType, view, objectsToBeLocked, timeout);
- }
- catch (TimeoutRuntimeException ex)
- {
- timedOut = true;
- return;
- }
- catch (InterruptedException ex)
- {
- throw WrappedException.wrap(ex);
- }
-
- try
- {
- for (CDORevisionKey revKey : revKeys)
- {
- checkStale(viewedBranch, revKey);
- }
- }
- catch (IllegalArgumentException ex)
- {
- lockManager.unlock(true, lockType, view, objectsToBeLocked);
- throw ex;
- }
-
- // If some of the clients' revisions are stale and it has passiveUpdates disabled,
- // then the locks are useless so we release them and report the stale revisions (later)
- staleNoUpdate = staleRevisions.size() > 0 && !passiveUpdatesEnabled;
- if (staleNoUpdate)
- {
- lockManager.unlock(true, lockType, view, objectsToBeLocked);
- }
+ InternalRepository repository = getRepository();
+ IView view = getView(viewID, viewedBranch);
+ result = repository.lock((InternalView)view, lockType, revisionKeys, viewedBranch, timeout);
}
- @Override
- protected void responding(CDODataOutput out) throws IOException
+ protected IView getView(int viewID, CDOBranch viewedBranch)
{
- boolean lockSuccesful = !timedOut && !staleNoUpdate;
- out.writeBoolean(lockSuccesful);
-
- if (lockSuccesful)
- {
- boolean clientMustWait = staleRevisions.size() > 0;
- out.writeBoolean(clientMustWait);
- if (clientMustWait)
- {
- out.writeLong(requiredTimestamp);
- }
- }
- else
- {
- out.writeBoolean(timedOut);
- if (!timedOut)
- {
- out.writeInt(staleRevisions.size());
- for (CDORevisionKey staleRevision : staleRevisions)
- {
- out.writeCDORevisionKey(staleRevision);
- }
- }
- }
+ return getSession().getView(viewID);
}
- private void checkStale(CDOBranch viewedBranch, CDORevisionKey revKey)
+ @Override
+ protected void responding(CDODataOutput out) throws IOException
{
- CDOID id = revKey.getID();
- InternalCDORevision rev = getRepository().getRevisionManager().getRevision(id, viewedBranch.getHead(),
- CDORevision.UNCHUNKED, CDORevision.DEPTH_NONE, true);
-
- if (rev == null)
+ out.writeBoolean(result.isSuccessful());
+ out.writeBoolean(result.isTimedOut());
+ out.writeBoolean(result.isWaitForUpdate());
+ out.writeLong(result.getRequiredTimestamp());
+
+ CDORevisionKey[] staleRevisions = result.getStaleRevisions();
+ out.writeInt(staleRevisions.length);
+ for (CDORevisionKey revKey : staleRevisions)
{
- throw new IllegalArgumentException(String.format("Object %s not found in branch %s (possibly detached)", id,
- viewedBranch));
+ out.writeCDORevisionKey(revKey);
}
- if (!revKey.equals(rev))
+ CDOLockState[] newLockStates = result.getNewLockStates();
+ out.writeInt(newLockStates.length);
+ for (CDOLockState lockState : newLockStates)
{
- staleRevisions.add(revKey);
- requiredTimestamp = Math.max(requiredTimestamp, rev.getTimeStamp());
+ out.writeCDOLockState(lockState);
}
}
}
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockStateIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockStateIndication.java
new file mode 100644
index 0000000..2ac03fb
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockStateIndication.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2004 - 2011 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.server.internal.net4j.protocol;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
+import org.eclipse.emf.cdo.common.lock.CDOLockUtil;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
+import org.eclipse.emf.cdo.server.IView;
+import org.eclipse.emf.cdo.spi.server.InternalLockManager;
+import org.eclipse.emf.cdo.spi.server.InternalView;
+
+import org.eclipse.net4j.util.concurrent.RWOLockManager.LockState;
+
+import java.io.IOException;
+
+/**
+ * @author Caspar De Groot
+ */
+public class LockStateIndication extends CDOServerReadIndication
+{
+ private CDOLockState[] cdoLockStates;
+
+ public LockStateIndication(CDOServerProtocol protocol)
+ {
+ super(protocol, CDOProtocolConstants.SIGNAL_LOCK_STATE);
+ }
+
+ @Override
+ protected void indicating(CDODataInput in) throws IOException
+ {
+ int viewID = in.readInt();
+ InternalView view = getSession().getView(viewID);
+ if (view == null)
+ {
+ throw new IllegalStateException("View not found");
+ }
+
+ InternalLockManager lockMgr = getRepository().getLockManager();
+
+ int n = in.readInt();
+ cdoLockStates = new CDOLockState[n];
+ for (int i = 0; i < n; i++)
+ {
+ Object key = indicatingCDOID(in, view.getBranch());
+ LockState<Object, IView> lockState = lockMgr.getLockState(key);
+ if (lockState != null)
+ {
+ cdoLockStates[i] = CDOLockUtil.createLockState(lockState);
+ }
+ else
+ {
+ cdoLockStates[i] = CDOLockUtil.createLockState(key);
+ }
+ }
+ }
+
+ private Object indicatingCDOID(CDODataInput in, CDOBranch viewedBranch) throws IOException
+ {
+ CDOID id = in.readCDOID();
+ if (getRepository().isSupportingBranches())
+ {
+ return CDOIDUtil.createIDAndBranch(id, viewedBranch);
+ }
+
+ return id;
+ }
+
+ @Override
+ protected void responding(CDODataOutput out) throws IOException
+ {
+ out.writeInt(cdoLockStates.length);
+ for (CDOLockState lockState : cdoLockStates)
+ {
+ out.writeCDOLockState(lockState);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/OpenViewIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/OpenViewIndication.java
index d55c50c..25c515f 100644
--- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/OpenViewIndication.java
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/OpenViewIndication.java
@@ -17,6 +17,7 @@ import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
import org.eclipse.emf.cdo.spi.server.InternalLockManager;
import org.eclipse.emf.cdo.spi.server.InternalSession;
+import org.eclipse.emf.cdo.spi.server.InternalView;
import java.io.IOException;
@@ -25,7 +26,7 @@ import java.io.IOException;
*/
public class OpenViewIndication extends CDOServerReadIndication
{
- private CDOBranchPoint result;
+ private InternalView newView;
private String message;
@@ -47,11 +48,11 @@ public class OpenViewIndication extends CDOServerReadIndication
CDOBranchPoint branchPoint = in.readCDOBranchPoint();
if (readOnly)
{
- session.openView(viewID, branchPoint);
+ newView = session.openView(viewID, branchPoint);
}
else
{
- session.openTransaction(viewID, branchPoint);
+ newView = session.openTransaction(viewID, branchPoint);
}
}
else
@@ -61,7 +62,7 @@ public class OpenViewIndication extends CDOServerReadIndication
try
{
String durableLockingID = in.readString();
- result = lockManager.openView(session, viewID, readOnly, durableLockingID);
+ newView = (InternalView)lockManager.openView(session, viewID, readOnly, durableLockingID);
}
catch (LockAreaNotFoundException ex)
{
@@ -77,10 +78,10 @@ public class OpenViewIndication extends CDOServerReadIndication
@Override
protected void responding(CDODataOutput out) throws IOException
{
- if (result != null)
+ if (newView != null)
{
out.writeBoolean(true);
- out.writeCDOBranchPoint(result);
+ out.writeCDOBranchPoint(newView);
}
else
{
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/UnlockDelegationIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/UnlockDelegationIndication.java
new file mode 100644
index 0000000..a33b260
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/UnlockDelegationIndication.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2004 - 2011 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.server.internal.net4j.protocol;
+
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
+import org.eclipse.emf.cdo.server.IView;
+import org.eclipse.emf.cdo.spi.server.InternalLockManager;
+import org.eclipse.emf.cdo.spi.server.InternalSession;
+import org.eclipse.emf.cdo.spi.server.InternalView;
+
+import java.io.IOException;
+
+/**
+ * @author Caspar De Groot
+ */
+public class UnlockDelegationIndication extends UnlockObjectsIndication
+{
+ private InternalView view;
+
+ private String lockAreaID;
+
+ public UnlockDelegationIndication(CDOServerProtocol protocol)
+ {
+ super(protocol, CDOProtocolConstants.SIGNAL_UNLOCK_OBJECTS);
+ }
+
+ @Override
+ protected void indicating(CDODataInput in) throws IOException
+ {
+ lockAreaID = in.readString();
+ super.indicating(in);
+ }
+
+ @Override
+ protected void responding(CDODataOutput out) throws IOException
+ {
+ try
+ {
+ super.responding(out);
+ }
+ finally
+ {
+ view.close();
+ }
+ }
+
+ @Override
+ protected IView getView(int viewID)
+ {
+ InternalLockManager lockManager = getRepository().getLockManager();
+ InternalSession session = getSession();
+ view = (InternalView)lockManager.openView(session, InternalSession.TEMP_VIEW_ID, true, lockAreaID);
+ return view;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/UnlockObjectsIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/UnlockObjectsIndication.java
index 7c01c31..a945056 100644
--- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/UnlockObjectsIndication.java
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/UnlockObjectsIndication.java
@@ -11,20 +11,21 @@
*/
package org.eclipse.emf.cdo.server.internal.net4j.protocol;
-import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.protocol.CDODataInput;
import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
import org.eclipse.emf.cdo.server.IView;
-import org.eclipse.emf.cdo.spi.server.InternalLockManager;
import org.eclipse.emf.cdo.spi.server.InternalRepository;
+import org.eclipse.emf.cdo.spi.server.InternalView;
import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+import org.eclipse.emf.spi.cdo.CDOSessionProtocol.UnlockObjectsResult;
+
import java.io.IOException;
-import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
/**
@@ -32,11 +33,18 @@ import java.util.List;
*/
public class UnlockObjectsIndication extends CDOServerWriteIndication
{
+ private UnlockObjectsResult result;
+
public UnlockObjectsIndication(CDOServerProtocol protocol)
{
super(protocol, CDOProtocolConstants.SIGNAL_UNLOCK_OBJECTS);
}
+ protected UnlockObjectsIndication(CDOServerProtocol protocol, short signalID)
+ {
+ super(protocol, signalID);
+ }
+
@Override
protected void indicating(CDODataInput in) throws IOException
{
@@ -45,33 +53,37 @@ public class UnlockObjectsIndication extends CDOServerWriteIndication
int size = in.readInt();
InternalRepository repository = getRepository();
- InternalLockManager lockManager = repository.getLockManager();
- IView view = getSession().getView(viewID);
+ IView view = getView(viewID);
if (size == CDOProtocolConstants.RELEASE_ALL_LOCKS)
{
- lockManager.unlock(true, view);
+ result = repository.unlock((InternalView)view, null, null);
}
else
{
- boolean supportingBranches = repository.isSupportingBranches();
- CDOBranch branch = view.getBranch();
-
- List<Object> keys = new ArrayList<Object>(size);
+ List<CDOID> objectIDs = new LinkedList<CDOID>();
for (int i = 0; i < size; i++)
{
- CDOID id = in.readCDOID();
- Object key = supportingBranches ? CDOIDUtil.createIDAndBranch(id, branch) : id;
- keys.add(key);
+ objectIDs.add(in.readCDOID());
}
- lockManager.unlock(true, lockType, view, keys);
+ result = repository.unlock((InternalView)view, lockType, objectIDs);
}
}
@Override
protected void responding(CDODataOutput out) throws IOException
{
- out.writeBoolean(true);
+ CDOLockState[] newLockStates = result.getNewLockStates();
+ out.writeInt(newLockStates.length);
+ for (CDOLockState state : newLockStates)
+ {
+ out.writeCDOLockState(state);
+ }
+ }
+
+ protected IView getView(int viewID)
+ {
+ return getSession().getView(viewID);
}
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/LockManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/LockManager.java
index 9322e13..f552982 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/LockManager.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/LockManager.java
@@ -23,6 +23,7 @@ import org.eclipse.emf.cdo.server.ISession;
import org.eclipse.emf.cdo.server.ISessionManager;
import org.eclipse.emf.cdo.server.IStoreAccessor;
import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking;
+import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking2;
import org.eclipse.emf.cdo.server.IView;
import org.eclipse.emf.cdo.server.StoreThreadLocal;
import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil;
@@ -45,6 +46,7 @@ import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -155,9 +157,16 @@ public class LockManager extends RWOLockManager<Object, IView> implements Intern
return result;
}
+ @Deprecated
public void lock(boolean explicit, LockType type, IView view, Collection<? extends Object> objectsToLock, long timeout)
throws InterruptedException
{
+ lock2(explicit, type, view, objectsToLock, timeout);
+ }
+
+ public List<LockState<Object, IView>> lock2(boolean explicit, LockType type, IView view,
+ Collection<? extends Object> objectsToLock, long timeout) throws InterruptedException
+ {
String durableLockingID = null;
DurableLocking accessor = null;
@@ -170,16 +179,25 @@ public class LockManager extends RWOLockManager<Object, IView> implements Intern
}
}
- super.lock(type, view, objectsToLock, timeout);
+ List<LockState<Object, IView>> newLockStates = super.lock2(type, view, objectsToLock, timeout);
if (accessor != null)
{
accessor.lock(durableLockingID, type, objectsToLock);
}
+
+ return newLockStates;
}
+ @Deprecated
public void unlock(boolean explicit, LockType type, IView view, Collection<? extends Object> objectsToUnlock)
{
+ unlock2(explicit, type, view, objectsToUnlock);
+ }
+
+ public List<LockState<Object, IView>> unlock2(boolean explicit, LockType type, IView view,
+ Collection<? extends Object> objectsToUnlock)
+ {
if (explicit)
{
String durableLockingID = view.getDurableLockingID();
@@ -190,11 +208,17 @@ public class LockManager extends RWOLockManager<Object, IView> implements Intern
}
}
- super.unlock(type, view, objectsToUnlock);
+ return super.unlock2(type, view, objectsToUnlock);
}
+ @Deprecated
public void unlock(boolean explicit, IView view)
{
+ unlock(explicit, view);
+ }
+
+ public List<LockState<Object, IView>> unlock2(boolean explicit, IView view)
+ {
if (explicit)
{
String durableLockingID = view.getDurableLockingID();
@@ -205,24 +229,41 @@ public class LockManager extends RWOLockManager<Object, IView> implements Intern
}
}
- super.unlock(view);
+ return super.unlock2(view);
}
public LockArea createLockArea(String userID, CDOBranchPoint branchPoint, boolean readOnly,
Map<CDOID, LockGrade> locks)
{
- DurableLocking accessor = getDurableLocking();
- return accessor.createLockArea(userID, branchPoint, readOnly, locks);
+ return createLockArea(userID, branchPoint, readOnly, locks, null);
+ }
+
+ private LockArea createLockArea(String userID, CDOBranchPoint branchPoint, boolean readOnly,
+ Map<CDOID, LockGrade> locks, String lockAreaID)
+ {
+ if (lockAreaID == null)
+ {
+ DurableLocking accessor = getDurableLocking();
+ return accessor.createLockArea(userID, branchPoint, readOnly, locks);
+ }
+
+ DurableLocking2 accessor = getDurableLocking2();
+ return accessor.createLockArea(lockAreaID, userID, branchPoint, readOnly, locks);
}
public LockArea createLockArea(InternalView view)
{
+ return createLockArea(view, null);
+ }
+
+ public LockArea createLockArea(InternalView view, String lockAreaID)
+ {
String userID = view.getSession().getUserID();
CDOBranchPoint branchPoint = CDOBranchUtil.copyBranchPoint(view);
boolean readOnly = view.isReadOnly();
Map<CDOID, LockGrade> locks = getLocks(view);
- LockArea area = createLockArea(userID, branchPoint, readOnly, locks);
+ LockArea area = createLockArea(userID, branchPoint, readOnly, locks, lockAreaID);
synchronized (openViews)
{
openViews.put(area.getDurableLockingID(), view);
@@ -328,7 +369,18 @@ public class LockManager extends RWOLockManager<Object, IView> implements Intern
return (DurableLocking)accessor;
}
- throw new IllegalStateException("Store does not support durable locking");
+ throw new IllegalStateException("Store does not implement " + DurableLocking.class.getSimpleName());
+ }
+
+ private DurableLocking2 getDurableLocking2()
+ {
+ IStoreAccessor accessor = StoreThreadLocal.getAccessor();
+ if (accessor instanceof DurableLocking2)
+ {
+ return (DurableLocking2)accessor;
+ }
+
+ throw new IllegalStateException("Store does not implement " + DurableLocking2.class.getSimpleName());
}
private void loadDurableLocks()
@@ -439,7 +491,7 @@ public class LockManager extends RWOLockManager<Object, IView> implements Intern
public ISession getSession()
{
- throw new UnsupportedOperationException();
+ return null;
}
@Override
@@ -518,4 +570,21 @@ public class LockManager extends RWOLockManager<Object, IView> implements Intern
return true;
}
}
+
+ public LockGrade getLockGrade(Object key)
+ {
+ LockState<Object, IView> lockState = getObjectToLocksMap().get(key);
+ LockGrade grade = LockGrade.NONE;
+ if (lockState != null)
+ {
+ for (LockType type : LockType.values())
+ {
+ if (lockState.hasLock(type))
+ {
+ grade = grade.getUpdated(type, true);
+ }
+ }
+ }
+ return grade;
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
index 79d2f21..60fac60 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
@@ -15,6 +15,7 @@
*/
package org.eclipse.emf.cdo.internal.server;
+import org.eclipse.emf.cdo.common.CDOCommonView;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.branch.CDOBranchHandler;
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
@@ -28,6 +29,10 @@ import org.eclipse.emf.cdo.common.id.CDOIDGenerator;
import org.eclipse.emf.cdo.common.id.CDOIDTemp;
import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.common.lob.CDOLobHandler;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
+import org.eclipse.emf.cdo.common.lock.CDOLockUtil;
import org.eclipse.emf.cdo.common.model.CDOModelUtil;
import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
import org.eclipse.emf.cdo.common.model.EMFUtil;
@@ -36,6 +41,7 @@ import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionFactory;
import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
import org.eclipse.emf.cdo.common.util.CDOCommonUtil;
import org.eclipse.emf.cdo.common.util.CDOQueryInfo;
@@ -53,6 +59,7 @@ import org.eclipse.emf.cdo.server.IStoreAccessor;
import org.eclipse.emf.cdo.server.IStoreChunkReader;
import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk;
import org.eclipse.emf.cdo.server.ITransaction;
+import org.eclipse.emf.cdo.server.IView;
import org.eclipse.emf.cdo.server.StoreThreadLocal;
import org.eclipse.emf.cdo.spi.common.CDOReplicationContext;
import org.eclipse.emf.cdo.spi.common.CDOReplicationInfo;
@@ -81,13 +88,18 @@ import org.eclipse.emf.cdo.spi.server.InternalSession;
import org.eclipse.emf.cdo.spi.server.InternalSessionManager;
import org.eclipse.emf.cdo.spi.server.InternalStore;
import org.eclipse.emf.cdo.spi.server.InternalTransaction;
+import org.eclipse.emf.cdo.spi.server.InternalView;
import org.eclipse.emf.internal.cdo.object.CDOFactoryImpl;
import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
import org.eclipse.net4j.util.StringUtil;
+import org.eclipse.net4j.util.WrappedException;
import org.eclipse.net4j.util.collection.MoveableList;
import org.eclipse.net4j.util.collection.Pair;
+import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+import org.eclipse.net4j.util.concurrent.RWOLockManager.LockState;
+import org.eclipse.net4j.util.concurrent.TimeoutRuntimeException;
import org.eclipse.net4j.util.container.Container;
import org.eclipse.net4j.util.container.IPluginContainer;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
@@ -99,6 +111,8 @@ import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.spi.cdo.CDOSessionProtocol.LockObjectsResult;
+import org.eclipse.emf.spi.cdo.CDOSessionProtocol.UnlockObjectsResult;
import java.io.IOException;
import java.io.OutputStream;
@@ -107,6 +121,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -1325,6 +1340,147 @@ public class Repository extends Container<Object> implements InternalRepository
}
}
+ public LockObjectsResult lock(InternalView view, LockType lockType, List<CDORevisionKey> revisionKeys,
+ CDOBranch viewedBranch, long timeout)
+ {
+ List<Object> objectsToLock = new ArrayList<Object>();
+ boolean isSupportingBranches = isSupportingBranches();
+ for (CDORevisionKey revKey : revisionKeys)
+ {
+ CDOID id = revKey.getID();
+ if (isSupportingBranches)
+ {
+ objectsToLock.add(CDOIDUtil.createIDAndBranch(id, viewedBranch));
+ }
+ else
+ {
+ objectsToLock.add(id);
+ }
+ }
+
+ InternalLockManager lockManager = getLockManager();
+ List<LockState<Object, IView>> newLockStates = null;
+
+ try
+ {
+ newLockStates = lockManager.lock2(true, lockType, view, objectsToLock, timeout);
+ }
+ catch (TimeoutRuntimeException ex)
+ {
+ return new LockObjectsResult(false, true, false, 0, new CDORevisionKey[0], new CDOLockState[0]);
+ }
+ catch (InterruptedException ex)
+ {
+ throw WrappedException.wrap(ex);
+ }
+
+ List<CDORevisionKey> staleRevisions = new LinkedList<CDORevisionKey>();
+ long requiredTimestamp = 0;
+
+ try
+ {
+ InternalCDORevisionManager revManager = getRevisionManager();
+
+ for (CDORevisionKey revKey : revisionKeys)
+ {
+ CDOID id = revKey.getID();
+ InternalCDORevision rev = revManager.getRevision(id, viewedBranch.getHead(), CDORevision.UNCHUNKED,
+ CDORevision.DEPTH_NONE, true);
+
+ if (rev == null)
+ {
+ throw new IllegalArgumentException(String.format("Object %s not found in branch %s (possibly detached)", id,
+ viewedBranch));
+ }
+
+ if (!revKey.equals(rev))
+ {
+ staleRevisions.add(revKey);
+ requiredTimestamp = Math.max(requiredTimestamp, rev.getTimeStamp());
+ }
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ lockManager.unlock2(true, lockType, view, objectsToLock);
+ throw ex;
+ }
+
+ // Convert the list to an array, to satisfy the API later
+ //
+ CDORevisionKey[] staleRevisionsArray = new CDORevisionKey[staleRevisions.size()];
+ staleRevisions.toArray(staleRevisionsArray);
+
+ // If some of the clients' revisions are stale and it has passiveUpdates disabled,
+ // then the locks are useless so we release them and report the stale revisions
+ InternalSession session = view.getSession();
+ boolean staleNoUpdate = staleRevisionsArray.length > 0 && !session.isPassiveUpdateEnabled();
+ if (staleNoUpdate)
+ {
+ lockManager.unlock2(true, lockType, view, objectsToLock);
+ return new LockObjectsResult(false, false, false, requiredTimestamp, staleRevisionsArray, new CDOLockState[0]);
+ }
+
+ CDOLockState[] cdoLockStates = toCDOLockStates(newLockStates);
+ sendLockNotifications(view, viewedBranch, Operation.LOCK, cdoLockStates);
+
+ boolean waitForUpdate = staleRevisionsArray.length > 0;
+ return new LockObjectsResult(true, false, waitForUpdate, requiredTimestamp, staleRevisionsArray, cdoLockStates);
+ }
+
+ private void sendLockNotifications(IView view, CDOBranch viewedBranch, Operation operation,
+ CDOLockState[] cdoLockStates)
+ {
+ long timestamp = getTimeStamp();
+ CDOLockChangeInfo lockChangeInfo = CDOLockUtil.createLockChangeInfo(timestamp, view, viewedBranch, operation,
+ cdoLockStates);
+ getSessionManager().sendLockNotification((InternalSession)view.getSession(), lockChangeInfo);
+ }
+
+ // TODO (CD) This doesn't really belong here.. but getting it into CDOLockUtil isn't possible
+ private CDOLockState[] toCDOLockStates(List<LockState<Object, IView>> lockStates)
+ {
+ CDOLockState[] cdoLockStates = new CDOLockState[lockStates.size()];
+ int i = 0;
+
+ for (LockState<Object, ? extends CDOCommonView> lockState : lockStates)
+ {
+ cdoLockStates[i++] = CDOLockUtil.createLockState(lockState);
+ }
+
+ return cdoLockStates;
+ }
+
+ public UnlockObjectsResult unlock(InternalView view, LockType lockType, List<CDOID> objectIDs)
+ {
+ List<Object> revisionKeys = null;
+ if (objectIDs != null)
+ {
+ revisionKeys = new ArrayList<Object>(objectIDs.size());
+ CDOBranch branch = view.getBranch();
+ for (CDOID id : objectIDs)
+ {
+ Object key = supportingBranches ? CDOIDUtil.createIDAndBranch(id, branch) : id;
+ revisionKeys.add(key);
+ }
+ }
+
+ List<LockState<Object, IView>> newLockStates = null;
+ if (lockType == null && revisionKeys == null)
+ {
+ newLockStates = lockManager.unlock2(true, view);
+ }
+ else
+ {
+ newLockStates = lockManager.unlock2(true, lockType, view, revisionKeys);
+ }
+
+ CDOLockState[] cdoLockStates = toCDOLockStates(newLockStates);
+ sendLockNotifications(view, view.getBranch(), Operation.UNLOCK, cdoLockStates);
+
+ return new UnlockObjectsResult(cdoLockStates);
+ }
+
@Override
public String toString()
{
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java
index 10868ef..3af601d 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java
@@ -19,6 +19,8 @@ import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOID.ObjectType;
import org.eclipse.emf.cdo.common.id.CDOIDGenerator;
import org.eclipse.emf.cdo.common.lob.CDOLobStore;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator;
import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
@@ -209,6 +211,11 @@ public class ServerCDOView extends AbstractCDOView implements org.eclipse.emf.cd
throw new UnsupportedOperationException();
}
+ public void handleLockNotification(CDOLockChangeInfo lockChangeInfo)
+ {
+ // Do nothing
+ }
+
public void prefetchRevisions(CDOID id, int depth)
{
throw new UnsupportedOperationException();
@@ -279,6 +286,16 @@ public class ServerCDOView extends AbstractCDOView implements org.eclipse.emf.cd
throw new UnsupportedOperationException();
}
+ public boolean isLockNotificationEnabled()
+ {
+ return false;
+ }
+
+ public void setLockNotificationEnabled(boolean enabled)
+ {
+ throw new UnsupportedOperationException();
+ }
+
public CDOAdapterPolicy[] getChangeSubscriptionPolicies()
{
return ADAPTER_POLICIES;
@@ -324,6 +341,11 @@ public class ServerCDOView extends AbstractCDOView implements org.eclipse.emf.cd
throw new UnsupportedOperationException();
}
+ public CDOLockState[] getLockStates(Collection<CDOID> ids)
+ {
+ throw new UnsupportedOperationException();
+ }
+
/**
* @author Eike Stepper
*/
@@ -784,6 +806,11 @@ public class ServerCDOView extends AbstractCDOView implements org.eclipse.emf.cd
throw new UnsupportedOperationException();
}
+ public void handleLockNotification(CDOLockChangeInfo lockChangeInfo)
+ {
+ throw new UnsupportedOperationException();
+ }
+
public void handleBranchNotification(InternalCDOBranch branch)
{
throw new UnsupportedOperationException();
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
index 727e0fd..cf32de4 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
@@ -20,6 +20,7 @@ import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
import org.eclipse.emf.cdo.common.model.CDOModelUtil;
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
@@ -453,6 +454,23 @@ public class Session extends Container<IView> implements InternalSession
}
}
+ public void sendLockNotification(CDOLockChangeInfo lockChangeInfo) throws Exception
+ {
+ if (protocol != null)
+ {
+ // If this session has one (or more) views configured for this branch,
+ // only then do we send the lockChangeInfo.
+ for (InternalView view : getViews())
+ {
+ if (view.isLockNotificationEnabled() && view.getBranch().equals(lockChangeInfo.getBranch()))
+ {
+ protocol.sendLockNotification(lockChangeInfo);
+ break;
+ }
+ }
+ }
+ }
+
private boolean hasSubscription(CDOID id, InternalView[] views)
{
for (InternalView view : views)
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java
index e519b9d..7869c79 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java
@@ -14,6 +14,7 @@ package org.eclipse.emf.cdo.internal.server;
import org.eclipse.emf.cdo.common.CDOCommonRepository;
import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
import org.eclipse.emf.cdo.internal.server.bundle.OM;
import org.eclipse.emf.cdo.server.ISession;
@@ -307,6 +308,23 @@ public class SessionManager extends Container<ISession> implements InternalSessi
}
}
+ public void sendLockNotification(InternalSession sender, CDOLockChangeInfo lockChangeInfo)
+ {
+ for (InternalSession session : getSessions())
+ {
+ // TODO Exclude the sender and notify locally there
+
+ try
+ {
+ session.sendLockNotification(lockChangeInfo);
+ }
+ catch (Exception ex)
+ {
+ handleNotificationProblem(session, ex);
+ }
+ }
+ }
+
/**
* @since 2.0
*/
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java
index 376ef17..e2290ce 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java
@@ -42,6 +42,7 @@ import org.eclipse.emf.cdo.internal.server.bundle.OM;
import org.eclipse.emf.cdo.server.ContainmentCycleDetectedException;
import org.eclipse.emf.cdo.server.IStoreAccessor;
import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
+import org.eclipse.emf.cdo.server.IView;
import org.eclipse.emf.cdo.server.StoreThreadLocal;
import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo;
@@ -66,6 +67,7 @@ import org.eclipse.net4j.util.ObjectUtil;
import org.eclipse.net4j.util.StringUtil;
import org.eclipse.net4j.util.collection.IndexedList;
import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+import org.eclipse.net4j.util.concurrent.RWOLockManager.LockState;
import org.eclipse.net4j.util.io.ExtendedDataInputStream;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import org.eclipse.net4j.util.om.monitor.Monitor;
@@ -147,6 +149,8 @@ public class TransactionCommitContext implements InternalCommitContext
private List<CDOIDReference> xRefs;
+ private List<LockState<Object, IView>> postCommitLockStates;
+
private boolean ensuringReferentialIntegrity;
private boolean autoReleaseLocksEnabled;
@@ -487,6 +491,11 @@ public class TransactionCommitContext implements InternalCommitContext
}
}
+ public List<LockState<Object, IView>> getPostCommmitLockStates()
+ {
+ return postCommitLockStates;
+ }
+
private void handleException(Throwable ex)
{
try
@@ -1046,7 +1055,7 @@ public class TransactionCommitContext implements InternalCommitContext
if (isAutoReleaseLocksEnabled())
{
- repository.getLockManager().unlock(transaction);
+ postCommitLockStates = repository.getLockManager().unlock2(true, transaction);
}
monitor.worked();
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/View.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/View.java
index 5701fc3..a81cbb8 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/View.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/View.java
@@ -22,6 +22,7 @@ import org.eclipse.emf.cdo.spi.server.InternalRepository;
import org.eclipse.emf.cdo.spi.server.InternalSession;
import org.eclipse.emf.cdo.spi.server.InternalView;
+import org.eclipse.net4j.util.ObjectUtil;
import org.eclipse.net4j.util.lifecycle.Lifecycle;
import java.text.MessageFormat;
@@ -37,7 +38,10 @@ public class View extends Lifecycle implements InternalView
{
private InternalSession session;
- private int viewID;
+ private final int viewID;
+
+ private final int sessionID; // Needed here so we can compute the hashCode even after session becomes null due to
+ // deactivation!
private CDOBranchPoint branchPoint;
@@ -47,6 +51,8 @@ public class View extends Lifecycle implements InternalView
private Set<CDOID> changeSubscriptionIDs = new HashSet<CDOID>();
+ private boolean lockNotificationsEnabled;
+
/**
* @since 2.0
*/
@@ -54,6 +60,7 @@ public class View extends Lifecycle implements InternalView
{
this.session = session;
this.viewID = viewID;
+ sessionID = session.getSessionID();
repository = session.getManager().getRepository();
setBranchPoint(branchPoint);
@@ -193,6 +200,12 @@ public class View extends Lifecycle implements InternalView
}
@Override
+ public int hashCode()
+ {
+ return ObjectUtil.hashCode(sessionID, viewID);
+ }
+
+ @Override
public String toString()
{
int sessionID = session == null ? 0 : session.getSessionID();
@@ -249,4 +262,14 @@ public class View extends Lifecycle implements InternalView
throw new IllegalStateException("View closed"); //$NON-NLS-1$
}
}
+
+ public boolean isLockNotificationEnabled()
+ {
+ return lockNotificationsEnabled;
+ }
+
+ public void setLockNotificationEnabled(boolean enable)
+ {
+ lockNotificationsEnabled = enable;
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedClientSessionProtocol.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedClientSessionProtocol.java
index 86ef2bc..dd7471a 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedClientSessionProtocol.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedClientSessionProtocol.java
@@ -24,6 +24,7 @@ import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDProvider;
import org.eclipse.emf.cdo.common.lob.CDOLob;
import org.eclipse.emf.cdo.common.lob.CDOLobInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator;
import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
@@ -140,6 +141,16 @@ public class EmbeddedClientSessionProtocol extends Lifecycle implements CDOSessi
return result;
}
+ public CDOLockState[] getLockStates(int viewID, Collection<CDOID> ids)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void enableLockNotifications(int viewID, boolean enable)
+ {
+ throw new UnsupportedOperationException();
+ }
+
public void disablePassiveUpdate()
{
// serverSessionProtocol.getSession().setPassiveUpdateEnabled(passiveUpdateEnabled);
@@ -329,13 +340,39 @@ public class EmbeddedClientSessionProtocol extends Lifecycle implements CDOSessi
throw new UnsupportedOperationException();
}
+ @Deprecated
public LockObjectsResult lockObjects(List<InternalCDORevision> viewedRevisions, int viewID, CDOBranch viewedBranch,
LockType lockType, long timeout) throws InterruptedException
{
throw new UnsupportedOperationException();
}
- public void unlockObjects(CDOView view, Collection<? extends CDOObject> objects, LockType lockType)
+ /**
+ * @since 4.1
+ */
+ public LockObjectsResult lockObjects2(List<CDORevisionKey> revisionKeys, int viewID, CDOBranch viewedBranch,
+ LockType lockType, long timeout) throws InterruptedException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void unlockObjects(CDOView view, Collection<CDOID> objectIDs, LockType lockType)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public UnlockObjectsResult unlockObjects2(CDOView view, Collection<CDOID> objectIDs, LockType lockType)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public LockObjectsResult delegateLockObjects(String lockAreaID, List<CDORevisionKey> revisionKeys,
+ CDOBranch viewedBranch, LockType lockType, long timeout) throws InterruptedException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public UnlockObjectsResult delegateUnlockObjects(String lockAreaID, Collection<CDOID> objectIDs, LockType lockType)
{
throw new UnsupportedOperationException();
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedServerSessionProtocol.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedServerSessionProtocol.java
index 8fd0ce5..adfec3f 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedServerSessionProtocol.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedServerSessionProtocol.java
@@ -12,6 +12,7 @@ package org.eclipse.emf.cdo.internal.server.embedded;
import org.eclipse.emf.cdo.common.CDOCommonRepository;
import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage;
import org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult;
import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
@@ -82,6 +83,12 @@ public class EmbeddedServerSessionProtocol extends Lifecycle implements ISession
clientSession.handleCommitNotification(commitInfo);
}
+ public void sendLockNotification(CDOLockChangeInfo lockChangeInfo)
+ {
+ EmbeddedClientSession clientSession = clientSessionProtocol.getSession();
+ clientSession.handleLockNotification(lockChangeInfo);
+ }
+
public void sendRemoteSessionNotification(InternalSession sender, byte opcode)
{
throw new UnsupportedOperationException();
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java
index 3793ac1..1f3b13f 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java
@@ -32,7 +32,7 @@ import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
import org.eclipse.emf.cdo.common.util.CDOCommonUtil;
import org.eclipse.emf.cdo.server.ISession;
import org.eclipse.emf.cdo.server.IStoreAccessor;
-import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking;
+import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking2;
import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
import org.eclipse.emf.cdo.server.ITransaction;
import org.eclipse.emf.cdo.server.IView;
@@ -88,7 +88,7 @@ import java.util.Set;
/**
* @author Simon McDuff
*/
-public class MEMStore extends LongIDStore implements IMEMStore, BranchLoader, DurableLocking
+public class MEMStore extends LongIDStore implements IMEMStore, BranchLoader, DurableLocking2
{
public static final String TYPE = "mem"; //$NON-NLS-1$
@@ -740,12 +740,27 @@ public class MEMStore extends LongIDStore implements IMEMStore, BranchLoader, Du
public synchronized LockArea createLockArea(String userID, CDOBranchPoint branchPoint, boolean readOnly,
Map<CDOID, LockGrade> locks)
{
- String durableLockingID;
+ return createLockArea(null, userID, branchPoint, readOnly, locks);
+ }
- do
+ public synchronized LockArea createLockArea(String durableLockingID, String userID, CDOBranchPoint branchPoint,
+ boolean readOnly, Map<CDOID, LockGrade> locks)
+ {
+ if (durableLockingID != null)
{
- durableLockingID = DurableLockArea.createDurableLockingID();
- } while (lockAreas.containsKey(durableLockingID));
+ // If the caller is specifying the ID, make sure there is no area with this ID yet
+ if (lockAreas.containsKey(durableLockingID))
+ {
+ throw new LockAreaAlreadyExistsException(durableLockingID);
+ }
+ }
+ else
+ {
+ do
+ {
+ durableLockingID = DurableLockArea.createDurableLockingID();
+ } while (lockAreas.containsKey(durableLockingID));
+ }
LockArea area = new DurableLockArea(durableLockingID, userID, branchPoint, readOnly, locks);
lockAreas.put(durableLockingID, area);
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java
index 2e071a7..90974d1 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java
@@ -28,7 +28,7 @@ import org.eclipse.emf.cdo.common.util.CDOQueryInfo;
import org.eclipse.emf.cdo.server.IQueryContext;
import org.eclipse.emf.cdo.server.IQueryHandler;
import org.eclipse.emf.cdo.server.ISession;
-import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking;
+import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking2;
import org.eclipse.emf.cdo.server.IStoreAccessor.Raw;
import org.eclipse.emf.cdo.server.ITransaction;
import org.eclipse.emf.cdo.spi.common.commit.CDOChangeSetSegment;
@@ -62,7 +62,7 @@ import java.util.Set;
/**
* @author Simon McDuff
*/
-public class MEMStoreAccessor extends LongIDStoreAccessor implements Raw, DurableLocking
+public class MEMStoreAccessor extends LongIDStoreAccessor implements Raw, DurableLocking2
{
private final IQueryHandler testQueryHandler = new IQueryHandler()
{
@@ -408,6 +408,12 @@ public class MEMStoreAccessor extends LongIDStoreAccessor implements Raw, Durabl
return getStore().createLockArea(userID, branchPoint, readOnly, locks);
}
+ public LockArea createLockArea(String durableLockingID, String userID, CDOBranchPoint branchPoint, boolean readOnly,
+ Map<CDOID, LockGrade> locks)
+ {
+ return getStore().createLockArea(durableLockingID, userID, branchPoint, readOnly, locks);
+ }
+
public LockArea getLockArea(String durableLockingID) throws LockAreaNotFoundException
{
return getStore().getLockArea(durableLockingID);
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/SynchronizableRepository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/SynchronizableRepository.java
index 712438d..9f424cb 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/SynchronizableRepository.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/SynchronizableRepository.java
@@ -25,6 +25,7 @@ import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
import org.eclipse.emf.cdo.common.util.CDOCommonUtil;
+import org.eclipse.emf.cdo.common.util.CDOException;
import org.eclipse.emf.cdo.internal.common.commit.CDOCommitDataImpl;
import org.eclipse.emf.cdo.internal.server.Repository;
import org.eclipse.emf.cdo.internal.server.TransactionCommitContext;
@@ -43,13 +44,20 @@ import org.eclipse.emf.cdo.spi.server.InternalSessionManager;
import org.eclipse.emf.cdo.spi.server.InternalStore;
import org.eclipse.emf.cdo.spi.server.InternalSynchronizableRepository;
import org.eclipse.emf.cdo.spi.server.InternalTransaction;
+import org.eclipse.emf.cdo.spi.server.InternalView;
+import org.eclipse.net4j.util.CheckUtil;
+import org.eclipse.net4j.util.WrappedException;
+import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
import org.eclipse.net4j.util.om.monitor.Monitor;
import org.eclipse.net4j.util.om.monitor.OMMonitor;
import org.eclipse.net4j.util.transaction.TransactionException;
import org.eclipse.emf.spi.cdo.CDOSessionProtocol;
import org.eclipse.emf.spi.cdo.CDOSessionProtocol.CommitTransactionResult;
+import org.eclipse.emf.spi.cdo.CDOSessionProtocol.LockObjectsResult;
+import org.eclipse.emf.spi.cdo.CDOSessionProtocol.UnlockObjectsResult;
+import org.eclipse.emf.spi.cdo.InternalCDOSession;
import java.io.IOException;
import java.util.Arrays;
@@ -420,6 +428,99 @@ public abstract class SynchronizableRepository extends Repository.Default implem
setState(INITIAL);
}
+ @Override
+ public LockObjectsResult lock(InternalView view, LockType lockType, List<CDORevisionKey> revisionKeys,
+ CDOBranch viewedBranch, long timeout)
+ {
+ CheckUtil.checkState(view.getBranch().equals(viewedBranch),
+ "Client view's branch and server view's branch are different.");
+
+ if (view.getBranch().isLocal())
+ {
+ return super.lock(view, lockType, revisionKeys, viewedBranch, timeout);
+ }
+
+ if (getState() != ONLINE)
+ {
+ throw new CDOException("Cannot lock in a non-local branch when clone is not connected to master");
+ }
+
+ return lockThrough(true, view, lockType, revisionKeys, viewedBranch, timeout);
+ }
+
+ private LockObjectsResult lockThrough(boolean explicit, InternalView view, LockType lockType,
+ List<CDORevisionKey> revisionKeys, CDOBranch viewedBranch, long timeout)
+ {
+ // Delegate locking to the master
+ InternalCDOSession remoteSession = getSynchronizer().getRemoteSession();
+ CDOSessionProtocol sessionProtocol = remoteSession.getSessionProtocol();
+ try
+ {
+ String lockAreaID = view.getDurableLockingID();
+ if (lockAreaID == null)
+ {
+ throw new IllegalStateException("Durable locking is not enabled.");
+ }
+
+ LockObjectsResult masterLockingResult = sessionProtocol.delegateLockObjects(lockAreaID, revisionKeys,
+ viewedBranch, lockType, timeout);
+ if (!masterLockingResult.isSuccessful())
+ {
+ return masterLockingResult;
+ }
+
+ if (masterLockingResult.isWaitForUpdate())
+ {
+ if (!getSynchronizer().getRemoteSession().options().isPassiveUpdateEnabled())
+ {
+ throw new AssertionError(
+ "Master lock result requires clone to wait, but clone does not have passiveUpdates enabled.");
+ }
+
+ long requiredTimestamp = masterLockingResult.getRequiredTimestamp();
+ remoteSession.waitForUpdate(requiredTimestamp);
+ }
+
+ return super.lock(view, lockType, revisionKeys, viewedBranch, timeout);
+ }
+ catch (InterruptedException ex)
+ {
+ throw WrappedException.wrap(ex);
+ }
+ }
+
+ @Override
+ public UnlockObjectsResult unlock(InternalView view, LockType lockType, List<CDOID> objectIDs)
+ {
+ if (view.getBranch().isLocal())
+ {
+ return super.unlock(view, lockType, objectIDs);
+ }
+
+ if (getState() != ONLINE)
+ {
+ throw new CDOException("Cannot unlock in a non-local branch when clone is not connected to master");
+ }
+
+ return unlockThrough(view, lockType, objectIDs);
+ }
+
+ private UnlockObjectsResult unlockThrough(InternalView view, LockType lockType, List<CDOID> objectIDs)
+ {
+ // Delegate unlocking to the master
+ InternalCDOSession remoteSession = getSynchronizer().getRemoteSession();
+ CDOSessionProtocol sessionProtocol = remoteSession.getSessionProtocol();
+
+ String lockAreaID = view.getDurableLockingID();
+ if (lockAreaID == null)
+ {
+ throw new IllegalStateException("Durable locking is not enabled.");
+ }
+
+ sessionProtocol.delegateUnlockObjects(lockAreaID, objectIDs, lockType);
+ return super.unlock(view, lockType, objectIDs);
+ }
+
/**
* @author Eike Stepper
*/
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java
index d93c7ca..d9da5d9 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java
@@ -42,6 +42,7 @@ import org.eclipse.emf.cdo.spi.server.InternalCommitContext;
import org.eclipse.emf.cdo.spi.server.InternalSession;
import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+import org.eclipse.net4j.util.concurrent.RWOLockManager.LockState;
import org.eclipse.net4j.util.io.ExtendedDataInputStream;
import org.eclipse.net4j.util.io.IOUtil;
import org.eclipse.net4j.util.om.monitor.OMMonitor;
@@ -393,6 +394,11 @@ public interface IStoreAccessor extends IQueryHandlerProvider, BranchLoader, Com
* @since 4.0
*/
public List<CDOIDReference> getXRefs();
+
+ /**
+ * @since 4.1
+ */
+ public List<LockState<Object, IView>> getPostCommmitLockStates();
}
/**
@@ -700,4 +706,14 @@ public interface IStoreAccessor extends IQueryHandlerProvider, BranchLoader, Com
public void unlock(String durableLockingID);
}
+
+ /**
+ * @author Eike Stepper
+ * @since 4.1
+ */
+ public interface DurableLocking2 extends DurableLocking
+ {
+ LockArea createLockArea(String durableLockingID, String userID, CDOBranchPoint branchPoint, boolean readOnly,
+ Map<CDOID, LockGrade> locks);
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/ISessionProtocol.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/ISessionProtocol.java
index 2edafbe..d8e378f 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/ISessionProtocol.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/ISessionProtocol.java
@@ -12,6 +12,7 @@ package org.eclipse.emf.cdo.spi.server;
import org.eclipse.emf.cdo.common.CDOCommonRepository;
import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
import org.eclipse.emf.cdo.common.protocol.CDOProtocol;
import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage;
import org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult;
@@ -43,4 +44,9 @@ public interface ISessionProtocol extends CDOProtocol
public void sendRemoteSessionNotification(InternalSession sender, byte opcode) throws Exception;
public void sendRemoteMessageNotification(InternalSession sender, CDORemoteSessionMessage message) throws Exception;
+
+ /**
+ * @since 4.1
+ */
+ public void sendLockNotification(CDOLockChangeInfo lockChangeInfo) throws Exception;
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockManager.java
index e7bd2e6..d96cc59 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockManager.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockManager.java
@@ -17,9 +17,11 @@ import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch;
import org.eclipse.emf.cdo.server.ISession;
import org.eclipse.emf.cdo.server.IView;
-import org.eclipse.net4j.util.concurrent.IRWLockManager;
+import org.eclipse.net4j.util.concurrent.IRWOLockManager;
+import org.eclipse.net4j.util.concurrent.RWOLockManager.LockState;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
/**
@@ -31,7 +33,7 @@ import java.util.Map;
* @noextend This interface is not intended to be extended by clients.
* @noimplement This interface is not intended to be implemented by clients.
*/
-public interface InternalLockManager extends IRWLockManager<Object, IView>, IDurableLockingManager
+public interface InternalLockManager extends IRWOLockManager<Object, IView>, IDurableLockingManager
{
public InternalRepository getRepository();
@@ -60,32 +62,67 @@ public interface InternalLockManager extends IRWLockManager<Object, IView>, IDur
/**
* @since 4.0
*/
+ @Deprecated
public void lock(boolean explicit, LockType type, IView context, Collection<? extends Object> objectsToLock,
long timeout) throws InterruptedException;
/**
+ * @since 4.1
+ */
+ public List<LockState<Object, IView>> lock2(boolean explicit, LockType type, IView context,
+ Collection<? extends Object> objectsToLock, long timeout) throws InterruptedException;
+
+ /**
* Attempts to release for a given locktype, view and objects.
*
* @throws IllegalMonitorStateException
* Unlocking objects without lock.
* @since 4.0
*/
+ @Deprecated
public void unlock(boolean explicit, LockType type, IView context, Collection<? extends Object> objectsToUnlock);
/**
+ * @since 4.1
+ */
+ public List<LockState<Object, IView>> unlock2(boolean explicit, LockType type, IView context,
+ Collection<? extends Object> objectsToUnlock);
+
+ /**
* Attempts to release all locks(read and write) for a given view.
*
* @since 4.0
*/
+ @Deprecated
public void unlock(boolean explicit, IView context);
/**
+ * @since 4.1
+ */
+ public List<LockState<Object, IView>> unlock2(boolean explicit, IView context);
+
+ /**
* @since 4.0
*/
public LockArea createLockArea(InternalView view);
/**
+ * @since 4.1
+ */
+ public LockArea createLockArea(InternalView view, String lockAreaID);
+
+ /**
* @since 4.0
*/
public IView openView(ISession session, int viewID, boolean readOnly, String durableLockingID);
+
+ /**
+ * @since 4.1
+ */
+ public LockGrade getLockGrade(Object key);
+
+ /**
+ * @since 4.1
+ */
+ public LockState<Object, IView> getLockState(Object key);
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockingManagerContext.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockingManagerContext.java
new file mode 100644
index 0000000..00782c3
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockingManagerContext.java
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2004 - 2011 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.spi.server;
+
+/**
+ * @author Caspar De Groot
+ * @since 4.1
+ */
+public interface InternalLockingManagerContext
+{
+
+}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java
index 3e7306d..732f716 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java
@@ -19,6 +19,7 @@ import org.eclipse.emf.cdo.common.lob.CDOLobHandler;
import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
import org.eclipse.emf.cdo.server.IQueryHandlerProvider;
import org.eclipse.emf.cdo.server.IRepository;
import org.eclipse.emf.cdo.server.IStoreAccessor;
@@ -37,10 +38,13 @@ import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager.RevisionLoader;
+import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
import org.eclipse.net4j.util.om.monitor.OMMonitor;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.spi.cdo.CDOSessionProtocol.LockObjectsResult;
+import org.eclipse.emf.spi.cdo.CDOSessionProtocol.UnlockObjectsResult;
import java.io.IOException;
import java.io.OutputStream;
@@ -213,4 +217,15 @@ public interface InternalRepository extends IRepository, PackageProcessor, Packa
* @since 4.0
*/
public void initMainBranch(InternalCDOBranchManager branchManager, long timeStamp);
+
+ /**
+ * @since 4.1
+ */
+ public LockObjectsResult lock(InternalView view, LockType lockType, List<CDORevisionKey> revisionKeys,
+ CDOBranch viewedBranch, long timeout);
+
+ /**
+ * @since 4.1
+ */
+ public UnlockObjectsResult unlock(InternalView view, LockType lockType, List<CDOID> objectIDs);
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java
index 47940ae..e06734b 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java
@@ -16,6 +16,7 @@ import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDProvider;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.server.ISession;
import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage;
@@ -65,4 +66,9 @@ public interface InternalSession extends ISession, CDOIDProvider, CDOCommonSessi
public void sendRemoteSessionNotification(InternalSession sender, byte opcode) throws Exception;
public void sendRemoteMessageNotification(InternalSession sender, CDORemoteSessionMessage message) throws Exception;
+
+ /**
+ * @since 4.1
+ */
+ public void sendLockNotification(CDOLockChangeInfo lockChangeInfo) throws Exception;
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java
index 7b46792..f82d68a 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java
@@ -12,6 +12,7 @@ package org.eclipse.emf.cdo.spi.server;
import org.eclipse.emf.cdo.common.CDOCommonRepository;
import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
import org.eclipse.emf.cdo.server.ISessionManager;
import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage;
import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
@@ -53,6 +54,11 @@ public interface InternalSessionManager extends ISessionManager
public void sendCommitNotification(InternalSession sender, CDOCommitInfo commitInfo);
+ /**
+ * @since 4.1
+ */
+ public void sendLockNotification(InternalSession sender, CDOLockChangeInfo lockChangeInfo);
+
public void sendRemoteSessionNotification(InternalSession sender, byte opcode);
public List<Integer> sendRemoteMessageNotification(InternalSession sender, CDORemoteSessionMessage message,
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalView.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalView.java
index 8adca8f..7440be8 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalView.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalView.java
@@ -53,4 +53,14 @@ public interface InternalView extends IView, ILifecycle
public void clearChangeSubscription();
public void doClose();
+
+ /**
+ * @since 4.1
+ */
+ public boolean isLockNotificationEnabled();
+
+ /**
+ * @since 4.1
+ */
+ public void setLockNotificationEnabled(boolean enable);
}
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2Offline.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2Offline.java
index 80d8ba1..26d0419 100644
--- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2Offline.java
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2Offline.java
@@ -20,6 +20,7 @@ import org.eclipse.emf.cdo.tests.offline.Bugzilla_328352_Test;
import org.eclipse.emf.cdo.tests.offline.Bugzilla_329014_Test;
import org.eclipse.emf.cdo.tests.offline.FailoverTest;
import org.eclipse.emf.cdo.tests.offline.OfflineDelayedTest;
+import org.eclipse.emf.cdo.tests.offline.OfflineLockingTest;
import org.eclipse.emf.cdo.tests.offline.OfflineRawTest;
import org.eclipse.emf.cdo.tests.offline.OfflineTest;
@@ -51,6 +52,7 @@ public class AllTestsDBH2Offline extends DBConfigs
testClasses.add(OfflineTest.class);
testClasses.add(OfflineRawTest.class);
testClasses.add(OfflineDelayedTest.class);
+ testClasses.add(OfflineLockingTest.class);
testClasses.add(Bugzilla_329014_Test.class);
testClasses.add(Bugzilla_328352_Test.class);
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
index 7b49bbe..a488d28 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
@@ -74,6 +74,7 @@ public abstract class AllConfigs extends ConfigTestSuite
testClasses.add(LockingManagerRestartTransactionTest.class);
testClasses.add(LockingManagerRestartSessionTest.class);
testClasses.add(LockingManagerRestartRepositoryTest.class);
+ testClasses.add(LockingNotificationsTest.class);
testClasses.add(MultiValuedOfAttributeTest.class);
testClasses.add(MapTest.class);
testClasses.add(FeatureMapTest.class);
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsMEMOffline.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsMEMOffline.java
index 72e5922..c67d939 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsMEMOffline.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsMEMOffline.java
@@ -14,6 +14,7 @@ import org.eclipse.emf.cdo.tests.config.IScenario;
import org.eclipse.emf.cdo.tests.config.impl.ConfigTest;
import org.eclipse.emf.cdo.tests.offline.FailoverTest;
import org.eclipse.emf.cdo.tests.offline.OfflineDelayed2Test;
+import org.eclipse.emf.cdo.tests.offline.OfflineLockingTest;
import org.eclipse.emf.cdo.tests.offline.OfflineTest;
import java.util.List;
@@ -43,6 +44,7 @@ public class AllTestsMEMOffline extends AllConfigs
// MEM does not support raw replication
// testClasses.add(OfflineRawTest.class);
+ testClasses.add(OfflineLockingTest.class);
testClasses.add(OfflineTest.class);
testClasses.add(OfflineDelayed2Test.class);
testClasses.add(FailoverTest.class);
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/LockingNotificationsTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/LockingNotificationsTest.java
new file mode 100644
index 0000000..f9b8f6e
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/LockingNotificationsTest.java
@@ -0,0 +1,341 @@
+/**
+ * Copyright (c) 2004 - 2011 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.id.CDOIDUtil;
+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.model1.Company;
+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.CDOLocksChangedEvent;
+import org.eclipse.emf.cdo.view.CDOView;
+
+import org.eclipse.net4j.util.event.IEvent;
+import org.eclipse.net4j.util.event.IListener;
+
+import java.util.LinkedList;
+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;
+ }
+
+ public void testSameBranchDifferentSession() throws CommitException
+ {
+ CDOSession session1 = openSession();
+ CDOSession session2 = openSession();
+ CDOView controlView = openViewWithLockNotifications(session2, null);
+ test(session1, controlView, true);
+ session1.close();
+ session2.close();
+ }
+
+ public void testSameBranchSameSession() throws CommitException
+ {
+ CDOSession session1 = openSession();
+ CDOView controlView = openViewWithLockNotifications(session1, null);
+ test(session1, controlView, true);
+ session1.close();
+ }
+
+ public void testDifferentBranchDifferentSession() throws CommitException
+ {
+ skipUnlessBranching();
+
+ CDOSession session1 = openSession();
+ CDOBranch subBranch = session1.getBranchManager().getMainBranch().createBranch("sub1");
+ CDOSession session2 = openSession();
+ CDOView controlView = openViewWithLockNotifications(session2, subBranch);
+ test(session1, controlView, false);
+ session1.close();
+ session2.close();
+ }
+
+ public void testDifferentBranchSameSession() throws CommitException
+ {
+ skipUnlessBranching();
+
+ CDOSession session1 = openSession();
+ CDOBranch subBranch = session1.getBranchManager().getMainBranch().createBranch("sub2");
+ CDOView controlView = openViewWithLockNotifications(session1, subBranch);
+ test(session1, controlView, false);
+ session1.close();
+ }
+
+ private void test(CDOSession session1, CDOView controlView, boolean mustReceiveNotifications) throws CommitException
+ {
+ CDOTransaction tx1 = session1.openTransaction();
+ CDOResource res1 = tx1.getOrCreateResource(getResourcePath("r1"));
+ LockEventListener listener1 = new LockEventListener();
+ tx1.addListener(listener1);
+ res1.getContents().clear();
+ Company company1 = getModel1Factory().createCompany();
+ res1.getContents().add(company1);
+ tx1.commit();
+
+ LockEventListener listener2 = new LockEventListener();
+ controlView.addListener(listener2);
+
+ CDOObject cdoCompany1 = CDOUtil.getCDOObject(company1);
+
+ /* Test write lock */
+
+ cdoCompany1.cdoWriteLock().lock();
+ if (mustReceiveNotifications)
+ {
+ listener2.waitFor(1);
+ assertEquals(1, listener2.getLockEvents().size());
+
+ CDOLocksChangedEvent event = listener2.getLockEvents().get(0);
+ assertLockOwner(tx1, event.getLockOwner());
+
+ CDOLockState[] lockStates = event.getLockStates();
+ assertEquals(1, lockStates.length);
+ assertLockedObject(cdoCompany1, lockStates[0].getLockedObject());
+ assertLockOwner(tx1, lockStates[0].getWriteLockOwner());
+ }
+
+ cdoCompany1.cdoWriteLock().unlock();
+ if (mustReceiveNotifications)
+ {
+ listener2.waitFor(2);
+
+ assertEquals(2, listener2.getLockEvents().size());
+
+ CDOLocksChangedEvent event = listener2.getLockEvents().get(1);
+ assertLockOwner(tx1, event.getLockOwner());
+
+ CDOLockState[] lockStates = event.getLockStates();
+ assertEquals(1, lockStates.length);
+ assertLockedObject(cdoCompany1, lockStates[0].getLockedObject());
+ assertNull(lockStates[0].getWriteLockOwner());
+ }
+
+ /* Test read lock */
+
+ cdoCompany1.cdoReadLock().lock();
+ if (mustReceiveNotifications)
+ {
+ listener2.waitFor(3);
+ assertEquals(3, listener2.getLockEvents().size());
+
+ CDOLocksChangedEvent event = listener2.getLockEvents().get(2);
+ assertLockOwner(tx1, event.getLockOwner());
+
+ CDOLockState[] lockStates = event.getLockStates();
+ assertEquals(1, lockStates.length);
+ assertLockedObject(cdoCompany1, lockStates[0].getLockedObject());
+ assertEquals(1, lockStates[0].getReadLockOwners().size());
+ CDOLockOwner tx1Lo = CDOLockUtil.createLockOwner(tx1);
+ assertEquals(true, lockStates[0].getReadLockOwners().contains(tx1Lo));
+ }
+
+ cdoCompany1.cdoReadLock().unlock();
+ if (mustReceiveNotifications)
+ {
+ listener2.waitFor(4);
+
+ assertEquals(4, listener2.getLockEvents().size());
+
+ CDOLocksChangedEvent event = listener2.getLockEvents().get(3);
+ assertLockOwner(tx1, event.getLockOwner());
+
+ CDOLockState[] lockStates = event.getLockStates();
+ assertEquals(1, lockStates.length);
+ assertEquals(0, lockStates[0].getReadLockOwners().size());
+ }
+
+ /* Test write option */
+
+ cdoCompany1.cdoWriteOption().lock();
+ if (mustReceiveNotifications)
+ {
+ listener2.waitFor(5);
+ assertEquals(5, listener2.getLockEvents().size());
+
+ CDOLocksChangedEvent event = listener2.getLockEvents().get(4);
+ assertLockOwner(tx1, event.getLockOwner());
+
+ CDOLockState[] lockStates = event.getLockStates();
+ assertEquals(1, lockStates.length);
+ assertLockedObject(cdoCompany1, lockStates[0].getLockedObject());
+ assertLockOwner(tx1, lockStates[0].getWriteOptionOwner());
+ }
+
+ cdoCompany1.cdoWriteOption().unlock();
+ if (mustReceiveNotifications)
+ {
+ listener2.waitFor(6);
+
+ assertEquals(6, listener2.getLockEvents().size());
+
+ CDOLocksChangedEvent event = listener2.getLockEvents().get(5);
+ assertLockOwner(tx1, event.getLockOwner());
+
+ CDOLockState[] lockStates = event.getLockStates();
+ assertEquals(1, lockStates.length);
+ assertLockedObject(cdoCompany1, lockStates[0].getLockedObject());
+ assertNull(lockStates[0].getWriteOptionOwner());
+ }
+
+ assertEquals(0, listener1.getLockEvents().size());
+
+ if (!mustReceiveNotifications)
+ {
+ assertEquals(0, listener2.getLockEvents().size());
+ }
+ }
+
+ private void assertLockedObject(CDOObject obj, Object lockedObject)
+ {
+ if (lockedObject instanceof CDOIDAndBranch)
+ {
+ CDOIDAndBranch idAndBranch = CDOIDUtil.createIDAndBranch(obj.cdoID(), obj.cdoView().getBranch());
+ assertEquals(idAndBranch, lockedObject);
+ }
+ else if (lockedObject instanceof CDOID)
+ {
+ assertEquals(obj.cdoID(), lockedObject);
+ }
+ }
+
+ private void assertLockOwner(CDOView view, CDOLockOwner lockOwner)
+ {
+ CDOLockOwner lo = CDOLockUtil.createLockOwner(view);
+ assertEquals(lo, lockOwner);
+ }
+
+ /**
+ * @author Caspar De Groot
+ */
+ private final class LockEventListener implements IListener
+ {
+ private List<CDOLocksChangedEvent> lockEvents = new LinkedList<CDOLocksChangedEvent>();
+
+ public synchronized void notifyEvent(IEvent event)
+ {
+ if (event instanceof CDOLocksChangedEvent)
+ {
+ lockEvents.add((CDOLocksChangedEvent)event);
+ notify();
+ }
+ }
+
+ public List<CDOLocksChangedEvent> getLockEvents()
+ {
+ return lockEvents;
+ }
+
+ public synchronized void waitFor(int n)
+ {
+ long timeout = 2000;
+ long t = 0;
+ while (lockEvents.size() < n)
+ {
+ if (timeout <= 0)
+ {
+ fail("Timed out");
+ }
+ try
+ {
+ t = System.currentTimeMillis();
+ wait(timeout);
+ }
+ catch (InterruptedException ex)
+ {
+ }
+ timeout -= System.currentTimeMillis() - t;
+ }
+ }
+ }
+
+ public void testEnableDisableNotifications() throws CommitException
+ {
+ CDOSession session1 = openSession();
+ CDOSession session2 = openSession();
+ CDOView controlView = session2.openView();
+ test(session1, controlView, false);
+
+ controlView.options().setLockNotificationEnabled(true);
+ test(session1, controlView, true);
+
+ controlView.options().setLockNotificationEnabled(false);
+ test(session1, controlView, false);
+
+ session1.close();
+ session2.close();
+ }
+
+ public void testLockStateHeldByDurableView() throws CommitException
+ {
+ {
+ CDOSession session1 = openSession();
+ CDOTransaction tx1 = session1.openTransaction();
+ tx1.enableDurableLocking(true);
+ 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());
+ assertSame(CDOLockOwner.UNKNOWN, cdoObj.cdoLockState().getWriteLockOwner());
+ 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);
+ assertNull(cdoObj.cdoLockState());
+
+ tx1.commit();
+ assertClean(cdoObj, tx1);
+ assertNotNull(cdoObj.cdoLockState());
+
+ res1.getContents().add(company1);
+ tx1.commit();
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineLockingTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineLockingTest.java
new file mode 100644
index 0000000..250fa7c
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineLockingTest.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2004 - 2011 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.offline;
+
+import org.eclipse.emf.cdo.CDOObject;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.tests.AbstractSyncingTest;
+import org.eclipse.emf.cdo.tests.model1.Company;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.CDOUtil;
+import org.eclipse.emf.cdo.view.CDOView;
+
+/**
+ * @author Caspar De Groot
+ */
+public class OfflineLockingTest extends AbstractSyncingTest
+{
+ public void testLockAndUnlockThrough() throws Exception
+ {
+ // InternalRepository clone = getRepository();
+ // InternalRepository master = getRepository(clone.getName() + "_master");
+
+ CDOSession masterSession = openSession(getRepository().getName() + "_master");
+ // CDOTransaction masterTx = masterSession.openTransaction();
+
+ CDOSession cloneSession = openSession();
+ waitForOnline(cloneSession.getRepositoryInfo());
+
+ CDOTransaction cloneTx = cloneSession.openTransaction();
+ cloneTx.enableDurableLocking(true);
+
+ CDOResource res = cloneTx.createResource(getResourcePath("test"));
+ Company company = getModel1Factory().createCompany();
+ res.getContents().add(company);
+ cloneTx.commit();
+
+ CDOObject cdoCompany = CDOUtil.getCDOObject(company);
+ cdoCompany.cdoWriteLock().lock();
+
+ CDOView masterView = masterSession.openView();
+ CDOObject cdoCompanyOnMaster = masterView.getObject(cdoCompany.cdoID());
+ assertEquals(true, cdoCompanyOnMaster.cdoWriteLock().isLockedByOthers());
+
+ // int viewID = cloneTx.getViewID();
+ // master.getLockManager().hasLock(LockType.WRITE, context, objectToLock);
+
+ cdoCompany.cdoWriteLock().unlock();
+ assertEquals(false, cdoCompanyOnMaster.cdoWriteLock().isLockedByOthers());
+
+ cloneSession.close();
+ masterSession.close();
+ }
+
+ public void testMasterLocks_ArrivalInClone() throws Exception
+ {
+
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo/.settings/.api_filters b/plugins/org.eclipse.emf.cdo/.settings/.api_filters
index 43d0cb2..c9ee689 100644
--- a/plugins/org.eclipse.emf.cdo/.settings/.api_filters
+++ b/plugins/org.eclipse.emf.cdo/.settings/.api_filters
@@ -4,6 +4,12 @@
<filter id="403804204">
<message_arguments>
<message_argument value="org.eclipse.emf.cdo.CDOObject"/>
+ <message_argument value="cdoLockState()"/>
+ </message_arguments>
+ </filter>
+ <filter id="403804204">
+ <message_arguments>
+ <message_argument value="org.eclipse.emf.cdo.CDOObject"/>
<message_argument value="cdoWriteOption()"/>
</message_arguments>
</filter>
@@ -85,6 +91,20 @@
</message_arguments>
</filter>
</resource>
+ <resource path="src/org/eclipse/emf/cdo/view/CDOLocksChangedEvent.java" type="org.eclipse.emf.cdo.view.CDOLocksChangedEvent">
+ <filter id="571473929">
+ <message_arguments>
+ <message_argument value="CDOBranchPoint"/>
+ <message_argument value="CDOLocksChangedEvent"/>
+ </message_arguments>
+ </filter>
+ <filter id="571473929">
+ <message_arguments>
+ <message_argument value="CDOLockChangeInfo"/>
+ <message_argument value="CDOLocksChangedEvent"/>
+ </message_arguments>
+ </filter>
+ </resource>
<resource path="src/org/eclipse/emf/cdo/view/CDOQuery.java" type="org.eclipse.emf.cdo.view.CDOQuery">
<filter id="571473929">
<message_arguments>
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOObject.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOObject.java
index 24e65bf..c08fc07 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOObject.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOObject.java
@@ -13,6 +13,7 @@ package org.eclipse.emf.cdo;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDTemp;
import org.eclipse.emf.cdo.common.id.CDOWithID;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionManager;
import org.eclipse.emf.cdo.eresource.CDOResource;
@@ -141,6 +142,13 @@ public interface CDOObject extends EObject, CDOWithID
public CDOLock cdoWriteOption();
/**
+ * Returns the {@link CDOLockState} of this object.
+ *
+ * @since 4.1
+ */
+ public CDOLockState cdoLockState();
+
+ /**
* Ensures that the revisions of the contained objects up to the given depth are in the local
* {@link CDORevisionManager revision cache}. Subsequent access to the respective contained objects will not lead to
* server round-trips after calling this method.
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOLocksChangedEvent.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOLocksChangedEvent.java
new file mode 100644
index 0000000..904dabb
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOLocksChangedEvent.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2004 - 2011 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.view;
+
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
+
+/**
+ * A {@link CDOViewEvent view event} fired when lock notifications are being received from a repository.
+ * {@link CDOView.Options#setLockNotificationEnabled(boolean)} must be enabled for this event to be fired.
+ *
+ * @author Caspar De Groot
+ * @since 4.1
+ */
+public interface CDOLocksChangedEvent extends CDOViewEvent, CDOLockChangeInfo
+{
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOView.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOView.java
index bfe7d06..4d74a8f 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOView.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOView.java
@@ -21,6 +21,7 @@ import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.commit.CDOChangeSetData;
import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.util.CDOException;
import org.eclipse.emf.cdo.eresource.CDOResource;
@@ -34,6 +35,7 @@ import org.eclipse.emf.cdo.util.ReadOnlyException;
import org.eclipse.net4j.util.collection.CloseableIterator;
import org.eclipse.net4j.util.concurrent.IRWLockManager;
import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+import org.eclipse.net4j.util.event.IListener;
import org.eclipse.net4j.util.event.INotifier;
import org.eclipse.net4j.util.options.IOptions;
import org.eclipse.net4j.util.options.IOptionsContainer;
@@ -466,6 +468,27 @@ public interface CDOView extends CDOCommonView, CDOUpdatable, INotifier, IOption
public void setInvalidationNotificationEnabled(boolean enabled);
/**
+ * Returns <code>true</code> if this view will notify its {@link IListener listeners} about changes to the
+ * {@link CDOLockState lock states} of the objects in this view (due to lock operations in <i>other</i> views),
+ * <code>false</code> otherwise.
+ *
+ * @see CDOLocksChangedEvent
+ * @see CDOLockState
+ * @since 4.1
+ */
+ public boolean isLockNotificationEnabled();
+
+ /**
+ * Specifies whether this view will notify its {@link IListener listeners} about changes to the {@link CDOLockState
+ * lock states} of the objects in this view (due to lock operations in <i>other</i> views), or not.
+ *
+ * @see CDOLocksChangedEvent
+ * @see CDOLockState
+ * @since 4.1
+ */
+ public void setLockNotificationEnabled(boolean enabled);
+
+ /**
* Returns the current set of {@link CDOAdapterPolicy change subscription policies}.
*
* @return The current set of change subscription policies, never <code>null</code>.
@@ -646,6 +669,14 @@ public interface CDOView extends CDOCommonView, CDOUpdatable, INotifier, IOption
}
/**
+ * @author Caspar De Groot
+ * @since 4.1
+ */
+ public interface LockNotificationEvent extends IOptionsEvent
+ {
+ }
+
+ /**
* An {@link IOptionsEvent options event} fired from view {@link CDOView#options() options} when the
* {@link Options#setRevisionPrefetchingPolicy(CDORevisionPrefetchingPolicy) revision prefetching policy} option has
* changed.
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java
index e2e2aa0..ffe5f92 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java
@@ -15,6 +15,7 @@ import org.eclipse.emf.cdo.CDOLock;
import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.CDOState;
import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.model.EMFUtil;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.eresource.CDOResource;
@@ -63,6 +64,7 @@ import org.eclipse.emf.spi.cdo.InternalCDOObject;
import org.eclipse.emf.spi.cdo.InternalCDOView;
import java.util.Collection;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
@@ -84,6 +86,8 @@ public class CDOObjectImpl extends EStoreEObjectImpl implements InternalCDOObjec
private InternalCDORevision revision;
+ private CDOLockState lockState;
+
/**
* CDO uses this list instead of eSettings for transient objects. EMF uses eSettings as cache. CDO deactivates the
* cache but EMF still used eSettings to store list wrappers. CDO needs another place to store the real list with the
@@ -184,17 +188,7 @@ public class CDOObjectImpl extends EStoreEObjectImpl implements InternalCDOObjec
*/
public CDOLock cdoReadLock()
{
- if (FSMUtil.isTransient(this))
- {
- throw new IllegalStateException("Call CDOView.lockObjects() for transient object " + this);
- }
-
- if (FSMUtil.isNew(this))
- {
- return CDOLockImpl.NOOP;
- }
-
- return new CDOLockImpl(this, LockType.READ);
+ return createCDOLock(LockType.READ);
}
/**
@@ -202,6 +196,19 @@ public class CDOObjectImpl extends EStoreEObjectImpl implements InternalCDOObjec
*/
public CDOLock cdoWriteLock()
{
+ return createCDOLock(LockType.WRITE);
+ }
+
+ /**
+ * @since 4.1
+ */
+ public CDOLock cdoWriteOption()
+ {
+ return createCDOLock(LockType.OPTION);
+ }
+
+ private CDOLock createCDOLock(LockType type)
+ {
if (FSMUtil.isTransient(this))
{
throw new IllegalStateException("Call CDOView.lockObjects() for transient object " + this);
@@ -212,25 +219,31 @@ public class CDOObjectImpl extends EStoreEObjectImpl implements InternalCDOObjec
return CDOLockImpl.NOOP;
}
- return new CDOLockImpl(this, LockType.WRITE);
+ return new CDOLockImpl(this, type);
}
/**
* @since 4.1
*/
- public CDOLock cdoWriteOption()
+ public synchronized CDOLockState cdoLockState()
{
- if (FSMUtil.isTransient(this))
+ if (lockState == null)
{
- throw new IllegalStateException("Call CDOView.lockObjects() for transient object " + this);
+ if (!FSMUtil.isTransient(this) && !FSMUtil.isNew(this))
+ {
+ lockState = view.getLockStates(Collections.singletonList(id))[0];
+ }
}
- if (FSMUtil.isNew(this))
- {
- return CDOLockImpl.NOOP;
- }
+ return lockState;
+ }
- return new CDOLockImpl(this, LockType.OPTION);
+ /**
+ * @since 4.1
+ */
+ public synchronized void cdoInternalSetLockState(CDOLockState lockState)
+ {
+ this.lockState = lockState;
}
public void cdoInternalSetID(CDOID id)
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java
index 3678c01..e0be183 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java
@@ -14,6 +14,7 @@ package org.eclipse.emf.internal.cdo.object;
import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.CDOState;
import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.model.CDOModelUtil;
import org.eclipse.emf.cdo.common.model.CDOPackageRegistry;
import org.eclipse.emf.cdo.common.model.CDOType;
@@ -57,6 +58,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -95,6 +97,8 @@ public abstract class CDOLegacyWrapper extends CDOObjectWrapper
protected InternalCDORevision revision;
+ protected CDOLockState lockState;
+
/**
* It could happen that while <i>revisionToInstance()</i> is executed externally the <i>internalPostLoad()</i> method
* will be called. This happens for example if <i>internalPostInvalidate()</i> is called. The leads to another
@@ -121,6 +125,24 @@ public abstract class CDOLegacyWrapper extends CDOObjectWrapper
return revision;
}
+ public synchronized CDOLockState cdoLockState()
+ {
+ if (lockState == null)
+ {
+ if (!FSMUtil.isTransient(this) && !FSMUtil.isNew(this))
+ {
+ lockState = view.getLockStates(Collections.singletonList(id))[0];
+ }
+ }
+
+ return lockState;
+ }
+
+ public synchronized void cdoInternalSetLockState(CDOLockState lockState)
+ {
+ this.lockState = lockState;
+ }
+
@Override
public CDOResourceImpl cdoResource()
{
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLockImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLockImpl.java
index 851c0a1..d161642 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLockImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLockImpl.java
@@ -12,6 +12,8 @@
package org.eclipse.emf.internal.cdo.object;
import org.eclipse.emf.cdo.CDOLock;
+import org.eclipse.emf.cdo.common.lock.CDOLockOwner;
+import org.eclipse.emf.cdo.common.lock.CDOLockUtil;
import org.eclipse.emf.cdo.util.LockTimeoutException;
import org.eclipse.net4j.util.WrappedException;
@@ -33,14 +35,17 @@ public class CDOLockImpl implements CDOLock
{
public static final CDOLock NOOP = new NOOPLockImpl();
- private InternalCDOObject object;
+ private final InternalCDOObject object;
- private LockType type;
+ private final LockType type;
+
+ private final CDOLockOwner owner;
public CDOLockImpl(InternalCDOObject object, LockType type)
{
this.object = object;
this.type = type;
+ owner = CDOLockUtil.createLockOwner(object.cdoView());
}
public LockType getType()
@@ -50,7 +55,7 @@ public class CDOLockImpl implements CDOLock
public boolean isLocked()
{
- return object.cdoView().isObjectLocked(object, type, false);
+ return object.cdoLockState().isLocked(type, owner, false);
}
/**
@@ -58,7 +63,7 @@ public class CDOLockImpl implements CDOLock
*/
public boolean isLockedByOthers()
{
- return object.cdoView().isObjectLocked(object, type, true);
+ return object.cdoLockState().isLocked(type, owner, true);
}
public void lock()
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java
index 4a39ec7..293f899 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java
@@ -27,6 +27,7 @@ import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDGenerator;
import org.eclipse.emf.cdo.common.lob.CDOLobInfo;
import org.eclipse.emf.cdo.common.lob.CDOLobStore;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
import org.eclipse.emf.cdo.common.model.EMFUtil;
import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator;
@@ -89,6 +90,7 @@ import org.eclipse.net4j.util.WrappedException;
import org.eclipse.net4j.util.collection.Pair;
import org.eclipse.net4j.util.concurrent.IRWLockManager;
import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+import org.eclipse.net4j.util.concurrent.IRWOLockManager;
import org.eclipse.net4j.util.concurrent.RWOLockManager;
import org.eclipse.net4j.util.event.Event;
import org.eclipse.net4j.util.event.EventUtil;
@@ -183,7 +185,7 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme
}
};
- private IRWLockManager<CDOSessionImpl, Object> lockManager = new RWOLockManager<CDOSessionImpl, Object>();
+ private IRWOLockManager<CDOSessionImpl, Object> lockManager = new RWOLockManager<CDOSessionImpl, Object>();
@ExcludeFromDump
private Set<CDOSessionImpl> singletonCollection = Collections.singleton(this);
@@ -715,17 +717,48 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme
public boolean waitForUpdate(long updateTime, long timeoutMillis)
{
long end = timeoutMillis == NO_TIMEOUT ? Long.MAX_VALUE : System.currentTimeMillis() + timeoutMillis;
- for (CDOView view : getViews())
+ InternalCDOView views[] = getViews();
+ if (views.length > 0)
{
- long viewTimeoutMillis = timeoutMillis == NO_TIMEOUT ? NO_TIMEOUT : end - System.currentTimeMillis();
- boolean ok = view.waitForUpdate(updateTime, viewTimeoutMillis);
- if (!ok)
+ for (CDOView view : views)
{
- return false;
+ long viewTimeoutMillis = timeoutMillis == NO_TIMEOUT ? NO_TIMEOUT : end - System.currentTimeMillis();
+ boolean ok = view.waitForUpdate(updateTime, viewTimeoutMillis);
+ if (!ok)
+ {
+ return false;
+ }
}
+
+ return true;
}
- return true;
+ // Session without views
+ for (;;)
+ {
+ synchronized (lastUpdateTimeLock)
+ {
+ if (lastUpdateTime >= updateTime)
+ {
+ return true;
+ }
+
+ long now = System.currentTimeMillis();
+ if (now >= end)
+ {
+ return false;
+ }
+
+ try
+ {
+ lastUpdateTimeLock.wait(end - now);
+ }
+ catch (InterruptedException ex)
+ {
+ throw WrappedException.wrap(ex);
+ }
+ }
+ }
}
/**
@@ -803,6 +836,14 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme
}
}
+ public void handleLockNotification(CDOLockChangeInfo lockChangeInfo)
+ {
+ for (InternalCDOView view : getViews())
+ {
+ view.handleLockNotification(lockChangeInfo);
+ }
+ }
+
private void registerPackageUnits(List<CDOPackageUnit> packageUnits)
{
InternalCDOPackageRegistry packageRegistry = getPackageRegistry();
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java
index 875a771..c88715a 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java
@@ -24,6 +24,7 @@ import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDProvider;
import org.eclipse.emf.cdo.common.lob.CDOLob;
import org.eclipse.emf.cdo.common.lob.CDOLobInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
@@ -384,6 +385,38 @@ public class DelegatingSessionProtocol extends Lifecycle implements CDOSessionPr
}
}
+ public CDOLockState[] getLockStates(int viewID, Collection<CDOID> ids)
+ {
+ int attempt = 0;
+ for (;;)
+ {
+ try
+ {
+ return delegate.getLockStates(viewID, ids);
+ }
+ catch (Exception ex)
+ {
+ handleException(++attempt, ex);
+ }
+ }
+ }
+
+ public void enableLockNotifications(int viewID, boolean enable)
+ {
+ int attempt = 0;
+ for (;;)
+ {
+ try
+ {
+ delegate.enableLockNotifications(viewID, enable);
+ }
+ catch (Exception ex)
+ {
+ handleException(++attempt, ex);
+ }
+ }
+ }
+
public boolean isObjectLocked(CDOView view, CDOObject object, LockType lockType, boolean byOthers)
{
int attempt = 0;
@@ -579,6 +612,7 @@ public class DelegatingSessionProtocol extends Lifecycle implements CDOSessionPr
}
}
+ @Deprecated
public LockObjectsResult lockObjects(List<InternalCDORevision> viewedRevisions, int viewID, CDOBranch viewedBranch,
LockType lockType, long timeout) throws InterruptedException
{
@@ -596,6 +630,60 @@ public class DelegatingSessionProtocol extends Lifecycle implements CDOSessionPr
}
}
+ /**
+ * @since 4.1
+ */
+ public LockObjectsResult lockObjects2(List<CDORevisionKey> revisionKeys, int viewID, CDOBranch viewedBranch,
+ LockType lockType, long timeout) throws InterruptedException
+
+ {
+ int attempt = 0;
+ for (;;)
+ {
+ try
+ {
+ return delegate.lockObjects2(revisionKeys, viewID, viewedBranch, lockType, timeout);
+ }
+ catch (Exception ex)
+ {
+ handleException(++attempt, ex);
+ }
+ }
+ }
+
+ public LockObjectsResult delegateLockObjects(String lockAreaID, List<CDORevisionKey> revisionKeys,
+ CDOBranch viewedBranch, LockType lockType, long timeout) throws InterruptedException
+ {
+ int attempt = 0;
+ for (;;)
+ {
+ try
+ {
+ return delegate.delegateLockObjects(lockAreaID, revisionKeys, viewedBranch, lockType, timeout);
+ }
+ catch (Exception ex)
+ {
+ handleException(++attempt, ex);
+ }
+ }
+ }
+
+ public UnlockObjectsResult delegateUnlockObjects(String lockAreaID, Collection<CDOID> objectIDs, LockType lockType)
+ {
+ int attempt = 0;
+ for (;;)
+ {
+ try
+ {
+ return delegate.delegateUnlockObjects(lockAreaID, objectIDs, lockType);
+ }
+ catch (Exception ex)
+ {
+ handleException(++attempt, ex);
+ }
+ }
+ }
+
public void query(CDOView view, AbstractQueryIterator<?> queryResult)
{
int attempt = 0;
@@ -665,14 +753,14 @@ public class DelegatingSessionProtocol extends Lifecycle implements CDOSessionPr
}
}
- public void unlockObjects(CDOView view, Collection<? extends CDOObject> objects, LockType lockType)
+ public void unlockObjects(CDOView view, Collection<CDOID> objectIDs, LockType lockType)
{
int attempt = 0;
for (;;)
{
try
{
- delegate.unlockObjects(view, objects, lockType);
+ delegate.unlockObjects(view, objectIDs, lockType);
return;
}
catch (Exception ex)
@@ -682,6 +770,22 @@ public class DelegatingSessionProtocol extends Lifecycle implements CDOSessionPr
}
}
+ public UnlockObjectsResult unlockObjects2(CDOView view, Collection<CDOID> objectIDs, LockType lockType)
+ {
+ int attempt = 0;
+ for (;;)
+ {
+ try
+ {
+ return delegate.unlockObjects2(view, objectIDs, lockType);
+ }
+ catch (Exception ex)
+ {
+ handleException(++attempt, ex);
+ }
+ }
+ }
+
public List<CDORemoteSession> getRemoteSessions(InternalCDORemoteSessionManager manager, boolean subscribe)
{
int attempt = 0;
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java
index 0968432..2f81f19 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java
@@ -34,6 +34,7 @@ import org.eclipse.emf.cdo.common.id.CDOIDTemp;
import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.common.lob.CDOLob;
import org.eclipse.emf.cdo.common.lob.CDOLobStore;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.model.CDOModelUtil;
import org.eclipse.emf.cdo.common.model.CDOPackageRegistry;
import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
@@ -2625,6 +2626,12 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa
fireEvent(new FinishedEvent(CDOTransactionFinishedEvent.Type.COMMITTED, idMappings), listeners);
}
+
+ CDOLockState[] newLockStates = result.getNewLockStates();
+ if (newLockStates != null)
+ {
+ updateLockStates(newLockStates);
+ }
}
catch (RuntimeException ex)
{
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java
index 5f4d77d..7e69345 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java
@@ -18,6 +18,11 @@ import org.eclipse.emf.cdo.CDOState;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
+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.common.revision.CDOIDAndVersion;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
@@ -36,6 +41,7 @@ import org.eclipse.emf.cdo.util.StaleRevisionLockException;
import org.eclipse.emf.cdo.view.CDOAdapterPolicy;
import org.eclipse.emf.cdo.view.CDOFeatureAnalyzer;
import org.eclipse.emf.cdo.view.CDOInvalidationPolicy;
+import org.eclipse.emf.cdo.view.CDOLocksChangedEvent;
import org.eclipse.emf.cdo.view.CDORevisionPrefetchingPolicy;
import org.eclipse.emf.cdo.view.CDOStaleReferencePolicy;
import org.eclipse.emf.cdo.view.CDOView;
@@ -75,6 +81,7 @@ import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.spi.cdo.CDOSessionProtocol;
import org.eclipse.emf.spi.cdo.CDOSessionProtocol.LockObjectsResult;
+import org.eclipse.emf.spi.cdo.CDOSessionProtocol.UnlockObjectsResult;
import org.eclipse.emf.spi.cdo.FSMUtil;
import org.eclipse.emf.spi.cdo.InternalCDOObject;
import org.eclipse.emf.spi.cdo.InternalCDOSession;
@@ -257,18 +264,18 @@ public class CDOViewImpl extends AbstractCDOView
checkActive();
checkState(getTimeStamp() == CDOBranchPoint.UNSPECIFIED_DATE, "Locking not supported for historial views");
- List<InternalCDORevision> revisions = new LinkedList<InternalCDORevision>();
+ List<CDORevisionKey> revisionKeys = new LinkedList<CDORevisionKey>();
for (CDOObject object : objects)
{
InternalCDORevision revision = getRevision(object);
if (revision != null)
{
- revisions.add(revision);
+ revisionKeys.add(revision);
}
}
CDOSessionProtocol sessionProtocol = session.getSessionProtocol();
- LockObjectsResult result = sessionProtocol.lockObjects(revisions, viewID, getBranch(), lockType, timeout);
+ LockObjectsResult result = sessionProtocol.lockObjects2(revisionKeys, viewID, getBranch(), lockType, timeout);
if (!result.isSuccessful())
{
@@ -286,6 +293,8 @@ public class CDOViewImpl extends AbstractCDOView
throw new AssertionError("Unexpected lock result state");
}
+ updateLockStates(result.getNewLockStates());
+
if (result.isWaitForUpdate())
{
if (!getSession().options().isPassiveUpdateEnabled())
@@ -299,6 +308,29 @@ public class CDOViewImpl extends AbstractCDOView
}
}
+ protected void updateLockStates(CDOLockState[] newLockStates)
+ {
+ for (CDOLockState lockState : newLockStates)
+ {
+ Object o = lockState.getLockedObject();
+ CDOID id;
+ if (o instanceof CDOID)
+ {
+ id = (CDOID)o;
+ }
+ else
+ {
+ id = ((CDOIDAndBranch)o).getID();
+ }
+
+ InternalCDOObject obj = getObject(id, false);
+ if (obj != null)
+ {
+ obj.cdoInternalSetLockState(lockState);
+ }
+ }
+ }
+
protected InternalCDORevision getRevision(CDOObject object)
{
if (object.cdoState() == CDOState.NEW)
@@ -321,8 +353,21 @@ public class CDOViewImpl extends AbstractCDOView
public synchronized void unlockObjects(Collection<? extends CDOObject> objects, LockType lockType)
{
checkActive();
+
+ List<CDOID> objectIDs = null;
+ if (objects != null)
+ {
+ objectIDs = new LinkedList<CDOID>();
+ for (CDOObject obj : objects)
+ {
+ objectIDs.add(obj.cdoID());
+ }
+ }
+
CDOSessionProtocol sessionProtocol = session.getSessionProtocol();
- sessionProtocol.unlockObjects(this, objects, lockType);
+ UnlockObjectsResult result = sessionProtocol.unlockObjects2(this, objectIDs, lockType);
+
+ updateLockStates(result.getNewLockStates());
}
/**
@@ -439,6 +484,13 @@ public class CDOViewImpl extends AbstractCDOView
return revisionManager.getRevision(id, branchPoint, initialChunkSize, CDORevision.DEPTH_NONE, loadOnDemand);
}
+ public CDOLockState[] getLockStates(Collection<CDOID> ids)
+ {
+ CDOSessionProtocol sessionProtocol = session.getSessionProtocol();
+ CDOLockState[] lockStates = sessionProtocol.getLockStates(viewID, ids);
+ return lockStates;
+ }
+
private CDOBranchPoint getBranchPointForID(CDOID id)
{
// If this view's timestamp is something other than UNSPECIFIED_DATE,
@@ -876,6 +928,38 @@ public class CDOViewImpl extends AbstractCDOView
}
}
+ public void handleLockNotification(CDOLockChangeInfo lockChangeInfo)
+ {
+ if (!options().isLockNotificationEnabled())
+ {
+ return;
+ }
+
+ // If lockChangeInfo pertains to a different view, do nothing.
+ if (!lockChangeInfo.getBranch().equals(getBranch()))
+ {
+ return;
+ }
+
+ // If lockChangeInfo represents lock changes authored by this view itself, do nothing.
+ CDOLockOwner thisView = CDOLockUtil.createLockOwner(this);
+ if (lockChangeInfo.getLockOwner().equals(thisView))
+ {
+ return;
+ }
+
+ fireLocksChangedEvent(lockChangeInfo);
+ }
+
+ private void fireLocksChangedEvent(CDOLockChangeInfo lockChangeInfo)
+ {
+ IListener[] listeners = getListeners();
+ if (listeners != null)
+ {
+ fireEvent(new LocksChangedEvent(lockChangeInfo), listeners);
+ }
+ }
+
/**
* @author Simon McDuff
* @since 2.0
@@ -1304,6 +1388,47 @@ public class CDOViewImpl extends AbstractCDOView
}
/**
+ * @author Caspar De Groot
+ * @since 4.1
+ */
+ private final class LocksChangedEvent extends Event implements CDOLocksChangedEvent
+ {
+ private static final long serialVersionUID = 1L;
+
+ private CDOLockChangeInfo lockChangeInfo;
+
+ public LocksChangedEvent(CDOLockChangeInfo lockChangeInfo)
+ {
+ this.lockChangeInfo = lockChangeInfo;
+ }
+
+ public CDOBranch getBranch()
+ {
+ return lockChangeInfo.getBranch();
+ }
+
+ public long getTimeStamp()
+ {
+ return lockChangeInfo.getTimeStamp();
+ }
+
+ public CDOLockOwner getLockOwner()
+ {
+ return lockChangeInfo.getLockOwner();
+ }
+
+ public CDOLockState[] getLockStates()
+ {
+ return lockChangeInfo.getLockStates();
+ }
+
+ public Operation getOperation()
+ {
+ return lockChangeInfo.getOperation();
+ }
+ }
+
+ /**
* @author Eike Stepper
* @since 2.0
*/
@@ -1313,6 +1438,8 @@ public class CDOViewImpl extends AbstractCDOView
private CDOInvalidationPolicy invalidationPolicy = CDOInvalidationPolicy.DEFAULT;
+ private boolean lockNotificationsEnabled;
+
private CDORevisionPrefetchingPolicy revisionPrefetchingPolicy = CDOUtil
.createRevisionPrefetchingPolicy(NO_REVISION_PREFETCHING);
@@ -1378,6 +1505,28 @@ public class CDOViewImpl extends AbstractCDOView
fireEvent(event);
}
+ public boolean isLockNotificationEnabled()
+ {
+ return lockNotificationsEnabled;
+ }
+
+ public void setLockNotificationEnabled(boolean enabled)
+ {
+ IEvent event = null;
+ synchronized (CDOViewImpl.this)
+ {
+ if (enabled != lockNotificationsEnabled)
+ {
+ CDOSessionProtocol protocol = getSession().getSessionProtocol();
+ protocol.enableLockNotifications(viewID, enabled);
+ lockNotificationsEnabled = enabled;
+ event = new LockNotificationEventImpl();
+ }
+ }
+
+ fireEvent(event);
+ }
+
public boolean hasChangeSubscriptionPolicies()
{
synchronized (CDOViewImpl.this)
@@ -1662,6 +1811,19 @@ public class CDOViewImpl extends AbstractCDOView
}
/**
+ * @author Caspar De Groot
+ */
+ private final class LockNotificationEventImpl extends OptionsEvent implements LockNotificationEvent
+ {
+ private static final long serialVersionUID = 1L;
+
+ public LockNotificationEventImpl()
+ {
+ super(OptionsImpl.this);
+ }
+ }
+
+ /**
* @author Eike Stepper
*/
private final class RevisionPrefetchingPolicyEventImpl extends OptionsEvent implements
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java
index 1032720..fdfc911 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java
@@ -24,6 +24,7 @@ import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDProvider;
import org.eclipse.emf.cdo.common.lob.CDOLob;
import org.eclipse.emf.cdo.common.lob.CDOLobInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
import org.eclipse.emf.cdo.common.protocol.CDOProtocol;
import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
@@ -45,6 +46,7 @@ import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager.RevisionLoader;
import org.eclipse.emf.cdo.view.CDOView;
+import org.eclipse.net4j.util.CheckUtil;
import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
import org.eclipse.net4j.util.om.monitor.OMMonitor;
@@ -131,15 +133,41 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo
public boolean cancelQuery(int queryId);
/**
+ * Use #lockObjects2 instead.
+ *
* @since 4.0
+ * @deprecated Not called anymore.
*/
+ @Deprecated
public LockObjectsResult lockObjects(List<InternalCDORevision> viewedRevisions, int viewID, CDOBranch viewedBranch,
LockType lockType, long timeout) throws InterruptedException;
/**
+ * @since 4.1
+ */
+ public LockObjectsResult lockObjects2(List<CDORevisionKey> revisionKeys, int viewID, CDOBranch viewedBranch,
+ LockType lockType, long timeout) throws InterruptedException;
+
+ /**
+ * @since 4.1
+ */
+ public LockObjectsResult delegateLockObjects(String lockAreaID, List<CDORevisionKey> revisionKeys,
+ CDOBranch viewedBranch, LockType lockType, long timeout) throws InterruptedException;
+
+ /**
* @since 3.0
*/
- public void unlockObjects(CDOView view, Collection<? extends CDOObject> objects, LockType lockType);
+ public void unlockObjects(CDOView view, Collection<CDOID> objectIDs, LockType lockType);
+
+ /**
+ * @since 4.1
+ */
+ public UnlockObjectsResult unlockObjects2(CDOView view, Collection<CDOID> objectIDs, LockType lockType);
+
+ /**
+ * @since 4.1
+ */
+ public UnlockObjectsResult delegateUnlockObjects(String lockAreaID, Collection<CDOID> objectIDs, LockType lockType);
/**
* @since 3.0
@@ -233,6 +261,16 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo
CDORevisionHandler handler);
/**
+ * @since 4.1
+ */
+ public CDOLockState[] getLockStates(int viewID, Collection<CDOID> ids);
+
+ /**
+ * @since 4.1
+ */
+ public void enableLockNotifications(int viewID, boolean enable);
+
+ /**
* @author Eike Stepper
* @since 3.0
* @noinstantiate This class is not intended to be instantiated by clients.
@@ -606,6 +644,8 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo
private CDOReferenceAdjuster referenceAdjuster;
+ private CDOLockState[] newLockStates;
+
/**
* @since 4.0
*/
@@ -697,6 +737,14 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo
idMappings.put(oldID, newID);
}
+ /**
+ * @since 4.1
+ */
+ public CDOLockState[] getNewLockStates()
+ {
+ return newLockStates;
+ }
+
protected PostCommitReferenceAdjuster createReferenceAdjuster()
{
return new PostCommitReferenceAdjuster(idProvider, new CDOIDMapper(idMappings));
@@ -735,6 +783,15 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo
return idMapper.adjustReference(id, feature, index);
}
}
+
+ /**
+ * @since 4.1
+ */
+ public void setNewLockStates(CDOLockState[] newLockStates)
+ {
+ CheckUtil.checkArg(newLockStates, "newLockStates");
+ this.newLockStates = newLockStates;
+ }
}
/**
@@ -752,14 +809,27 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo
private CDORevisionKey[] staleRevisions;
+ private CDOLockState[] newLockStates;
+
+ @Deprecated
public LockObjectsResult(boolean successful, boolean timedOut, boolean waitForUpdate, long requiredTimestamp,
CDORevisionKey[] staleRevisions)
{
+ throw new AssertionError("Deprecated"); // TODO (CD) What to do about this??
+ }
+
+ /**
+ * @since 4.1
+ */
+ public LockObjectsResult(boolean successful, boolean timedOut, boolean waitForUpdate, long requiredTimestamp,
+ CDORevisionKey[] staleRevisions, CDOLockState[] newLockStates)
+ {
this.successful = successful;
this.timedOut = timedOut;
this.waitForUpdate = waitForUpdate;
this.requiredTimestamp = requiredTimestamp;
this.staleRevisions = staleRevisions;
+ this.newLockStates = newLockStates;
}
public boolean isSuccessful()
@@ -786,5 +856,31 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo
{
return staleRevisions;
}
+
+ /**
+ * @since 4.1
+ */
+ public CDOLockState[] getNewLockStates()
+ {
+ return newLockStates;
+ }
+ }
+
+ /**
+ * @since 4.1
+ */
+ public static final class UnlockObjectsResult
+ {
+ private CDOLockState[] newLockStates;
+
+ public UnlockObjectsResult(CDOLockState[] newLockStates)
+ {
+ this.newLockStates = newLockStates;
+ }
+
+ public CDOLockState[] getNewLockStates()
+ {
+ return newLockStates;
+ }
}
}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOObject.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOObject.java
index ee269a9..4329baf 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOObject.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOObject.java
@@ -7,13 +7,14 @@
*
* Contributors:
* Eike Stepper - initial API and implementation
- * Martin Flügge - enhancements
+ * Martin Fl�gge - enhancements
*/
package org.eclipse.emf.spi.cdo;
import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.CDOState;
import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.model.CDOPackageTypeRegistry.CDOObjectMarker;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
@@ -55,6 +56,11 @@ public interface InternalCDOObject extends CDOObject, InternalEObject, InternalC
public CDOState cdoInternalSetState(CDOState state);
+ /**
+ * @since 4.1
+ */
+ public void cdoInternalSetLockState(CDOLockState lockState);
+
public InternalEObject cdoInternalInstance();
public EStructuralFeature cdoInternalDynamicFeature(int dynamicFeatureID);
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSession.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSession.java
index c82f67d..2f04595 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSession.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSession.java
@@ -17,6 +17,7 @@ import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDGenerator;
import org.eclipse.emf.cdo.common.lob.CDOLobStore;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.session.CDORepositoryInfo;
@@ -180,6 +181,11 @@ public interface InternalCDOSession extends CDOSession, PackageProcessor, Packag
public void handleCommitNotification(CDOCommitInfo commitInfo);
/**
+ * @since 4.1
+ */
+ public void handleLockNotification(CDOLockChangeInfo lockChangeInfo);
+
+ /**
* @since 3.0
*/
public void invalidate(CDOCommitInfo commitInfo, InternalCDOTransaction sender);
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOView.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOView.java
index 345a1ae..27ba5cc 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOView.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOView.java
@@ -15,6 +15,8 @@ import org.eclipse.emf.cdo.CDOState;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDProvider;
+import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
+import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
import org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl;
@@ -28,6 +30,7 @@ import org.eclipse.net4j.util.lifecycle.ILifecycle;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.ecore.EObject;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -133,6 +136,16 @@ public interface InternalCDOView extends CDOView, CDOIDProvider, ILifecycle
public boolean hasSubscription(CDOID id);
+ /**
+ * @since 4.1
+ */
+ public void handleLockNotification(CDOLockChangeInfo lockChangeInfo);
+
+ /**
+ * @since 4.1
+ */
+ public CDOLockState[] getLockStates(Collection<CDOID> ids);
+
// /**
// * Each time CDORevision or CDOState of an CDOObject is modified, ensure that no concurrent access is modifying it
// at
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ObjectUtil.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ObjectUtil.java
index 01f8d39..2b8a621 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ObjectUtil.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ObjectUtil.java
@@ -43,6 +43,23 @@ public final class ObjectUtil
return o.hashCode();
}
+ /**
+ * A collision-free hash code for small sets (<=4) of small, positive integers (<=128)
+ *
+ * @since 3.2
+ */
+ public static int hashCode(int... values)
+ {
+ int hash = 0;
+ for (int i = 0; i < values.length; i++)
+ {
+ hash += values[i];
+ hash = (hash << 7) - hash;
+ }
+
+ return hash;
+ }
+
public static int hashCode(long num)
{
return (int)(num >> 32) ^ (int)(num & 0xffffffff);
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/IRWOLockManager.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/IRWOLockManager.java
new file mode 100644
index 0000000..040ce50
--- /dev/null
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/IRWOLockManager.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2004 - 2011 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.net4j.util.concurrent;
+
+import org.eclipse.net4j.util.concurrent.RWOLockManager.LockState;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @author Caspar De Groot
+ * @since 3.2
+ */
+public interface IRWOLockManager<OBJECT, CONTEXT> extends IRWLockManager<OBJECT, CONTEXT>
+{
+ public List<LockState<OBJECT, CONTEXT>> lock2(LockType type, CONTEXT context,
+ Collection<? extends OBJECT> objectsToLock, long timeout) throws InterruptedException;
+
+ public List<LockState<OBJECT, CONTEXT>> unlock2(LockType type, CONTEXT context,
+ Collection<? extends OBJECT> objectsToUnlock);
+}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWOLockManager.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWOLockManager.java
index 979238a..846e9f3 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWOLockManager.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWOLockManager.java
@@ -15,6 +15,7 @@ import org.eclipse.net4j.util.ObjectUtil;
import org.eclipse.net4j.util.collection.HashBag;
import org.eclipse.net4j.util.lifecycle.Lifecycle;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -33,20 +34,26 @@ import java.util.Set;
* @author Caspar De Groot
* @since 3.2
*/
-public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLockManager<OBJECT, CONTEXT>
+public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWOLockManager<OBJECT, CONTEXT>
{
- // TODO (CD) Ensure that CDOID and CDOIDandBranch have good hashCode implementations
+ private final List<LockState<OBJECT, CONTEXT>> EMPTY_RESULT = Collections.emptyList();
+
private final Map<OBJECT, LockState<OBJECT, CONTEXT>> objectToLockStateMap = createObjectToLocksMap();
- // TODO (CD) Ensure that IView has a good hashCode implementation
private final Map<CONTEXT, Set<LockState<OBJECT, CONTEXT>>> contextToLockStates = createContextToLocksMap();
public void lock(LockType type, CONTEXT context, Collection<? extends OBJECT> objectsToLock, long timeout)
throws InterruptedException
{
+ lock2(type, context, objectsToLock, timeout);
+ }
+
+ public List<LockState<OBJECT, CONTEXT>> lock2(LockType type, CONTEXT context,
+ Collection<? extends OBJECT> objectsToLock, long timeout) throws InterruptedException
+ {
if (objectsToLock.isEmpty())
{
- return;
+ return EMPTY_RESULT;
}
// Must come before the synchronized block!
@@ -56,7 +63,7 @@ public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLoc
synchronized (this)
{
int count = objectsToLock.size();
- LockState<?, ?>[] lockStates = new LockState<?, ?>[count];
+ List<LockState<OBJECT, CONTEXT>> lockStates = new ArrayList<LockState<OBJECT, CONTEXT>>(count);
for (;;)
{
@@ -64,13 +71,12 @@ public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLoc
{
for (int i = 0; i < count; i++)
{
- @SuppressWarnings("unchecked")
- LockState<OBJECT, CONTEXT> lockState = (LockState<OBJECT, CONTEXT>)lockStates[i];
+ LockState<OBJECT, CONTEXT> lockState = lockStates.get(i);
lockState.lock(type, context);
addLockToContext(context, lockState);
}
- return;
+ return lockStates;
}
wait(startTime, timeout);
@@ -86,9 +92,15 @@ public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLoc
public synchronized void unlock(LockType type, CONTEXT context, Collection<? extends OBJECT> objectsToUnlock)
{
+ unlock2(type, context, objectsToUnlock);
+ }
+
+ public synchronized List<LockState<OBJECT, CONTEXT>> unlock2(LockType type, CONTEXT context,
+ Collection<? extends OBJECT> objectsToUnlock)
+ {
if (objectsToUnlock.isEmpty())
{
- return;
+ return EMPTY_RESULT;
}
List<LockState<OBJECT, CONTEXT>> lockStates = new LinkedList<LockState<OBJECT, CONTEXT>>();
@@ -121,14 +133,21 @@ public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLoc
}
notifyAll();
+
+ return lockStates;
}
public synchronized void unlock(CONTEXT context)
{
+ unlock2(context);
+ }
+
+ public synchronized List<LockState<OBJECT, CONTEXT>> unlock2(CONTEXT context)
+ {
Set<LockState<OBJECT, CONTEXT>> lockStates = contextToLockStates.get(context);
if (lockStates == null)
{
- return;
+ return EMPTY_RESULT;
}
List<OBJECT> objectsWithoutLocks = new LinkedList<OBJECT>();
@@ -141,8 +160,6 @@ public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLoc
{
lockState.unlock(lockType, context);
}
-
- // TODO (CD) Consider whether WRITE_OPTIONs should be excluded from this...
}
if (lockState.hasNoLocks())
@@ -161,18 +178,35 @@ public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLoc
}
notifyAll();
+
+ return toList(lockStates);
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<LockState<OBJECT, CONTEXT>> toList(Set<LockState<OBJECT, CONTEXT>> lockStates)
+ {
+ if (lockStates instanceof List)
+ {
+ return (List<LockState<OBJECT, CONTEXT>>)lockStates;
+ }
+
+ List<LockState<OBJECT, CONTEXT>> list = new LinkedList<LockState<OBJECT, CONTEXT>>();
+ for (LockState<OBJECT, CONTEXT> lockState : lockStates)
+ {
+ list.add(lockState);
+ }
+
+ return list;
}
public synchronized boolean hasLock(LockType type, CONTEXT context, OBJECT objectToLock)
{
- // TODO (CD) Should this be synced?
LockState<OBJECT, CONTEXT> lockState = objectToLockStateMap.get(objectToLock);
return lockState != null && lockState.hasLock(type, context, false);
}
public synchronized boolean hasLockByOthers(LockType type, CONTEXT context, OBJECT objectToLock)
{
- // TODO (CD) Should this be synced?
LockState<OBJECT, CONTEXT> lockState = objectToLockStateMap.get(objectToLock);
return lockState != null && lockState.hasLock(type, context, true);
}
@@ -222,6 +256,11 @@ public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLoc
return contextToLockStates;
}
+ public LockState<OBJECT, CONTEXT> getLockState(Object key)
+ {
+ return objectToLockStateMap.get(key);
+ }
+
private LockState<OBJECT, CONTEXT> getOrCreateLockState(OBJECT o)
{
LockState<OBJECT, CONTEXT> lockState = objectToLockStateMap.get(o);
@@ -235,10 +274,10 @@ public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLoc
}
private boolean canLockInContext(LockType type, CONTEXT context, Collection<? extends OBJECT> objectsToLock,
- LockState<?, ?>[] lockStatesToFill)
+ List<LockState<OBJECT, CONTEXT>> lockStatesToFill)
{
Iterator<? extends OBJECT> it = objectsToLock.iterator();
- for (int i = 0; i < lockStatesToFill.length; i++)
+ for (int i = 0; i < objectsToLock.size(); i++)
{
OBJECT o = it.next();
LockState<OBJECT, CONTEXT> lockState = getOrCreateLockState(o);
@@ -247,7 +286,7 @@ public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLoc
return false;
}
- lockStatesToFill[i] = lockState;
+ lockStatesToFill.add(lockState);
}
return true;
@@ -301,7 +340,7 @@ public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLoc
/**
* Represents a combination of locks for one OBJECT. The different lock types are represented by the values of the
- * enum {@link LockType}.
+ * enum {@link IRWLockManager.LockType}
* <p>
* The locking semantics established by this class are as follows:
* <li>a read lock prevents a write lock by another, but allows read locks by others and allows a write option by
@@ -315,11 +354,10 @@ public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLoc
* @author Caspar De Groot
* @since 3.2
*/
- protected static class LockState<OBJECT, CONTEXT>
+ public static class LockState<OBJECT, CONTEXT>
{
private final OBJECT lockedObject;
- // TODO (CD) Ensure that IView has a good hashCode implementation
private final HashBag<CONTEXT> readLockOwners = new HashBag<CONTEXT>();
private CONTEXT writeLockOwner;
@@ -374,6 +412,23 @@ public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLoc
return false;
}
+ public boolean hasLock(org.eclipse.net4j.util.concurrent.IRWLockManager.LockType type)
+ {
+ switch (type)
+ {
+ case READ:
+ return readLockOwners.size() > 0;
+
+ case WRITE:
+ return writeLockOwner != null;
+
+ case OPTION:
+ return writeOptionOwner != null;
+ }
+
+ return false;
+ }
+
@Override
public String toString()
{
@@ -648,5 +703,20 @@ public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLoc
{
writeOptionOwner = null;
}
+
+ public Set<CONTEXT> getReadLockOwners()
+ {
+ return Collections.unmodifiableSet(readLockOwners);
+ }
+
+ public CONTEXT getWriteLockOwner()
+ {
+ return writeLockOwner;
+ }
+
+ public CONTEXT getWriteOptionOwner()
+ {
+ return writeOptionOwner;
+ }
}
}