/*
 * Written by Dirk Gorissen and Dawid Kurzyniec and released to the public
 * domain, as explained at http://creativecommons.org/licenses/publicdomain
 */

package edu.emory.mathcs.util.remote.locks;

import java.rmi.*;

import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;

/**
 * Interface mirroring the Lock interface in java.util.concurrent
 * but allowing for RemoteExceptions since an implementation
 * will involve network communication.
 *
 * Semantics of equals: two remote locks should be considered equal w.r.t.
 * the equals() method iff they represent the same remote lock, i.e. method
 * calls on each of them must perform the same actions. In particular, it must
 * be possible to call lock() on one of the objects and successful unlock()
 * on the other.
 *
 * @author Dirk Gorissen <dgorissen@gmx.net>
 * @author Dawid Kurzyniec
 */
public interface RemoteLock extends Remote {

    /**
     * Acquires the remote lock.
     * If the lock is not available then the current thread becomes disabled
     * for thread scheduling purposes and lies dormant until the lock has been acquired.
     *
     * @throws RemoteException if a communication error occurs
     */
    public void lock() throws RemoteException;


    /**
     * Acquires the remote lock unless the current thread is interrupted.
     * If the lock is not available then the current thread becomes
     * disabled for thread scheduling purposes and lies dormant until
     * one of two things happens:
     * <ul>
     * <li>The lock is acquired by the current thread; or
     * <li>Some other thread interrupts the current thread, and interruption
     *     of lock acquisition is supported.
     * </ul>
     *
     * @throws InterruptedException if the current thread is interrupted
     * while acquiring the lock (and interruption of lock acquisition is
     * supported).
     * @throws RemoteException if a communication error occurs
     */
    public void lockInterruptibly() throws InterruptedException,
            RemoteException;

    /**
     * Acquires the remote lock only if it is free at the time of invocation.
     * If the lock is not available then this method will return
     * immediately with the value <tt>false</tt>.
     *
     * @return <tt>true</tt> if the lock was acquired and <tt>false</tt>
     * otherwise.
     * @throws RemoteException if a communication error occurs
     */
    public boolean tryLock() throws RemoteException;

    /**
     * Acquires the remote lock if it is free within the given waiting time and the
     * current thread has not been interrupted.
     *
     * If the lock is not available then the current thread becomes disabled
     * for thread scheduling purposes and lies dormant until one of three things happens:
     * <ul>
     * <li>The lock is acquired by the current thread; or
     * <li>Some other thread interrupts the current thread, and interruption of
     *     lock acquisition is supported; or
     * <li>The specified waiting time elapses
     * </ul>
     *
     * @param time the maximum time to wait for the lock
     * @param unit the time unit of the <tt>time</tt> argument.
     * @return <tt>true</tt> if the lock was acquired and <tt>false</tt>
     * if the waiting time elapsed before the lock was acquired.
     *
     * @throws InterruptedException if the current thread is interrupted
     * while acquiring the lock (and interruption of lock acquisition is
     * supported).
     * @throws RemoteException if a communication error occurs
     */
    public boolean tryLock(long time, TimeUnit unit)
        throws InterruptedException, RemoteException;

    /**
     * Releases the remote lock.
     *
     * @throws RemoteException if a communication error occurs
     */
    public void unlock() throws RemoteException;

    /**
     * Returns a new Condition instance that is bound to this <tt>RemoteLock</tt> instance.
     * Before waiting on the condition the lock must be held by the current thread.
     *
     * @return A new Condition instance for this <tt>RemoteLock</tt>
     * instance.
     **/
    public RemoteCondition newCondition() throws RemoteException;
}
