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 }