/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.tests;

import EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock;
import EDU.oswego.cs.dl.util.concurrent.Sync;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.jboss.cache.lock.SimpleReadWriteLock;

/**
 * Tests ReentrantWriterPreferenceReadWriteLock
 * @author Bela Ban
 * @version $Id: ReentrantWriterPreferenceReadWriteLockTest.java,v 1.3.2.2 2005/04/06 21:07:04 starksm Exp $
 */
public class ReentrantWriterPreferenceReadWriteLockTest extends TestCase {
   // ReentrantWriterPreferenceReadWriteLock lock;
   SimpleReadWriteLock lock;
   Sync rl, wl;
   Exception thread_ex=null;

   protected void setUp() throws Exception {
      super.setUp();
      // lock=new ReentrantWriterPreferenceReadWriteLock();
      lock=new SimpleReadWriteLock();
      rl=lock.readLock();
      wl=lock.writeLock();
      thread_ex=null;
   }

   protected void tearDown() throws Exception {
      super.tearDown();
      lock=null;
      if(thread_ex != null)
         throw thread_ex;
   }

   public void testMultipleReadLockAcquisitions() throws InterruptedException {
      rl.acquire();
      rl.acquire();
   }

   public void testMultipleWriteLockAcquisitions() throws InterruptedException {
      wl.acquire();
      wl.acquire();
   }

   public void testMultipleReadLockReleases() throws InterruptedException {
      rl.acquire();
      rl.release();
      try {
         rl.release();
         fail("we should not get here, cannot acquire RL once but release twice");
      }
      catch(IllegalStateException illegalState) {
         // this is as expected
      }
   }


   public void acquireReadAndWriteLocks() throws InterruptedException {
      rl.acquire();
      rl.acquire();
      boolean fl=wl.attempt(4000);
      assertTrue(fl);
   }


   public void acquireWriteThenReadLock() throws InterruptedException {
      wl.acquire();
      rl.acquire();
      wl.release();
      rl.release();
   }

   public void testMultipleWriteLockReleases() throws InterruptedException {
      wl.acquire();
      wl.release();
      wl.release();
   }

   public void testAcquireWriteLockAfterReadLock() throws InterruptedException {
      rl.acquire();
      wl.acquire();
   }


   public void testAcquiringReadLockedLockWithRead() throws InterruptedException {
      new Thread() {
         public void run() {
            try {rl.acquire();}
            catch(InterruptedException e) {}
         }
      }.start();

      sleep(500);

      // now we have a RL by another thread

      rl.acquire();
      rl.release();
      rl.release();
      wl.acquire();
   }

   public void testAcquiringReadLockedLock() throws InterruptedException {
      new Thread() {
         public void run() {
            try {rl.acquire();}
            catch(InterruptedException e) {}
         }
      }.start();

      sleep(500);

      // now we have a RL by another thread
      wl.acquire();
      rl.acquire();
   }

   public void test2ReadersAnd1Writer() throws InterruptedException {
      Upgrader upgrader=new Upgrader("Upgrader");
      Reader reader=new Reader("Reader");
      upgrader.start();
      reader.start();

      sleep(500);
      synchronized(upgrader) {
         upgrader.notify();
      }
      sleep(500);
      synchronized(reader) {
         reader.notify();
      }
      reader.join();
      upgrader.join();
   }


   public void testWriteThenReadByDifferentTx() throws InterruptedException {
      Writer writer=new Writer("Writer");
      Reader reader=new Reader("Reader");
      writer.start();
      sleep(500);
      reader.start();
      sleep(1000);

      synchronized(writer) {
         log("terminating Writer");
         writer.notify();
      }
      sleep(500);
      synchronized(reader) {
         reader.notify();
      }
      writer.join();
      reader.join();
   }

   public void testReadThenWriteByDifferentTx() throws InterruptedException {
      Writer writer=new Writer("Writer");
      Reader reader=new Reader("Reader");

      reader.start();
      sleep(500);
      writer.start();
      sleep(1000);

      synchronized(reader) {
         log("terminating Reader");
         reader.notify();
      }

      sleep(500);
      synchronized(writer) {
         writer.notify();
      }
      writer.join();
      reader.join();
   }



   private static void log(String msg) {
      System.out.println(System.currentTimeMillis() + "  " + Thread.currentThread() +
                         " [" + Thread.currentThread().getName() + "]: " + msg);
   }

   private static void sleep(long timeout) {
      try {
         Thread.sleep(timeout);
      }
      catch(InterruptedException e) {
      }
   }


   class Reader extends Thread {

      public Reader(String name) {
         super(name);
      }

      public void run() {
         try {
            log("acquiring RL");
            rl.acquire();
            log("acquired RL");
            synchronized(this) {
               this.wait();
            }
            log("releasing RL");
            rl.release();
            log("released RL");
         }
         catch(InterruptedException e) {
            ;
         }
      }
   }


   class Writer extends Thread {

      public Writer(String name) {
         super(name);
      }

      public void run() {
         try {
            log("acquiring WL");
            wl.acquire();
            log("acquired WL");
            synchronized(this) {
               this.wait();
            }
            log("releasing WL");
            wl.release();
            log("released WL");
         }
         catch(InterruptedException e) {
            ;
         }
      }
   }


   class Upgrader extends Thread {
      public Upgrader(String name) {
         super(name);
      }

      public void run() {
         try {
            log("acquiring RL");
            rl.acquire();
            log("acquired RL");
            synchronized(this) {
               this.wait();
            }
            log("attempting to acquire WL");
            // rl.release();
            wl.acquire();
            log("acquired WL");
            log("releasing WL/RL");
            wl.release();
            log("released WL/RL");
         }
         catch(InterruptedException e) {
            ;
         }
      }
   }



   public static Test suite() {
      return new TestSuite(ReentrantWriterPreferenceReadWriteLockTest.class);
   }

   public static void main(String[] args) {
      junit.textui.TestRunner.run(suite());
   }

}