Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2012-07-19 08:22:04 +0000
committerEike Stepper2012-07-19 08:22:04 +0000
commit1460904fd3c193ffaf809913b2983a400fce9d94 (patch)
tree72f3a17b75fedba3ae1060df1d32c9c7889be954 /plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWLockManager.java
parent5f360965ae87478e0681899bf310a210cafc2c44 (diff)
downloadcdo-1460904fd3c193ffaf809913b2983a400fce9d94.tar.gz
cdo-1460904fd3c193ffaf809913b2983a400fce9d94.tar.xz
cdo-1460904fd3c193ffaf809913b2983a400fce9d94.zip
Fix line endings in master (dos2unix)
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.java1586
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 50ae00b8af..7e6a9f2b12 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 - 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
- {
- }
-}
+/*
+ * 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
+ {
+ }
+}

Back to the top