1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.nio.channels;
19
20import java.io.IOException;
21
22/**
23 * A {@code FileLock} represents a locked region of a file.
24 * <p>
25 * Locks have certain properties that enable collaborating processes to avoid
26 * the lost update problem or reading inconsistent data. Logically, a file lock
27 * can be <em>exclusive</em> or <em>shared</em>. Multiple processes can hold
28 * shared locks on the same region of a file, but only a single process can hold
29 * an exclusive lock on a given region of a file and no other process can
30 * simultaneously hold a shared lock overlapping the exclusive lock. An
31 * application can determine whether a {@code FileLock} is shared or exclusive
32 * via the {@code isShared()} method.
33 * <p>
34 * Locks held by a particular process cannot overlap one another. Applications
35 * can determine whether a proposed lock will overlap by using the {@code
36 * overlaps(long, long)}) method. Locks held in other processes may overlap
37 * locks held in this process. Locks are shared amongst all threads in the
38 * acquiring process, and are therefore unsuitable for intra-process
39 * synchronization.
40 * <p>
41 * Once a lock is acquired, it is immutable in all its state except {@code
42 * isValid()}. The lock will initially be valid, but may be rendered invalid by
43 * explicit removal of the lock, using {@code release()}, or implicitly by
44 * closing the channel or exiting the process (terminating the VM).
45 * <h3>Platform dependencies</h3>
46 * <p>
47 * Locks are intended to be true platform operating system file locks, and
48 * therefore locks held by the VM will be visible to other
49 * operating system processes.
50 * <p>
51 * The characteristics of the underlying operating system locks will show
52 * through in the Java implementation. For example, some platforms' locks are
53 * 'mandatory' -- meaning the operating system enforces the locks on processes
54 * that attempt to access locked regions of files; whereas other platforms'
55 * locks are only 'advisory' -- meaning that processes are required to
56 * collaborate to ensure locks are acquired and there is a potential for
57 * processes to not play well. To be on the safe side, it is best to assume that
58 * the platform is adopting advisory locks and always acquire shared locks when
59 * reading a region of a file.
60 * <p>
61 * On some platforms, the presence of a lock will prevent the file from being
62 * memory-mapped. On some platforms, closing a channel on a given file handle
63 * will release all the locks held on that file -- even if there are other
64 * channels open on the same file; their locks will also be released. The safe
65 * option here is to ensure that you only acquire locks on a single channel for
66 * a particular file and that becomes the synchronization point.
67 * <p>
68 * Further care should be exercised when locking files maintained on network
69 * file systems, since they often have further limitations.
70 */
71public abstract class FileLock implements AutoCloseable {
72
73    // The underlying file channel.
74    private final FileChannel channel;
75
76    // The lock starting position.
77    private final long position;
78
79    // The lock length in bytes
80    private final long size;
81
82    // If true then shared, if false then exclusive
83    private final boolean shared;
84
85    /**
86     * Constructs a new file lock instance for a given channel. The constructor
87     * enforces the starting position, length and sharing mode of the lock.
88     *
89     * @param channel
90     *            the underlying file channel that holds the lock.
91     * @param position
92     *            the starting point for the lock.
93     * @param size
94     *            the length of the lock in number of bytes.
95     * @param shared
96     *            the lock's sharing mode of lock; {@code true} is shared,
97     *            {@code false} is exclusive.
98     */
99    protected FileLock(FileChannel channel, long position, long size, boolean shared) {
100        if (position < 0 || size < 0 || position + size < 0) {
101            throw new IllegalArgumentException("position=" + position + " size=" + size);
102        }
103        this.channel = channel;
104        this.position = position;
105        this.size = size;
106        this.shared = shared;
107    }
108
109    /**
110     * Returns the lock's {@link FileChannel}.
111     */
112    public final FileChannel channel() {
113        return channel;
114    }
115
116    /**
117     * Returns the lock's starting position in the file.
118     *
119     * @return the lock position.
120     */
121    public final long position() {
122        return position;
123    }
124
125    /**
126     * Returns the length of the file lock in bytes.
127     *
128     * @return the size of the file lock in bytes.
129     */
130    public final long size() {
131        return size;
132    }
133
134    /**
135     * Indicates if the file lock is shared with other processes or if it is
136     * exclusive.
137     *
138     * @return {@code true} if the lock is a shared lock, {@code false} if it is
139     *         exclusive.
140     */
141    public final boolean isShared() {
142        return shared;
143    }
144
145    /**
146     * Indicates if the receiver's lock region overlaps the region described
147     * in the parameter list.
148     *
149     * @param start
150     *            the starting position for the comparative lock.
151     * @param length
152     *            the length of the comparative lock.
153     * @return {@code true} if there is an overlap, {@code false} otherwise.
154     */
155    public final boolean overlaps(long start, long length) {
156        final long end = position + size - 1;
157        final long newEnd = start + length - 1;
158        if (end < start || position > newEnd) {
159            return false;
160        }
161        return true;
162    }
163
164    /**
165     * Indicates whether this lock is a valid file lock. The lock is
166     * valid unless the underlying channel has been closed or it has been
167     * explicitly released.
168     *
169     * @return {@code true} if the lock is valid, {@code false} otherwise.
170     */
171    public abstract boolean isValid();
172
173    /**
174     * Releases this particular lock on the file. If the lock is invalid then
175     * this method has no effect. Once released, the lock becomes invalid.
176     *
177     * @throws ClosedChannelException
178     *             if the channel is already closed when an attempt to release
179     *             the lock is made.
180     * @throws IOException
181     *             if another I/O error occurs.
182     */
183    public abstract void release() throws IOException;
184
185    /**
186     * Calls {@link #release} for {@code AutoCloseable}.
187     *
188     * @since 1.7
189     */
190    public final void close() throws IOException {
191        release();
192    }
193
194    /**
195     * Returns a string that shows the details of the lock suitable for debugging.
196     */
197    @Override
198    public final String toString() {
199        return "FileLock[position=" + position + ", size=" + size + ", shared=" + shared + "]";
200    }
201}
202