/***********************************************************************
*
* $CVSHeader$
*
* This file is part of WebScarab, an Open Web Application Security
* Project utility. For details, please see http://www.owasp.org/
*
* Copyright (c) 2002 - 2004 Rogan Dawes
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Getting Source
* ==============
*
* Source for this application is maintained at Sourceforge.net, a
* repository for free software projects.
*
* For details, please see http://www.sourceforge.net/projects/owasp
*
*/
/*
* ReentrantReaderPreferenceReadWriteLock.java
*
* Created on September 8, 2004, 7:38 AM
*/
package org.owasp.webscarab.util;
import EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock;
import EDU.oswego.cs.dl.util.concurrent.Sync;
import java.util.Iterator;
/** Provides an implementation of a reentrant Read/Write lock that gives preference
* to readers, rather than writers. This makes sense in the context of the webscarab
* model because updates are fired with a read lock held, we want our listeners
* to be able to get back into the model to perform other reads, BEFORE any other
* writes are permitted.
*
* @author rogan
*/
public class ReentrantReaderPreferenceReadWriteLock extends ReentrantWriterPreferenceReadWriteLock {
private Sync _writeLock;
/** Creates a new instance of ReentrantReaderPreferenceReadWriteLock */
public ReentrantReaderPreferenceReadWriteLock() {
super();
_writeLock = new LoggingLock(super.writeLock());
}
/**
* Provides an implementation of a reentrant Read/Write lock that gives preference
* to readers, rather than writers. This makes sense in the context of the model,
* because updates are fired with a read lock held, we generally want our listeners
* to be able to get back into the model to perform other reads, BEFORE any other
* writes are permitted.
* @return true when there are no active writers, or the active writer is the current thread
*/
protected boolean allowReader() {
return activeWriter_ == null || activeWriter_ == Thread.currentThread();
}
public void debug() {
Iterator<?> it = readers_.keySet().iterator();
System.err.println("Readers:");
while(it.hasNext()) {
Object key = it.next();
Object value = readers_.get(key);
System.err.println(key + " : " + value);
}
System.err.println("Done");
System.err.println("Writer thread:");
System.err.println(activeWriter_ == null ? null : activeWriter_.getName());
System.err.println("Stack Trace:");
Thread.dumpStack();
}
public EDU.oswego.cs.dl.util.concurrent.Sync writeLock() {
return _writeLock;
}
private class LoggingLock implements Sync {
private Sync _sync;
public LoggingLock(Sync sync) {
_sync = sync;
}
public void acquire() throws InterruptedException {
// System.err.println(Thread.currentThread().getName() + " acquiring");
while (!_sync.attempt(5000)) {
debug();
}
// System.err.println(Thread.currentThread().getName() + " acquired");
}
public boolean attempt(long msecs) throws InterruptedException {
// System.err.println(Thread.currentThread().getName() + " attempting");
try {
boolean result = _sync.attempt(msecs);
if (result) {
// System.err.println(Thread.currentThread().getName() + " successful");
} else {
System.err.println(Thread.currentThread().getName() + "sync attempt unsuccessful");
}
return result;
} catch (InterruptedException ie) {
System.err.println(Thread.currentThread().getName() + " interrupted");
throw ie;
}
}
public void release() {
// System.err.println(Thread.currentThread().getName() + " releasing");
_sync.release();
// System.err.println(Thread.currentThread().getName() + " released");
}
}
}