001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.nio.channels;
019:
020: import java.io.IOException;
021:
022: /**
023: * A <code>FileLock</code> represents a locked region of a file.
024: * <p>
025: * Locks have certain properties that enable collaborating processes to avoid
026: * the lost update problem, or reading inconsistent data.
027: * </p>
028: * <p>
029: * logically, a file lock can be 'exclusive' or 'shared'. Multiple processes can
030: * hold shared locks on the same region of a file, but only a single process can
031: * hold an exclusive lock on a given region of a file and no other process can
032: * simultaneously hold a shared lock overlapping the exclusive lock. An
033: * application can determine whether a FileLock is shared or exclusive via the
034: * <code>isShared()</code> API.
035: * </p>
036: * <p>
037: * Locks held by a particular process cannot overlap one another. Applications
038: * can determine whether a proposed lock will overlap by using the
039: * <code>overlaps(long, long)</code) API. Locks held in
040: * other processes may overlap locks held in this process.</p>
041: * <p>
042: * Locks are shared amongst all threads in the acquiring process, and are therefore unsuitable for
043: * intra-process synchronization.</p>
044: * <p>
045: * Once a lock is acquired it is immutable in all its state except <code>isValid()</code>. The lock
046: * will initially be valid, but may be rendered invalid by explicit removal of the lock, using <code>
047: * release()</code>, or implicitly by closing the channel or exiting the process (terminating the JVM).</p>
048: * <p>
049: * <em>Platform dependencies</em></p>
050: * <p>
051: * Locks are intended to be true platform operating system file locks, and therefore locks held by the
052: * JVM process will be visible to other OS processes.</p>
053: * <p>
054: * The characteristics of the underlying OS locks will show through in the Java implementation. For
055: * example, some platforms' locks are 'mandatory' -- meaning the operating system enforces the locks
056: * on processes that attempt to access locked regions of file; whereas other platforms' locks are
057: * only 'advisory' -- meaning that processes are required to collaborate on ensuring locks are acquired
058: * and there is a potential for processes not to play well. The only safe answer is to assume that
059: * the platform is adopting advisory locks an always acquire shared locks when reading a region of file.</p>
060: * <p>
061: * On some platforms the presence of a lock will prevent the file being memory mapped. On some platforms
062: * closing a channel on a given file handle will release all the locks held on that file -- even if there
063: * are other channels open on the same file (their locks will be released). The safe option here is to
064: * ensure that you only acquire locks on a single channel for a particular file, and that becomes the
065: * synchronization point.</p>
066: * <p>
067: * Further care should be exercised when locking files maintained on network file systems since they often
068: * have further limitations.</p>
069: *
070: */
071: public abstract class FileLock {
072:
073: // The underlying file channel.
074: private final FileChannel channel;
075:
076: // The lock starting position.
077: private final long position;
078:
079: // The lock length in bytes
080: private final long size;
081:
082: // If true then shared, if false then exclusive
083: private final boolean shared;
084:
085: /**
086: * Constructor for a new file lock instance for a given channel. The
087: * constructor enforces the starting position, stretch, and shared status of
088: * the lock.
089: *
090: * @param channel
091: * underlying file channel that holds the lock.
092: * @param position
093: * starting point for the lock.
094: * @param size
095: * length of lock in number of bytes.
096: * @param shared
097: * shared status of lock (true is shared, false is exclusive).
098: */
099: protected FileLock(FileChannel channel, long position, long size,
100: boolean shared) {
101: super ();
102: if (position < 0 || size < 0 || position + size < 0) {
103: throw new IllegalArgumentException();
104: }
105: this .channel = channel;
106: this .position = position;
107: this .size = size;
108: this .shared = shared;
109: }
110:
111: /**
112: * Answers the lock's FileChannel.
113: *
114: * @return the channel.
115: */
116: public final FileChannel channel() {
117: return channel;
118: }
119:
120: /**
121: * Answers the lock's starting position in the file.
122: *
123: * @return the lock position.
124: */
125: public final long position() {
126: return position;
127: }
128:
129: /**
130: * Answers the length of the file lock in bytes.
131: *
132: * @return the size of file lock in bytes.
133: */
134: public final long size() {
135: return size;
136: }
137:
138: /**
139: * Answers true if the file lock is shared with other processes and false if
140: * it is not.
141: *
142: * @return true if the lock is a shared lock, and false if it is exclusive.
143: */
144: public final boolean isShared() {
145: return shared;
146: }
147:
148: /**
149: * Answers true if the receiver's lock region overlapps the region described
150: * in the parameter list,and answers false otherwise.
151: *
152: * @param start
153: * the starting position for the comparative lock.
154: * @param length
155: * the length of the comparative lock.
156: * @return true if there is an overlap, and false otherwise.
157: */
158: public final boolean overlaps(long start, long length) {
159: final long end = position + size - 1;
160: final long newEnd = start + length - 1;
161: if (end < start || position > newEnd) {
162: return false;
163: }
164: return true;
165: }
166:
167: /**
168: * Answers whether the receiver is a valid file lock or not. The lock is
169: * valid unless the underlying channel has been closed or it has been
170: * explicitly released.
171: *
172: * @return true if the lock is valid, and false otherwise.
173: */
174: public abstract boolean isValid();
175:
176: /**
177: * Releases this particular lock on the file. If the lock is invalid then
178: * this method has no effect. Once released the lock becomes invalid.
179: *
180: * @throws ClosedChannelException
181: * if the channel is already closed when an attempt to release
182: * the lock is made.
183: * @throws IOException
184: * some other IO exception occurred.
185: */
186: public abstract void release() throws IOException;
187:
188: /**
189: * Answers a string that shows the details of the lock suitable for display
190: * to an end user.
191: *
192: * @return the display string.
193: */
194: @Override
195: @SuppressWarnings("nls")
196: public final String toString() {
197: StringBuffer buffer = new StringBuffer(64); // Guess length of string
198: buffer.append("FileLock: [position=");
199: buffer.append(position);
200: buffer.append(", size=");
201: buffer.append(size);
202: buffer.append(", shared=");
203: buffer.append(Boolean.toString(shared));
204: buffer.append("]");
205: return buffer.toString();
206: }
207: }
|