package co.codewizards.cloudstore.core.io; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.concurrent.locks.Lock; import co.codewizards.cloudstore.core.oio.File; /** * Lock-file exclusively locking a certain {@link #getFile() file}. * <p> * An instance is acquired by invoking {@link LockFileFactory#acquire(File, long)}. * <p> * All methods of this interface are thread-safe. * <p> * <b>Important:</b> You should never access the {@linkplain #getFile() locked file} directly. Though this * works fine on some operating systems (e.g. on GNU/Linux), it fails on others (e.g. on Windows). If you * want to read from / write to the locked file, please use {@link #createInputStream()} or * {@link #createOutputStream()} instead. * @author Marco หงุ่ยตระกูล-Schulze - marco at codewizards dot co */ public interface LockFile extends AutoCloseable { /** * Gets the underlying file being locked. * @return the underlying file being locked. Never <code>null</code>. */ File getFile(); /** * Releases the lock. * <p> * <b>Important:</b> This method <b>must</b> be called <b>exactly once</b> for every {@code LockFile} instance! * It is highly recommended to use a try-finally-block: * <pre> LockFile lockFile = LockFileFactory.acquire(theFile, theTimeout); * try { * // do something * } finally { * lockFile.release(); * }</pre> * <p> * This method is thread-safe and thus might be invoked on a different thread than the instance * was created. However, it should be invoked exactly once (per {@code LockFile} instance). * <p> * Please note: It is possible to use the new try-with-resources-clause introduced by Java 7. See * {@link #close()}. * @see LockFileFactory#acquire(File, long) * @see #close() */ void release(); /** * Equivalent to {@link #release()}. * <p> * Implementations must make sure that invoking {@code close()} means exactly the same as invoking * {@code release()}. This method was added to make the usage of {@code LockFile} possible in a * try-with-resources-clause. See {@link AutoCloseable} for more details. Here's a code example: * <pre> try ( LockFile lockFile = LockFileFactory.acquire(theFile, theTimeout); ) { * // do something while the file represented by 'lockFile' is locked. * }</pre> * <p> * @see #release() */ @Override public void close(); /** * Gets the {@code Lock} corresponding to the underlying file to synchronise multiple threads of the same * process. * <p> * A {@code LockFile} (usually implemented using {@link java.nio.channels.FileLock FileLock}) is not * guaranteed to exclude multiple threads from accessing a single file. In order to additionally provide * thread-synchronisation (as is pretty straight-forward and needed in many situations), there is a * {@link Lock} associated to every {@code LockFile}. It is highly recommended to synchronise additionally * on this {@code Lock}. Note, that {@link #createInputStream()} and {@link #createOutputStream()} are * expected to implicitly do this. * @return the {@code Lock} corresponding to the underlying file. Never <code>null</code>. */ Lock getLock(); /** * Creates an {@link InputStream} reading from the {@linkplain #getFile() locked file}. * <p> * <b>Important:</b> You must {@linkplain InputStream#close() close} the {@code InputStream}! Locks held * are released only when doing so. * @return an {@link InputStream} reading from the {@linkplain #getFile() locked file}. Never * <code>null</code>. * @throws IOException if creating the {@link InputStream} fails. */ IInputStream createInputStream() throws IOException; /** * Creates an {@link OutputStream} writing into the {@linkplain #getFile() locked file} (overwriting * all old content). * <p> * <b>Important:</b> You must {@linkplain OutputStream#close() close} the {@code OutputStream}! Locks * held are released only when doing so. * @return an {@link OutputStream} writing into the {@linkplain #getFile() locked file}. Never * <code>null</code>. * @throws IOException if creating the {@link OutputStream} fails. */ IOutputStream createOutputStream() throws IOException; }