/*
* Copyright (C) 2000 - 2010 TagServlet Ltd
*
* This file is part of Open BlueDragon (OpenBD) CFML Server Engine.
*
* OpenBD is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Free Software Foundation,version 3.
*
* OpenBD is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenBD. If not, see http://www.gnu.org/licenses/
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with any of the JARS listed in the README.txt (or a modified version of
* (that library), containing parts covered by the terms of that JAR, the
* licensors of this Program grant you additional permission to convey the
* resulting work.
* README.txt @ http://www.openbluedragon.org/license/README.txt
*
* http://www.openbluedragon.org/
*/
package com.naryx.tagfusion.cfm.tag;
import java.io.Serializable;
import java.util.Iterator;
import com.nary.util.FastMap;
import com.naryx.tagfusion.cfm.engine.cfData;
public class cfLockingObject extends cfData implements Serializable {
private static final long serialVersionUID = 1L;
private FastMap readOnly = new FastMap(); // keyed by Thread, holds readonly counters
private FastMap exclusive = new FastMap(); // keyed by Thread, hold exclusive counters
private int refCount;
public cfLockingObject() {
setImplicit(true); // part of fix for bug #2083
}
public String getString() {
return "";
}
public synchronized boolean isFree() {
return ((refCount == 0) && (readOnly.size() == 0) && (exclusive.size() == 0));
}
public synchronized void incrRefCount() {
refCount += 1;
}
public synchronized void decrRefCount() {
refCount -= 1;
}
public String toString() {
return "cfLockingObject; exclusive = " + exclusive + ", read-only = "
+ readOnly;
}
public boolean lock(String type, long msecs) {
return (type.equals(cfLOCK.TYPE_EXCLUSIVE) ? lockExclusive(msecs)
: lockReadOnly(msecs));
}
public void unlock(String type) {
if (type.equals(cfLOCK.TYPE_EXCLUSIVE))
unlockExclusive();
else
unlockReadOnly();
}
/**
* Return true if no thread other than the current thread has an exclusive
* lock.
*/
private synchronized boolean canGetReadOnlyLock(Thread currentThread) {
Iterator iter = exclusive.keySet().iterator();
while (iter.hasNext()) {
if ((Thread) iter.next() != currentThread)
return false;
}
return true;
}
private synchronized boolean getReadOnlyLock() {
Thread currentThread = Thread.currentThread();
// make sure no other thread has an exclusive lock
if (!canGetReadOnlyLock(currentThread))
return false;
// increment the read-only counter for this thread
Integer readOnlyCount = (Integer) readOnly.get(currentThread);
if (readOnlyCount == null) {
readOnlyCount = new Integer(0);
}
readOnly.put(currentThread, new Integer(readOnlyCount.intValue() + 1));
return true;
}
private boolean lockReadOnly(long msecs) {
if (getReadOnlyLock())
return true;
long startTime = System.currentTimeMillis();
long timeElapsed = 0;
long sleepInterval = 1;
while (timeElapsed < msecs) {
try {
Thread.sleep(sleepInterval);
} catch (InterruptedException e) {
}
if (getReadOnlyLock()) {
return true;
}
if (sleepInterval < 128) {
sleepInterval = sleepInterval * 2;
}
timeElapsed = System.currentTimeMillis() - startTime;
}
return getReadOnlyLock();
}
private synchronized void unlockReadOnly() {
Thread currentThread = Thread.currentThread();
if (readOnly.containsKey(currentThread)) {
// decrement the read-only counter for this thread
int readOnlyCount = ((Integer) readOnly.get(currentThread)).intValue() - 1;
if (readOnlyCount == 0)
readOnly.remove(currentThread);
else
readOnly.put(currentThread, new Integer(readOnlyCount));
}
}
/**
* Return true if no thread other than the current thread has an exclusive or
* read-only lock.
*/
private synchronized boolean getExclusiveLock() {
Thread currentThread = Thread.currentThread();
// make sure no other thread has an exclusive lock
if (!canGetReadOnlyLock(currentThread))
return false;
// make sure no other thread has a read-only lock
Iterator iter = readOnly.keySet().iterator();
while (iter.hasNext()) {
if ((Thread) iter.next() != currentThread)
return false;
}
// increment the exclusive counter for this thread
Integer exclusiveCount = (Integer) exclusive.get(currentThread);
if (exclusiveCount == null) {
exclusiveCount = new Integer(0);
}
exclusive.put(currentThread, new Integer(exclusiveCount.intValue() + 1));
return true;
}
private boolean lockExclusive(long msecs) {
if (getExclusiveLock())
return true;
long startTime = System.currentTimeMillis();
long timeElapsed = 0;
long sleepInterval = 1;
while (timeElapsed < msecs) {
try {
Thread.sleep(sleepInterval);
} catch (InterruptedException e) {
}
if (getExclusiveLock()) {
return true;
}
if (sleepInterval < 128) {
sleepInterval = sleepInterval * 2;
}
timeElapsed = System.currentTimeMillis() - startTime;
}
return getExclusiveLock();
}
private synchronized void unlockExclusive() {
Thread currentThread = Thread.currentThread();
if (exclusive.containsKey(currentThread)) {
// decrement the exclusive counter for this thread
int exclusiveCount = ((Integer) exclusive.get(currentThread)).intValue() - 1;
if (exclusiveCount == 0)
exclusive.remove(currentThread);
else
exclusive.put(currentThread, new Integer(exclusiveCount));
}
}
}