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 }