gt:         if (listener != null) {
context: /*
   * eXist Open Source Native XML Database
   * Copyright (C) 2005-2007 The eXist Project
   * http://exist-db.org
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
   * 
   * You should have received a copy of the GNU Lesser General Public License
   * along with this program; if not, write to the Free Software Foundation
   * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   *  
   *
   * File: ReentrantLock.java
   *
   * Originally written by Doug Lea and released into the public domain.
   * This may be used for any purposes whatsoever without acknowledgment.
   * Thanks for the assistance and support of Sun Microsystems Labs,
   * and everyone contributing, testing, and using this code.
   *
   * $Id$
   *
  */
  package org.exist.storage.lock;
  
  import java.io.PrintStream;
  import java.util.Stack;
  
  import org.apache.log4j.Logger;
  import org.exist.util.LockException;
  
  /**
   * A lock with the same semantics as builtin
   * Java synchronized locks: Once a thread has a lock, it
   * can re-obtain it any number of times without blocking.
   * The lock is made available to other threads when
   * as many releases as acquires have occurred.
   * 
   * The lock has a timeout: a read lock will be released if the
   * timeout is reached.
  */
  
  public class ReentrantReadWriteLock implements Lock {
  
      private static final int WAIT_CHECK_PERIOD = 200;
  
      private class SuspendedWaiter {
          Thread thread;
          int lockMode;
          int lockCount;
  
          public SuspendedWaiter(Thread thread, int lockMode, int lockCount) {
              this.thread = thread;
              this.lockMode = lockMode;
              this.lockCount = lockCount;
          }
      }
  
      private final static Logger LOG = Logger.getLogger(ReentrantReadWriteLock.class);
  
      protected Object id_ = null;
  	protected Thread owner_ = null;
      protected Stack<SuspendedWaiter> suspendedThreads = new Stack<SuspendedWaiter>();
  
      protected int holds_ = 0;
      public int mode_ = Lock.NO_LOCK;
      private Stack<Integer> modeStack = new Stack<Integer>();
      private int writeLocks = 0;
      private boolean DEBUG = false;
      private Stack<StackTraceElement[]> seStack;
      private LockListener listener = null;
  
      public ReentrantReadWriteLock(Object id) {
          id_ = id;
          if (DEBUG)
              {seStack = new Stack<StackTraceElement[]>();}
      }
  
      public String getId() {
          return id_.toString();
      }
  
      /* @deprecated Use other method
        * @see org.exist.storage.lock.Lock#acquire()
        */
      public boolean acquire() throws LockException {
          return acquire(Lock.READ_LOCK);
      }
  
      public boolean acquire(int mode) throws LockException {
          if (mode == Lock.NO_LOCK) {
              LOG.warn("acquired with no lock !");
              return true;
          }
          if (Thread.interrupted())
              {throw new LockException();}
          Thread caller = Thread.currentThread();
          synchronized (this) {
              WaitingThread waitingOnResource;
              if (caller == owner_) {
                  ++holds_;
                  modeStack.push(Integer.valueOf(mode));
                  if (mode == Lock.WRITE_LOCK)
                      {writeLocks++;}
                  if (DEBUG) {
                      final Throwable t = new Throwable();
                      seStack.push(t.getStackTrace());
                  }
                  mode_ = mode;
                  return true;
              } else if (owner_ == null) {
                  owner_ = caller;
                  holds_ = 1;
                  modeStack.push(Integer.valueOf(mode));
                  if (mode== Lock.WRITE_LOCK)
                      {writeLocks++;}
                  if (DEBUG) {
                      final Throwable t = new Throwable();
                      seStack.push(t.getStackTrace());
                  }
                  mode_ = mode;
                  return true;
              } else if ((waitingOnResource = 
                      DeadlockDetection.deadlockCheckResource(caller, owner_)) != null) {
                  waitingOnResource.suspendWaiting();
                  final SuspendedWaiter suspended = new SuspendedWaiter(owner_, mode_, holds_);
                  suspendedThreads.push(suspended);
                  owner_ = caller;
                  holds_ = 1;
                  modeStack.push(Integer.valueOf(mode));
                  if (mode== Lock.WRITE_LOCK)
                      {writeLocks++;}
                  mode_ = mode;
                  listener = waitingOnResource;
                  return true;
              } else {
                  DeadlockDetection.addCollectionWaiter(caller, this);
                  try {
                      for (;;) {
                          wait(WAIT_CHECK_PERIOD);
                          if ((waitingOnResource = DeadlockDetection.deadlockCheckResource(caller, owner_)) != null) {
                              waitingOnResource.suspendWaiting();
                              final SuspendedWaiter suspended = new SuspendedWaiter(owner_, mode_, holds_);
                              suspendedThreads.push(suspended);
                              owner_ = caller;
                              holds_ = 1;
                              modeStack.push(Integer.valueOf(mode));
                              if (mode== Lock.WRITE_LOCK)
                                  {writeLocks++;}
                              mode_ = mode;
                              listener = waitingOnResource;
                              DeadlockDetection.clearCollectionWaiter(owner_);
                              return true;
                          } else if (caller == owner_) {
                              ++holds_;
                              modeStack.push(Integer.valueOf(mode));
                              if (mode == Lock.WRITE_LOCK)
                                  {writeLocks++;}
                              if (DEBUG) {
                                  final Throwable t = new Throwable();
                                  seStack.push(t.getStackTrace());
                              }
                              mode_ = mode;
                              DeadlockDetection.clearCollectionWaiter(owner_);
                              return true;
                          } else if (owner_ == null) {
                              owner_ = caller;
                              holds_ = 1;
                              modeStack.push(Integer.valueOf(mode));
                              if (mode == Lock.WRITE_LOCK)
                                  {writeLocks++;}
                              if (DEBUG) {
                                  final Throwable t = new Throwable();
                                  seStack.push(t.getStackTrace());
                              }
                              mode_ = mode;
                              DeadlockDetection.clearCollectionWaiter(owner_);
                              return true;
                          }
                      }
                  } catch (final InterruptedException ex) {
                      notify();
                      throw new LockException("Interrupted while waiting for lock");
                  }
              }
          }
      }
  
      public synchronized void wakeUp() {
          notify();
      }
  
      public boolean attempt(int mode) {
          Thread caller = Thread.currentThread();
          synchronized (this) {
              if (caller == owner_) {
                  ++holds_;
                  modeStack.push(Integer.valueOf(mode));
                  if (mode == Lock.WRITE_LOCK)
                      {writeLocks++;}
                  if (DEBUG) {
                      final Throwable t = new Throwable();
                      seStack.push(t.getStackTrace());
                  }
                  mode_ = mode;
                  return true;
              } else if (owner_ == null) {
                  owner_ = caller;
                  holds_ = 1;
                  modeStack.push(Integer.valueOf(mode));
                  if (mode == Lock.WRITE_LOCK)
                      {writeLocks++;}
                  if (DEBUG) {
                      final Throwable t = new Throwable();
                      seStack.push(t.getStackTrace());
                  }
                  mode_ = mode;
                  return true;
              } else {
                  return false;
              }
          }
      }
  
      /* (non-Javadoc)
       * @see org.exist.util.Lock#isLockedForWrite()
       */
      public synchronized boolean isLockedForWrite() {
          return writeLocks > 0;
      }
  
      public boolean isLockedForRead(Thread owner) {
          // always returns false for this lock
          return false;
      }
  
      public synchronized boolean hasLock() {
          return holds_ > 0;
      }
  
      public boolean hasLock(Thread owner) {
          return this.owner_ == owner;
      }
  
      public Thread getOwner() {
          return this.owner_;
      }
  
      /* (non-Javadoc)
       * @see org.exist.util.Lock#release(int)
       */
      public synchronized void release(int mode) {
          if (Thread.currentThread() != owner_) {
              
              if(LOG.isDebugEnabled()){
                  LOG.warn("Possible lock problem: thread " + Thread.currentThread() +
                      " Released a lock on " + getId() + " it didn't hold." +
                      " Either the thread was interrupted or it never acquired the lock." +
                      " The lock was owned by: " + owner_);
              }
                     
              if (DEBUG) {
                  LOG.debug("Lock was acquired by :");
                  while (!seStack.isEmpty()) {
                      StackTraceElement[] se = seStack.pop();
                      LOG.debug(se);
                      se = null;
                  }
              }
              return;
          }
          Integer top = modeStack.pop();
          mode_ = top.intValue();
          top = null; 	
          if (mode_ != mode) {
              LOG.warn("Released lock of different type. Expected " + mode_ +
                  " got " + mode, new Throwable());
          }      	
          if (mode_ == Lock.WRITE_LOCK) {
              writeLocks--;
          }
          if (DEBUG) {
              seStack.pop();
          }
          if (--holds_ == 0) {
              if (!suspendedThreads.isEmpty()) {
                  final SuspendedWaiter suspended = suspendedThreads.pop();
                  owner_ = suspended.thread;
                  mode_ = suspended.lockMode;
                  holds_ = suspended.lockCount;
              } else {
                  owner_ = null;
                  mode_ = Lock.NO_LOCK;
                  notify();
              }
          }
  