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}