diff options
author | Eike Stepper | 2012-01-14 10:27:01 +0000 |
---|---|---|
committer | Eike Stepper | 2012-01-14 10:27:01 +0000 |
commit | 0266166cb9ff9535c150250073ea1e57b42d2693 (patch) | |
tree | c006a3bc0ba1f6e1d8a2bc032eedc346f71eab0d /plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWLockManager.java | |
parent | 7416443692cdda72d1f704ea4fc5ececcc669df7 (diff) | |
download | cdo-0266166cb9ff9535c150250073ea1e57b42d2693.tar.gz cdo-0266166cb9ff9535c150250073ea1e57b42d2693.tar.xz cdo-0266166cb9ff9535c150250073ea1e57b42d2693.zip |
Adjusted copyrights to 2012
Diffstat (limited to 'plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWLockManager.java')
-rw-r--r-- | plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWLockManager.java | 1586 |
1 files changed, 793 insertions, 793 deletions
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWLockManager.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWLockManager.java index 257333be4f..50ae00b8af 100644 --- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWLockManager.java +++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWLockManager.java @@ -1,793 +1,793 @@ -/* - * 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: - * Simon McDuff - initial API and implementation - * Eike Stepper - maintenance - */ -package org.eclipse.net4j.util.concurrent; - -import org.eclipse.net4j.util.ObjectUtil; -import org.eclipse.net4j.util.collection.HashBag; -import org.eclipse.net4j.util.lifecycle.Lifecycle; - -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -/** - * Support Multiple reads/no write and upgrade lock from read to write. Many context could request - * {@link IRWLockManager.LockType#WRITE write} lock at the same time. It will privileges first context that has already - * a {@link IRWLockManager.LockType#READ read} lock. If no one has any read lock, it's "first come first serve". - * - * @author Simon McDuff - * @since 2.0 - * @deprecated Use {@link RWOLockManager} - */ -@Deprecated -public class RWLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLockManager<OBJECT, CONTEXT> -{ - private LockStrategy<OBJECT, CONTEXT> readLockStrategy = new LockStrategy<OBJECT, CONTEXT>() - { - public boolean isLocked(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context) - { - return entry.isReadLock(context); - } - - public boolean isLockedByOthers(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context) - { - return entry.isReadLockByOthers(context); - } - - public boolean canObtainLock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context) - { - return entry.canObtainReadLock(context); - } - - public LockEntry<OBJECT, CONTEXT> lock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context) - { - return entry.readLock(context); - } - - public LockEntry<OBJECT, CONTEXT> unlock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context) - { - return entry.readUnlock(context); - } - - @Override - public String toString() - { - return "ReadLockStrategy"; - } - }; - - private LockStrategy<OBJECT, CONTEXT> writeLockStrategy = new LockStrategy<OBJECT, CONTEXT>() - { - public boolean isLocked(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context) - { - return entry.isWriteLock(context); - } - - public boolean isLockedByOthers(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context) - { - return entry.isWriteLockByOthers(context); - } - - public boolean canObtainLock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context) - { - return entry.canObtainWriteLock(context); - } - - public LockEntry<OBJECT, CONTEXT> lock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context) - { - return entry.writeLock(context); - } - - public LockEntry<OBJECT, CONTEXT> unlock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context) - { - return entry.writeUnlock(context); - } - - @Override - public String toString() - { - return "WriteLockStrategy"; - } - }; - - private Map<OBJECT, LockEntry<OBJECT, CONTEXT>> lockEntries = new HashMap<OBJECT, LockEntry<OBJECT, CONTEXT>>(); - - private LockChanged lockChanged = new LockChanged(); - - /** - * @since 3.0 - */ - public void lock(LockType type, CONTEXT context, Collection<? extends OBJECT> objectsToLock, long timeout) - throws InterruptedException - { - LockStrategy<OBJECT, CONTEXT> lockingStrategy = getLockingStrategy(type); - lock(lockingStrategy, context, objectsToLock, timeout); - } - - /** - * @since 3.0 - */ - public void lock(LockType type, CONTEXT context, OBJECT objectToLock, long timeout) throws InterruptedException - { - List<OBJECT> objectsToLock = Collections.singletonList(objectToLock); - lock(type, context, objectsToLock, timeout); - } - - /** - * Attempts to release for a given locktype, context and objects. - * - * @throws IllegalMonitorStateException - * Unlocking objects without lock. - * @since 3.0 - */ - public void unlock(LockType type, CONTEXT context, Collection<? extends OBJECT> objectsToUnlock) - { - LockStrategy<OBJECT, CONTEXT> lockingStrategy = getLockingStrategy(type); - unlock(lockingStrategy, context, objectsToUnlock); - } - - /** - * Attempts to release all locks(read and write) for a given context. - */ - public void unlock(CONTEXT context) - { - synchronized (lockChanged) - { - List<LockEntry<OBJECT, CONTEXT>> lockEntrysToRemove = new ArrayList<LockEntry<OBJECT, CONTEXT>>(); - List<LockEntry<OBJECT, CONTEXT>> lockEntrysToAdd = new ArrayList<LockEntry<OBJECT, CONTEXT>>(); - - for (Entry<OBJECT, LockEntry<OBJECT, CONTEXT>> entry : lockEntries.entrySet()) - { - LockEntry<OBJECT, CONTEXT> lockedContext = entry.getValue(); - LockEntry<OBJECT, CONTEXT> newEntry = lockedContext.clearLock(context); - if (newEntry == null) - { - lockEntrysToRemove.add(lockedContext); - } - else if (newEntry != entry) - { - lockEntrysToAdd.add(newEntry); - } - } - - for (LockEntry<OBJECT, CONTEXT> lockEntry : lockEntrysToRemove) - { - OBJECT object = lockEntry.getObject(); - lockEntries.remove(object); - } - - for (LockEntry<OBJECT, CONTEXT> lockEntry : lockEntrysToAdd) - { - OBJECT object = lockEntry.getObject(); - lockEntries.put(object, lockEntry); - } - - lockChanged.notifyAll(); - } - } - - /** - * @since 3.0 - */ - public boolean hasLock(LockType type, CONTEXT context, OBJECT objectToLock) - { - LockStrategy<OBJECT, CONTEXT> lockingStrategy = getLockingStrategy(type); - return hasLock(lockingStrategy, context, objectToLock); - } - - /** - * @since 3.0 - */ - public boolean hasLockByOthers(LockType type, CONTEXT context, OBJECT objectToLock) - { - LockStrategy<OBJECT, CONTEXT> lockingStrategy = getLockingStrategy(type); - LockEntry<OBJECT, CONTEXT> entry = getLockEntry(objectToLock); - return entry != null && lockingStrategy.isLockedByOthers(entry, context); - } - - /** - * @since 3.1 - */ - protected void handleLockEntries(CONTEXT context, LockEntryHandler<OBJECT, CONTEXT> handler) - { - synchronized (lockChanged) - { - for (LockEntry<OBJECT, CONTEXT> lockEntry : lockEntries.values()) - { - if (context == null || lockEntry.hasContext(context)) - { - if (!handler.handleLockEntry(lockEntry)) - { - break; - } - } - } - } - } - - /** - * @since 3.1 - */ - protected LockEntry<OBJECT, CONTEXT> getLockEntry(OBJECT objectToLock) - { - synchronized (lockChanged) - { - return lockEntries.get(objectToLock); - } - } - - /** - * @since 3.1 - */ - protected LockStrategy<OBJECT, CONTEXT> getLockingStrategy(LockType type) - { - if (type == LockType.READ) - { - return readLockStrategy; - } - - if (type == LockType.WRITE) - { - return writeLockStrategy; - } - - throw new IllegalArgumentException("Invalid lock type: " + type); - } - - /** - * @since 3.1 - */ - protected void changeContext(CONTEXT oldContext, CONTEXT newContext) - { - synchronized (lockChanged) - { - for (LockEntry<OBJECT, CONTEXT> lockEntry : lockEntries.values()) - { - lockEntry.changeContext(oldContext, newContext); - } - } - } - - /** - * Attempts to release this lock. - * <p> - * If the number of context is now zero then the lock is made available for write lock attempts. - * - * @throws IllegalMonitorStateException - * Unlocking object not locked. - */ - private void unlock(LockStrategy<OBJECT, CONTEXT> lockingStrategy, CONTEXT context, - Collection<? extends OBJECT> objectsToLock) - { - synchronized (lockChanged) - { - List<LockEntry<OBJECT, CONTEXT>> lockEntrysToRemove = new ArrayList<LockEntry<OBJECT, CONTEXT>>(); - List<LockEntry<OBJECT, CONTEXT>> lockEntrysToAdd = new ArrayList<LockEntry<OBJECT, CONTEXT>>(); - for (OBJECT objectToLock : objectsToLock) - { - LockEntry<OBJECT, CONTEXT> entry = lockEntries.get(objectToLock); - if (entry == null) - { - throw new IllegalMonitorStateException(); - } - - LockEntry<OBJECT, CONTEXT> newEntry = lockingStrategy.unlock(entry, context); - if (newEntry == null) - { - lockEntrysToRemove.add(entry); - } - else if (newEntry != entry) - { - lockEntrysToAdd.add(newEntry); - } - } - - for (LockEntry<OBJECT, CONTEXT> lockEntry : lockEntrysToRemove) - { - OBJECT object = lockEntry.getObject(); - lockEntries.remove(object); - } - - for (LockEntry<OBJECT, CONTEXT> lockEntry : lockEntrysToAdd) - { - OBJECT object = lockEntry.getObject(); - lockEntries.put(object, lockEntry); - } - - lockChanged.notifyAll(); - } - } - - private boolean hasLock(LockStrategy<OBJECT, CONTEXT> lockingStrategy, CONTEXT context, OBJECT objectToLock) - { - LockEntry<OBJECT, CONTEXT> entry = getLockEntry(objectToLock); - return entry != null && lockingStrategy.isLocked(entry, context); - } - - private void lock(LockStrategy<OBJECT, CONTEXT> lockStrategy, CONTEXT context, - Collection<? extends OBJECT> objectsToLocks, long timeout) throws InterruptedException - { - long startTime = System.currentTimeMillis(); - while (true) - { - synchronized (lockChanged) - { - OBJECT conflict = obtainLock(lockStrategy, context, objectsToLocks); - if (conflict == null) - { - lockChanged.notifyAll(); - return; - } - - long elapsedTime = System.currentTimeMillis() - startTime; - if (timeout != WAIT && elapsedTime > timeout) - { - throw new TimeoutRuntimeException("Could not lock " + conflict + " within " + timeout + " milli seconds"); //$NON-NLS-1$ - } - - if (timeout == WAIT) - { - lockChanged.wait(); - } - else - { - lockChanged.wait(Math.max(1, timeout - elapsedTime)); - } - } - } - } - - private OBJECT obtainLock(LockStrategy<OBJECT, CONTEXT> lockingStrategy, CONTEXT context, - Collection<? extends OBJECT> objectsToLock) - { - List<LockEntry<OBJECT, CONTEXT>> lockEntrys = new ArrayList<LockEntry<OBJECT, CONTEXT>>(); - for (OBJECT objectToLock : objectsToLock) - { - LockEntry<OBJECT, CONTEXT> entry = lockEntries.get(objectToLock); - if (entry == null) - { - entry = new NoLockEntry<OBJECT, CONTEXT>(objectToLock); - } - - if (lockingStrategy.canObtainLock(entry, context)) - { - lockEntrys.add(entry); - } - else - { - return objectToLock; - } - } - - for (LockEntry<OBJECT, CONTEXT> lockEntry : lockEntrys) - { - OBJECT object = lockEntry.getObject(); - LockEntry<OBJECT, CONTEXT> lock = lockingStrategy.lock(lockEntry, context); - lockEntries.put(object, lock); - } - - return null; - } - - /** - * @author Simon McDuff - * @since 3.1 - * @deprecated Use {@link RWOLockManager} - */ - @Deprecated - protected interface LockStrategy<OBJECT, CONTEXT> - { - public boolean isLocked(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context); - - public boolean isLockedByOthers(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context); - - public boolean canObtainLock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context); - - public LockEntry<OBJECT, CONTEXT> lock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context); - - public LockEntry<OBJECT, CONTEXT> unlock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context); - } - - /** - * @author Simon McDuff - * @since 3.1 - * @deprecated Use {@link RWOLockManager} - */ - @Deprecated - protected interface LockEntry<OBJECT, CONTEXT> - { - public OBJECT getObject(); - - public boolean isReadLock(CONTEXT context); - - public boolean isWriteLock(CONTEXT context); - - public boolean isReadLockByOthers(CONTEXT context); - - public boolean isWriteLockByOthers(CONTEXT context); - - public boolean canObtainReadLock(CONTEXT context); - - public boolean canObtainWriteLock(CONTEXT context); - - public LockEntry<OBJECT, CONTEXT> readLock(CONTEXT context); - - public LockEntry<OBJECT, CONTEXT> writeLock(CONTEXT context); - - public LockEntry<OBJECT, CONTEXT> readUnlock(CONTEXT context); - - public LockEntry<OBJECT, CONTEXT> writeUnlock(CONTEXT context); - - public LockEntry<OBJECT, CONTEXT> clearLock(CONTEXT context); - - /** - * @since 3.1 - */ - public void changeContext(CONTEXT oldContext, CONTEXT newContext); - - /** - * @since 3.1 - */ - public boolean hasContext(CONTEXT context); - } - - /** - * @author Eike Stepper - * @since 3.1 - * @deprecated Use {@link RWOLockManager} - */ - @Deprecated - protected interface LockEntryHandler<OBJECT, CONTEXT> - { - public boolean handleLockEntry(LockEntry<OBJECT, CONTEXT> lockEntry); - } - - /** - * @author Simon McDuff - */ - private static final class ReadLockEntry<OBJECT, CONTEXT> implements LockEntry<OBJECT, CONTEXT> - { - private OBJECT object; - - private Set<CONTEXT> contexts = new HashBag<CONTEXT>(); - - public ReadLockEntry(OBJECT objectToLock, CONTEXT context) - { - this.object = objectToLock; - contexts.add(context); - } - - public OBJECT getObject() - { - return object; - } - - public boolean isReadLock(CONTEXT context) - { - return contexts.contains(context); - } - - public boolean isWriteLock(CONTEXT context) - { - return false; - } - - public boolean isReadLockByOthers(CONTEXT context) - { - if (contexts.isEmpty()) - { - return false; - } - - return contexts.size() > (isReadLock(context) ? 1 : 0); - } - - public boolean isWriteLockByOthers(CONTEXT context) - { - return false; - } - - public boolean canObtainReadLock(CONTEXT context) - { - return true; - } - - public boolean canObtainWriteLock(CONTEXT context) - { - return contexts.size() == 1 && contexts.contains(context); - } - - public LockEntry<OBJECT, CONTEXT> readLock(CONTEXT context) - { - contexts.add(context); - return this; - } - - public LockEntry<OBJECT, CONTEXT> writeLock(CONTEXT context) - { - return new WriteLockEntry<OBJECT, CONTEXT>(object, context, this); - } - - public LockEntry<OBJECT, CONTEXT> readUnlock(CONTEXT context) - { - contexts.remove(context); - return contexts.isEmpty() ? null : this; - } - - public LockEntry<OBJECT, CONTEXT> writeUnlock(CONTEXT context) - { - throw new IllegalMonitorStateException(); - } - - public LockEntry<OBJECT, CONTEXT> clearLock(CONTEXT context) - { - while (contexts.remove(context)) - { - } - - return contexts.isEmpty() ? null : this; - } - - public void changeContext(CONTEXT oldContext, CONTEXT newContext) - { - if (contexts.remove(oldContext)) - { - contexts.add(newContext); - } - } - - public boolean hasContext(CONTEXT context) - { - return contexts.contains(context); - } - - @Override - public String toString() - { - return MessageFormat.format("ReadLockEntry[object={0}, contexts={1}]", object, contexts); - } - } - - /** - * @author Simon McDuff - */ - private static final class WriteLockEntry<OBJECT, CONTEXT> implements LockEntry<OBJECT, CONTEXT> - { - private OBJECT object; - - private CONTEXT context; - - private int count; - - private ReadLockEntry<OBJECT, CONTEXT> readLock; - - public WriteLockEntry(OBJECT object, CONTEXT context, ReadLockEntry<OBJECT, CONTEXT> readLock) - { - this.object = object; - this.context = context; - this.readLock = readLock; - this.count = 1; - } - - public OBJECT getObject() - { - return object; - } - - public boolean isReadLock(CONTEXT context) - { - return readLock != null ? readLock.isReadLock(context) : false; - } - - public boolean isWriteLock(CONTEXT context) - { - return ObjectUtil.equals(this.context, context); - } - - public boolean isReadLockByOthers(CONTEXT context) - { - return readLock != null ? readLock.isReadLockByOthers(context) : false; - } - - public boolean isWriteLockByOthers(CONTEXT context) - { - return context != this.context; - } - - public boolean canObtainWriteLock(CONTEXT context) - { - return ObjectUtil.equals(this.context, context); - } - - public boolean canObtainReadLock(CONTEXT context) - { - return ObjectUtil.equals(this.context, context); - } - - public LockEntry<OBJECT, CONTEXT> readLock(CONTEXT context) - { - ReadLockEntry<OBJECT, CONTEXT> lock = getReadLock(); - lock.readLock(context); - return this; - } - - public LockEntry<OBJECT, CONTEXT> writeLock(CONTEXT context) - { - count++; - return this; - } - - public LockEntry<OBJECT, CONTEXT> readUnlock(CONTEXT context) - { - if (readLock != null) - { - if (readLock.readUnlock(context) == null) - { - readLock = null; - } - - return this; - } - - throw new IllegalMonitorStateException(); - } - - public LockEntry<OBJECT, CONTEXT> writeUnlock(CONTEXT context) - { - return --count <= 0 ? readLock : this; - } - - public LockEntry<OBJECT, CONTEXT> clearLock(CONTEXT context) - { - if (readLock != null) - { - if (readLock.clearLock(context) == null) - { - readLock = null; - } - } - - return ObjectUtil.equals(this.context, context) ? readLock : this; - } - - public void changeContext(CONTEXT oldContext, CONTEXT newContext) - { - if (ObjectUtil.equals(context, oldContext)) - { - context = newContext; - } - } - - public boolean hasContext(CONTEXT context) - { - return ObjectUtil.equals(this.context, context); - } - - @Override - public String toString() - { - return MessageFormat.format("WriteLockEntry[object={0}, context={1}, count={2}]", object, context, count); - } - - private ReadLockEntry<OBJECT, CONTEXT> getReadLock() - { - if (readLock == null) - { - readLock = new ReadLockEntry<OBJECT, CONTEXT>(object, context); - } - - return readLock; - } - } - - /** - * @author Simon McDuff - */ - private static final class NoLockEntry<OBJECT, CONTEXT> implements LockEntry<OBJECT, CONTEXT> - { - private OBJECT object; - - public NoLockEntry(OBJECT objectToLock) - { - this.object = objectToLock; - } - - public OBJECT getObject() - { - return object; - } - - public boolean isReadLock(CONTEXT context) - { - throw new UnsupportedOperationException(); - } - - public boolean isWriteLock(CONTEXT context) - { - throw new UnsupportedOperationException(); - } - - public boolean isReadLockByOthers(CONTEXT context) - { - throw new UnsupportedOperationException(); - } - - public boolean isWriteLockByOthers(CONTEXT context) - { - throw new UnsupportedOperationException(); - } - - public boolean canObtainWriteLock(CONTEXT context) - { - return true; - } - - public boolean canObtainReadLock(CONTEXT context) - { - return true; - } - - public LockEntry<OBJECT, CONTEXT> readLock(CONTEXT context) - { - return new ReadLockEntry<OBJECT, CONTEXT>(object, context); - } - - public LockEntry<OBJECT, CONTEXT> writeLock(CONTEXT context) - { - return new WriteLockEntry<OBJECT, CONTEXT>(object, context, null); - } - - public LockEntry<OBJECT, CONTEXT> readUnlock(CONTEXT context) - { - throw new UnsupportedOperationException(); - } - - public LockEntry<OBJECT, CONTEXT> writeUnlock(CONTEXT context) - { - throw new UnsupportedOperationException(); - } - - public LockEntry<OBJECT, CONTEXT> clearLock(CONTEXT context) - { - throw new UnsupportedOperationException(); - } - - public void changeContext(CONTEXT oldContext, CONTEXT newContext) - { - // Do nothing - } - - public boolean hasContext(CONTEXT context) - { - return false; - } - - @Override - public String toString() - { - return MessageFormat.format("NoLockEntry[object={0}]", object); - } - } - - /** - * @author Eike Stepper - */ - private static final class LockChanged - { - } -} +/*
+ * Copyright (c) 2004 - 2012 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:
+ * Simon McDuff - initial API and implementation
+ * Eike Stepper - maintenance
+ */
+package org.eclipse.net4j.util.concurrent;
+
+import org.eclipse.net4j.util.ObjectUtil;
+import org.eclipse.net4j.util.collection.HashBag;
+import org.eclipse.net4j.util.lifecycle.Lifecycle;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Support Multiple reads/no write and upgrade lock from read to write. Many context could request
+ * {@link IRWLockManager.LockType#WRITE write} lock at the same time. It will privileges first context that has already
+ * a {@link IRWLockManager.LockType#READ read} lock. If no one has any read lock, it's "first come first serve".
+ *
+ * @author Simon McDuff
+ * @since 2.0
+ * @deprecated Use {@link RWOLockManager}
+ */
+@Deprecated
+public class RWLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWLockManager<OBJECT, CONTEXT>
+{
+ private LockStrategy<OBJECT, CONTEXT> readLockStrategy = new LockStrategy<OBJECT, CONTEXT>()
+ {
+ public boolean isLocked(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context)
+ {
+ return entry.isReadLock(context);
+ }
+
+ public boolean isLockedByOthers(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context)
+ {
+ return entry.isReadLockByOthers(context);
+ }
+
+ public boolean canObtainLock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context)
+ {
+ return entry.canObtainReadLock(context);
+ }
+
+ public LockEntry<OBJECT, CONTEXT> lock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context)
+ {
+ return entry.readLock(context);
+ }
+
+ public LockEntry<OBJECT, CONTEXT> unlock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context)
+ {
+ return entry.readUnlock(context);
+ }
+
+ @Override
+ public String toString()
+ {
+ return "ReadLockStrategy";
+ }
+ };
+
+ private LockStrategy<OBJECT, CONTEXT> writeLockStrategy = new LockStrategy<OBJECT, CONTEXT>()
+ {
+ public boolean isLocked(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context)
+ {
+ return entry.isWriteLock(context);
+ }
+
+ public boolean isLockedByOthers(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context)
+ {
+ return entry.isWriteLockByOthers(context);
+ }
+
+ public boolean canObtainLock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context)
+ {
+ return entry.canObtainWriteLock(context);
+ }
+
+ public LockEntry<OBJECT, CONTEXT> lock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context)
+ {
+ return entry.writeLock(context);
+ }
+
+ public LockEntry<OBJECT, CONTEXT> unlock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context)
+ {
+ return entry.writeUnlock(context);
+ }
+
+ @Override
+ public String toString()
+ {
+ return "WriteLockStrategy";
+ }
+ };
+
+ private Map<OBJECT, LockEntry<OBJECT, CONTEXT>> lockEntries = new HashMap<OBJECT, LockEntry<OBJECT, CONTEXT>>();
+
+ private LockChanged lockChanged = new LockChanged();
+
+ /**
+ * @since 3.0
+ */
+ public void lock(LockType type, CONTEXT context, Collection<? extends OBJECT> objectsToLock, long timeout)
+ throws InterruptedException
+ {
+ LockStrategy<OBJECT, CONTEXT> lockingStrategy = getLockingStrategy(type);
+ lock(lockingStrategy, context, objectsToLock, timeout);
+ }
+
+ /**
+ * @since 3.0
+ */
+ public void lock(LockType type, CONTEXT context, OBJECT objectToLock, long timeout) throws InterruptedException
+ {
+ List<OBJECT> objectsToLock = Collections.singletonList(objectToLock);
+ lock(type, context, objectsToLock, timeout);
+ }
+
+ /**
+ * Attempts to release for a given locktype, context and objects.
+ *
+ * @throws IllegalMonitorStateException
+ * Unlocking objects without lock.
+ * @since 3.0
+ */
+ public void unlock(LockType type, CONTEXT context, Collection<? extends OBJECT> objectsToUnlock)
+ {
+ LockStrategy<OBJECT, CONTEXT> lockingStrategy = getLockingStrategy(type);
+ unlock(lockingStrategy, context, objectsToUnlock);
+ }
+
+ /**
+ * Attempts to release all locks(read and write) for a given context.
+ */
+ public void unlock(CONTEXT context)
+ {
+ synchronized (lockChanged)
+ {
+ List<LockEntry<OBJECT, CONTEXT>> lockEntrysToRemove = new ArrayList<LockEntry<OBJECT, CONTEXT>>();
+ List<LockEntry<OBJECT, CONTEXT>> lockEntrysToAdd = new ArrayList<LockEntry<OBJECT, CONTEXT>>();
+
+ for (Entry<OBJECT, LockEntry<OBJECT, CONTEXT>> entry : lockEntries.entrySet())
+ {
+ LockEntry<OBJECT, CONTEXT> lockedContext = entry.getValue();
+ LockEntry<OBJECT, CONTEXT> newEntry = lockedContext.clearLock(context);
+ if (newEntry == null)
+ {
+ lockEntrysToRemove.add(lockedContext);
+ }
+ else if (newEntry != entry)
+ {
+ lockEntrysToAdd.add(newEntry);
+ }
+ }
+
+ for (LockEntry<OBJECT, CONTEXT> lockEntry : lockEntrysToRemove)
+ {
+ OBJECT object = lockEntry.getObject();
+ lockEntries.remove(object);
+ }
+
+ for (LockEntry<OBJECT, CONTEXT> lockEntry : lockEntrysToAdd)
+ {
+ OBJECT object = lockEntry.getObject();
+ lockEntries.put(object, lockEntry);
+ }
+
+ lockChanged.notifyAll();
+ }
+ }
+
+ /**
+ * @since 3.0
+ */
+ public boolean hasLock(LockType type, CONTEXT context, OBJECT objectToLock)
+ {
+ LockStrategy<OBJECT, CONTEXT> lockingStrategy = getLockingStrategy(type);
+ return hasLock(lockingStrategy, context, objectToLock);
+ }
+
+ /**
+ * @since 3.0
+ */
+ public boolean hasLockByOthers(LockType type, CONTEXT context, OBJECT objectToLock)
+ {
+ LockStrategy<OBJECT, CONTEXT> lockingStrategy = getLockingStrategy(type);
+ LockEntry<OBJECT, CONTEXT> entry = getLockEntry(objectToLock);
+ return entry != null && lockingStrategy.isLockedByOthers(entry, context);
+ }
+
+ /**
+ * @since 3.1
+ */
+ protected void handleLockEntries(CONTEXT context, LockEntryHandler<OBJECT, CONTEXT> handler)
+ {
+ synchronized (lockChanged)
+ {
+ for (LockEntry<OBJECT, CONTEXT> lockEntry : lockEntries.values())
+ {
+ if (context == null || lockEntry.hasContext(context))
+ {
+ if (!handler.handleLockEntry(lockEntry))
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @since 3.1
+ */
+ protected LockEntry<OBJECT, CONTEXT> getLockEntry(OBJECT objectToLock)
+ {
+ synchronized (lockChanged)
+ {
+ return lockEntries.get(objectToLock);
+ }
+ }
+
+ /**
+ * @since 3.1
+ */
+ protected LockStrategy<OBJECT, CONTEXT> getLockingStrategy(LockType type)
+ {
+ if (type == LockType.READ)
+ {
+ return readLockStrategy;
+ }
+
+ if (type == LockType.WRITE)
+ {
+ return writeLockStrategy;
+ }
+
+ throw new IllegalArgumentException("Invalid lock type: " + type);
+ }
+
+ /**
+ * @since 3.1
+ */
+ protected void changeContext(CONTEXT oldContext, CONTEXT newContext)
+ {
+ synchronized (lockChanged)
+ {
+ for (LockEntry<OBJECT, CONTEXT> lockEntry : lockEntries.values())
+ {
+ lockEntry.changeContext(oldContext, newContext);
+ }
+ }
+ }
+
+ /**
+ * Attempts to release this lock.
+ * <p>
+ * If the number of context is now zero then the lock is made available for write lock attempts.
+ *
+ * @throws IllegalMonitorStateException
+ * Unlocking object not locked.
+ */
+ private void unlock(LockStrategy<OBJECT, CONTEXT> lockingStrategy, CONTEXT context,
+ Collection<? extends OBJECT> objectsToLock)
+ {
+ synchronized (lockChanged)
+ {
+ List<LockEntry<OBJECT, CONTEXT>> lockEntrysToRemove = new ArrayList<LockEntry<OBJECT, CONTEXT>>();
+ List<LockEntry<OBJECT, CONTEXT>> lockEntrysToAdd = new ArrayList<LockEntry<OBJECT, CONTEXT>>();
+ for (OBJECT objectToLock : objectsToLock)
+ {
+ LockEntry<OBJECT, CONTEXT> entry = lockEntries.get(objectToLock);
+ if (entry == null)
+ {
+ throw new IllegalMonitorStateException();
+ }
+
+ LockEntry<OBJECT, CONTEXT> newEntry = lockingStrategy.unlock(entry, context);
+ if (newEntry == null)
+ {
+ lockEntrysToRemove.add(entry);
+ }
+ else if (newEntry != entry)
+ {
+ lockEntrysToAdd.add(newEntry);
+ }
+ }
+
+ for (LockEntry<OBJECT, CONTEXT> lockEntry : lockEntrysToRemove)
+ {
+ OBJECT object = lockEntry.getObject();
+ lockEntries.remove(object);
+ }
+
+ for (LockEntry<OBJECT, CONTEXT> lockEntry : lockEntrysToAdd)
+ {
+ OBJECT object = lockEntry.getObject();
+ lockEntries.put(object, lockEntry);
+ }
+
+ lockChanged.notifyAll();
+ }
+ }
+
+ private boolean hasLock(LockStrategy<OBJECT, CONTEXT> lockingStrategy, CONTEXT context, OBJECT objectToLock)
+ {
+ LockEntry<OBJECT, CONTEXT> entry = getLockEntry(objectToLock);
+ return entry != null && lockingStrategy.isLocked(entry, context);
+ }
+
+ private void lock(LockStrategy<OBJECT, CONTEXT> lockStrategy, CONTEXT context,
+ Collection<? extends OBJECT> objectsToLocks, long timeout) throws InterruptedException
+ {
+ long startTime = System.currentTimeMillis();
+ while (true)
+ {
+ synchronized (lockChanged)
+ {
+ OBJECT conflict = obtainLock(lockStrategy, context, objectsToLocks);
+ if (conflict == null)
+ {
+ lockChanged.notifyAll();
+ return;
+ }
+
+ long elapsedTime = System.currentTimeMillis() - startTime;
+ if (timeout != WAIT && elapsedTime > timeout)
+ {
+ throw new TimeoutRuntimeException("Could not lock " + conflict + " within " + timeout + " milli seconds"); //$NON-NLS-1$
+ }
+
+ if (timeout == WAIT)
+ {
+ lockChanged.wait();
+ }
+ else
+ {
+ lockChanged.wait(Math.max(1, timeout - elapsedTime));
+ }
+ }
+ }
+ }
+
+ private OBJECT obtainLock(LockStrategy<OBJECT, CONTEXT> lockingStrategy, CONTEXT context,
+ Collection<? extends OBJECT> objectsToLock)
+ {
+ List<LockEntry<OBJECT, CONTEXT>> lockEntrys = new ArrayList<LockEntry<OBJECT, CONTEXT>>();
+ for (OBJECT objectToLock : objectsToLock)
+ {
+ LockEntry<OBJECT, CONTEXT> entry = lockEntries.get(objectToLock);
+ if (entry == null)
+ {
+ entry = new NoLockEntry<OBJECT, CONTEXT>(objectToLock);
+ }
+
+ if (lockingStrategy.canObtainLock(entry, context))
+ {
+ lockEntrys.add(entry);
+ }
+ else
+ {
+ return objectToLock;
+ }
+ }
+
+ for (LockEntry<OBJECT, CONTEXT> lockEntry : lockEntrys)
+ {
+ OBJECT object = lockEntry.getObject();
+ LockEntry<OBJECT, CONTEXT> lock = lockingStrategy.lock(lockEntry, context);
+ lockEntries.put(object, lock);
+ }
+
+ return null;
+ }
+
+ /**
+ * @author Simon McDuff
+ * @since 3.1
+ * @deprecated Use {@link RWOLockManager}
+ */
+ @Deprecated
+ protected interface LockStrategy<OBJECT, CONTEXT>
+ {
+ public boolean isLocked(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context);
+
+ public boolean isLockedByOthers(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context);
+
+ public boolean canObtainLock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context);
+
+ public LockEntry<OBJECT, CONTEXT> lock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context);
+
+ public LockEntry<OBJECT, CONTEXT> unlock(LockEntry<OBJECT, CONTEXT> entry, CONTEXT context);
+ }
+
+ /**
+ * @author Simon McDuff
+ * @since 3.1
+ * @deprecated Use {@link RWOLockManager}
+ */
+ @Deprecated
+ protected interface LockEntry<OBJECT, CONTEXT>
+ {
+ public OBJECT getObject();
+
+ public boolean isReadLock(CONTEXT context);
+
+ public boolean isWriteLock(CONTEXT context);
+
+ public boolean isReadLockByOthers(CONTEXT context);
+
+ public boolean isWriteLockByOthers(CONTEXT context);
+
+ public boolean canObtainReadLock(CONTEXT context);
+
+ public boolean canObtainWriteLock(CONTEXT context);
+
+ public LockEntry<OBJECT, CONTEXT> readLock(CONTEXT context);
+
+ public LockEntry<OBJECT, CONTEXT> writeLock(CONTEXT context);
+
+ public LockEntry<OBJECT, CONTEXT> readUnlock(CONTEXT context);
+
+ public LockEntry<OBJECT, CONTEXT> writeUnlock(CONTEXT context);
+
+ public LockEntry<OBJECT, CONTEXT> clearLock(CONTEXT context);
+
+ /**
+ * @since 3.1
+ */
+ public void changeContext(CONTEXT oldContext, CONTEXT newContext);
+
+ /**
+ * @since 3.1
+ */
+ public boolean hasContext(CONTEXT context);
+ }
+
+ /**
+ * @author Eike Stepper
+ * @since 3.1
+ * @deprecated Use {@link RWOLockManager}
+ */
+ @Deprecated
+ protected interface LockEntryHandler<OBJECT, CONTEXT>
+ {
+ public boolean handleLockEntry(LockEntry<OBJECT, CONTEXT> lockEntry);
+ }
+
+ /**
+ * @author Simon McDuff
+ */
+ private static final class ReadLockEntry<OBJECT, CONTEXT> implements LockEntry<OBJECT, CONTEXT>
+ {
+ private OBJECT object;
+
+ private Set<CONTEXT> contexts = new HashBag<CONTEXT>();
+
+ public ReadLockEntry(OBJECT objectToLock, CONTEXT context)
+ {
+ this.object = objectToLock;
+ contexts.add(context);
+ }
+
+ public OBJECT getObject()
+ {
+ return object;
+ }
+
+ public boolean isReadLock(CONTEXT context)
+ {
+ return contexts.contains(context);
+ }
+
+ public boolean isWriteLock(CONTEXT context)
+ {
+ return false;
+ }
+
+ public boolean isReadLockByOthers(CONTEXT context)
+ {
+ if (contexts.isEmpty())
+ {
+ return false;
+ }
+
+ return contexts.size() > (isReadLock(context) ? 1 : 0);
+ }
+
+ public boolean isWriteLockByOthers(CONTEXT context)
+ {
+ return false;
+ }
+
+ public boolean canObtainReadLock(CONTEXT context)
+ {
+ return true;
+ }
+
+ public boolean canObtainWriteLock(CONTEXT context)
+ {
+ return contexts.size() == 1 && contexts.contains(context);
+ }
+
+ public LockEntry<OBJECT, CONTEXT> readLock(CONTEXT context)
+ {
+ contexts.add(context);
+ return this;
+ }
+
+ public LockEntry<OBJECT, CONTEXT> writeLock(CONTEXT context)
+ {
+ return new WriteLockEntry<OBJECT, CONTEXT>(object, context, this);
+ }
+
+ public LockEntry<OBJECT, CONTEXT> readUnlock(CONTEXT context)
+ {
+ contexts.remove(context);
+ return contexts.isEmpty() ? null : this;
+ }
+
+ public LockEntry<OBJECT, CONTEXT> writeUnlock(CONTEXT context)
+ {
+ throw new IllegalMonitorStateException();
+ }
+
+ public LockEntry<OBJECT, CONTEXT> clearLock(CONTEXT context)
+ {
+ while (contexts.remove(context))
+ {
+ }
+
+ return contexts.isEmpty() ? null : this;
+ }
+
+ public void changeContext(CONTEXT oldContext, CONTEXT newContext)
+ {
+ if (contexts.remove(oldContext))
+ {
+ contexts.add(newContext);
+ }
+ }
+
+ public boolean hasContext(CONTEXT context)
+ {
+ return contexts.contains(context);
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("ReadLockEntry[object={0}, contexts={1}]", object, contexts);
+ }
+ }
+
+ /**
+ * @author Simon McDuff
+ */
+ private static final class WriteLockEntry<OBJECT, CONTEXT> implements LockEntry<OBJECT, CONTEXT>
+ {
+ private OBJECT object;
+
+ private CONTEXT context;
+
+ private int count;
+
+ private ReadLockEntry<OBJECT, CONTEXT> readLock;
+
+ public WriteLockEntry(OBJECT object, CONTEXT context, ReadLockEntry<OBJECT, CONTEXT> readLock)
+ {
+ this.object = object;
+ this.context = context;
+ this.readLock = readLock;
+ this.count = 1;
+ }
+
+ public OBJECT getObject()
+ {
+ return object;
+ }
+
+ public boolean isReadLock(CONTEXT context)
+ {
+ return readLock != null ? readLock.isReadLock(context) : false;
+ }
+
+ public boolean isWriteLock(CONTEXT context)
+ {
+ return ObjectUtil.equals(this.context, context);
+ }
+
+ public boolean isReadLockByOthers(CONTEXT context)
+ {
+ return readLock != null ? readLock.isReadLockByOthers(context) : false;
+ }
+
+ public boolean isWriteLockByOthers(CONTEXT context)
+ {
+ return context != this.context;
+ }
+
+ public boolean canObtainWriteLock(CONTEXT context)
+ {
+ return ObjectUtil.equals(this.context, context);
+ }
+
+ public boolean canObtainReadLock(CONTEXT context)
+ {
+ return ObjectUtil.equals(this.context, context);
+ }
+
+ public LockEntry<OBJECT, CONTEXT> readLock(CONTEXT context)
+ {
+ ReadLockEntry<OBJECT, CONTEXT> lock = getReadLock();
+ lock.readLock(context);
+ return this;
+ }
+
+ public LockEntry<OBJECT, CONTEXT> writeLock(CONTEXT context)
+ {
+ count++;
+ return this;
+ }
+
+ public LockEntry<OBJECT, CONTEXT> readUnlock(CONTEXT context)
+ {
+ if (readLock != null)
+ {
+ if (readLock.readUnlock(context) == null)
+ {
+ readLock = null;
+ }
+
+ return this;
+ }
+
+ throw new IllegalMonitorStateException();
+ }
+
+ public LockEntry<OBJECT, CONTEXT> writeUnlock(CONTEXT context)
+ {
+ return --count <= 0 ? readLock : this;
+ }
+
+ public LockEntry<OBJECT, CONTEXT> clearLock(CONTEXT context)
+ {
+ if (readLock != null)
+ {
+ if (readLock.clearLock(context) == null)
+ {
+ readLock = null;
+ }
+ }
+
+ return ObjectUtil.equals(this.context, context) ? readLock : this;
+ }
+
+ public void changeContext(CONTEXT oldContext, CONTEXT newContext)
+ {
+ if (ObjectUtil.equals(context, oldContext))
+ {
+ context = newContext;
+ }
+ }
+
+ public boolean hasContext(CONTEXT context)
+ {
+ return ObjectUtil.equals(this.context, context);
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("WriteLockEntry[object={0}, context={1}, count={2}]", object, context, count);
+ }
+
+ private ReadLockEntry<OBJECT, CONTEXT> getReadLock()
+ {
+ if (readLock == null)
+ {
+ readLock = new ReadLockEntry<OBJECT, CONTEXT>(object, context);
+ }
+
+ return readLock;
+ }
+ }
+
+ /**
+ * @author Simon McDuff
+ */
+ private static final class NoLockEntry<OBJECT, CONTEXT> implements LockEntry<OBJECT, CONTEXT>
+ {
+ private OBJECT object;
+
+ public NoLockEntry(OBJECT objectToLock)
+ {
+ this.object = objectToLock;
+ }
+
+ public OBJECT getObject()
+ {
+ return object;
+ }
+
+ public boolean isReadLock(CONTEXT context)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isWriteLock(CONTEXT context)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isReadLockByOthers(CONTEXT context)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isWriteLockByOthers(CONTEXT context)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean canObtainWriteLock(CONTEXT context)
+ {
+ return true;
+ }
+
+ public boolean canObtainReadLock(CONTEXT context)
+ {
+ return true;
+ }
+
+ public LockEntry<OBJECT, CONTEXT> readLock(CONTEXT context)
+ {
+ return new ReadLockEntry<OBJECT, CONTEXT>(object, context);
+ }
+
+ public LockEntry<OBJECT, CONTEXT> writeLock(CONTEXT context)
+ {
+ return new WriteLockEntry<OBJECT, CONTEXT>(object, context, null);
+ }
+
+ public LockEntry<OBJECT, CONTEXT> readUnlock(CONTEXT context)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public LockEntry<OBJECT, CONTEXT> writeUnlock(CONTEXT context)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public LockEntry<OBJECT, CONTEXT> clearLock(CONTEXT context)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void changeContext(CONTEXT oldContext, CONTEXT newContext)
+ {
+ // Do nothing
+ }
+
+ public boolean hasContext(CONTEXT context)
+ {
+ return false;
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("NoLockEntry[object={0}]", object);
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private static final class LockChanged
+ {
+ }
+}
|