001    /*
002     * Created on May 24, 2007
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005     * in compliance with the License. You may obtain a copy of the License at
006     *
007     * http://www.apache.org/licenses/LICENSE-2.0
008     *
009     * Unless required by applicable law or agreed to in writing, software distributed under the License
010     * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011     * or implied. See the License for the specific language governing permissions and limitations under
012     * the License.
013     *
014     * Copyright @2007-2010 the original author or authors.
015     */
016    package org.fest.swing.lock;
017    
018    import static org.fest.util.Strings.concat;
019    
020    import java.util.concurrent.locks.*;
021    
022    import net.jcip.annotations.GuardedBy;
023    import net.jcip.annotations.ThreadSafe;
024    
025    import org.fest.swing.exception.ScreenLockException;
026    
027    /**
028     * Understands a lock that each GUI test should acquire before being executed, to guarantee sequential execution of
029     * GUI tests and to prevent GUI tests from blocking each other.
030     *
031     * @author Yvonne Wang
032     * @author Alex Ruiz
033     */
034    @ThreadSafe
035    public final class ScreenLock {
036    
037      private final Lock lock = new ReentrantLock();
038      private final Condition released = lock.newCondition();
039    
040      @GuardedBy("lock")
041      private Object owner;
042    
043      @GuardedBy("lock")
044      private boolean acquired;
045    
046      /**
047       * Acquires this lock. If this lock was already acquired by another object, this method will block until the lock is
048       * released.
049       * @param newOwner the new owner of the lock.
050       */
051      public void acquire(Object newOwner) {
052        lock.lock();
053        try {
054          if (alreadyAcquiredBy(newOwner)) return;
055          while (acquired) released.await();
056          owner = newOwner;
057          acquired = true;
058        } catch (InterruptedException ignored) {
059          Thread.currentThread().interrupt();
060        } finally {
061          lock.unlock();
062        }
063      }
064    
065      /**
066       * Releases this lock.
067       * @param currentOwner the current owner of the lock.
068       * @throws ScreenLockException if the lock has not been previously acquired.
069       * @throws ScreenLockException if the given owner is not the same as the current owner of the lock.
070       */
071      public void release(Object currentOwner) {
072        lock.lock();
073        try {
074          if (!acquired) throw new ScreenLockException("No lock to release");
075          if (owner != currentOwner) throw new ScreenLockException(concat(currentOwner, " is not the lock owner"));
076          acquired = false;
077          owner = null;
078          released.signal();
079        } finally {
080          lock.unlock();
081        }
082      }
083    
084      /**
085       * Indicates whether this lock was acquired by the given object.
086       * @param possibleOwner the given object, which could be owning the lock.
087       * @return <code>true</code> if the given object is owning the lock; <code>false</code> otherwise.
088       */
089      public boolean acquiredBy(Object possibleOwner) {
090        lock.lock();
091        try {
092          return alreadyAcquiredBy(possibleOwner);
093        } finally {
094          lock.unlock();
095        }
096      }
097    
098      private boolean alreadyAcquiredBy(Object possibleOwner) {
099        return acquired && owner == possibleOwner;
100      }
101    
102      /**
103       * Indicates whether this lock is already acquired.
104       * @return <code>true</code> if the lock is already acquired; <code>false</code> otherwise.
105       * @see #acquiredBy(Object)
106       * @since 1.2
107       */
108      public boolean acquired() {
109        lock.lock();
110        try {
111          return acquired;
112        } finally {
113          lock.unlock();
114        }
115      }
116    
117      /**
118       * Returns the singleton instance of this class.
119       * @return the singleton instance of this class.
120       */
121      public static ScreenLock instance() { return ScreenLockHolder.instance; }
122    
123      private static class ScreenLockHolder {
124        static ScreenLock instance = new ScreenLock();
125      }
126    
127      ScreenLock() {}
128    }