001package co.codewizards.cloudstore.core.io;
002
003import java.io.IOException;
004import java.io.InputStream;
005import java.io.OutputStream;
006import java.util.concurrent.locks.Lock;
007
008import co.codewizards.cloudstore.core.oio.File;
009
010/**
011 * Lock-file exclusively locking a certain {@link #getFile() file}.
012 * <p>
013 * An instance is acquired by invoking {@link LockFileFactory#acquire(File, long)}.
014 * <p>
015 * All methods of this interface are thread-safe.
016 * <p>
017 * <b>Important:</b> You should never access the {@linkplain #getFile() locked file} directly. Though this
018 * works fine on some operating systems (e.g. on GNU/Linux), it fails on others (e.g. on Windows). If you
019 * want to read from / write to the locked file, please use {@link #createInputStream()} or
020 * {@link #createOutputStream()} instead.
021 * @author Marco หงุ่ยตระกูล-Schulze - marco at codewizards dot co
022 */
023public interface LockFile extends AutoCloseable {
024
025        /**
026         * Gets the underlying file being locked.
027         * @return the underlying file being locked. Never <code>null</code>.
028         */
029        File getFile();
030
031        /**
032         * Releases the lock.
033         * <p>
034         * <b>Important:</b> This method <b>must</b> be called <b>exactly once</b> for every {@code LockFile} instance!
035         * It is highly recommended to use a try-finally-block:
036         * <pre>  LockFile lockFile = LockFileFactory.acquire(theFile, theTimeout);
037         *  try {
038         *    // do something
039         *  } finally {
040         *    lockFile.release();
041         *  }</pre>
042         *  <p>
043         *  This method is thread-safe and thus might be invoked on a different thread than the instance
044         *  was created. However, it should be invoked exactly once (per {@code LockFile} instance).
045         *  <p>
046         *  Please note: It is possible to use the new try-with-resources-clause introduced by Java 7. See
047         *  {@link #close()}.
048         *  @see LockFileFactory#acquire(File, long)
049         *  @see #close()
050         */
051        void release();
052
053        /**
054         * Equivalent to {@link #release()}.
055         * <p>
056         * Implementations must make sure that invoking {@code close()} means exactly the same as invoking
057         * {@code release()}. This method was added to make the usage of {@code LockFile} possible in a
058         * try-with-resources-clause. See {@link AutoCloseable} for more details. Here's a code example:
059         * <pre>  try ( LockFile lockFile = LockFileFactory.acquire(theFile, theTimeout); ) {
060         *    // do something while the file represented by 'lockFile' is locked.
061         *  }</pre>
062         * <p>
063         * @see #release()
064         */
065        @Override
066        public void close();
067
068        /**
069         * Gets the {@code Lock} corresponding to the underlying file to synchronise multiple threads of the same
070         * process.
071         * <p>
072         * A {@code LockFile} (usually implemented using {@link java.nio.channels.FileLock FileLock}) is not
073         * guaranteed to exclude multiple threads from accessing a single file. In order to additionally provide
074         * thread-synchronisation (as is pretty straight-forward and needed in many situations), there is a
075         * {@link Lock} associated to every {@code LockFile}. It is highly recommended to synchronise additionally
076         * on this {@code Lock}. Note, that {@link #createInputStream()} and {@link #createOutputStream()} are
077         * expected to implicitly do this.
078         * @return the {@code Lock} corresponding to the underlying file. Never <code>null</code>.
079         */
080        Lock getLock();
081
082        /**
083         * Creates an {@link InputStream} reading from the {@linkplain #getFile() locked file}.
084         * <p>
085         * <b>Important:</b> You must {@linkplain InputStream#close() close} the {@code InputStream}! Locks held
086         * are released only when doing so.
087         * @return an {@link InputStream} reading from the {@linkplain #getFile() locked file}. Never
088         * <code>null</code>.
089         * @throws IOException if creating the {@link InputStream} fails.
090         */
091        IInputStream createInputStream() throws IOException;
092
093        /**
094         * Creates an {@link OutputStream} writing into the {@linkplain #getFile() locked file} (overwriting
095         * all old content).
096         * <p>
097         * <b>Important:</b> You must {@linkplain OutputStream#close() close} the {@code OutputStream}! Locks
098         * held are released only when doing so.
099         * @return an {@link OutputStream} writing into the {@linkplain #getFile() locked file}. Never
100         * <code>null</code>.
101         * @throws IOException if creating the {@link OutputStream} fails.
102         */
103        IOutputStream createOutputStream() throws IOException;
104
105}