1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.apache.harmony.tests.java.nio.channels;
18
19import java.io.File;
20import java.io.FileInputStream;
21import java.io.FileOutputStream;
22import java.io.FileWriter;
23import java.io.IOException;
24import java.io.RandomAccessFile;
25import java.nio.channels.FileChannel;
26import java.nio.channels.FileLock;
27import java.nio.channels.NonReadableChannelException;
28import java.nio.channels.NonWritableChannelException;
29import java.nio.channels.OverlappingFileLockException;
30
31import junit.framework.TestCase;
32
33/**
34 * API tests for the NIO FileChannel locking APIs
35 */
36public class FileChannelLockingTest extends TestCase {
37
38    private FileChannel readOnlyChannel;
39
40    private FileChannel writeOnlyChannel;
41
42    private FileChannel readWriteChannel;
43
44    private final String CONTENT = "The best things in life are nearest: Breath in your nostrils, light in your eyes, "
45            + "flowers at your feet, duties at your hand, the path of right just before you. Then do not grasp at the stars, "
46            + "but do life's plain, common work as it comes, certain that daily duties and daily bread are the sweetest "
47            + " things in life.--Robert Louis Stevenson";
48
49    protected void setUp() throws Exception {
50        super.setUp();
51
52        // Create a three temporary files with content.
53        File[] tempFiles = new File[3];
54        for (int i = 0; i < tempFiles.length; i++) {
55            tempFiles[i] = File.createTempFile("testing", "tmp");
56            tempFiles[i].deleteOnExit();
57            FileWriter writer = new FileWriter(tempFiles[i]);
58            writer.write(CONTENT);
59            writer.close();
60        }
61
62        // Open read, write, and read/write channels on the temp files.
63        FileInputStream fileInputStream = new FileInputStream(tempFiles[0]);
64        readOnlyChannel = fileInputStream.getChannel();
65
66        FileOutputStream fileOutputStream = new FileOutputStream(tempFiles[1]);
67        writeOnlyChannel = fileOutputStream.getChannel();
68
69        RandomAccessFile randomAccessFile = new RandomAccessFile(tempFiles[2],
70                "rw");
71        readWriteChannel = randomAccessFile.getChannel();
72    }
73
74    protected void tearDown() throws IOException {
75        if (readOnlyChannel != null) {
76            readOnlyChannel.close();
77        }
78        if (writeOnlyChannel != null) {
79            writeOnlyChannel.close();
80        }
81        if (readWriteChannel != null) {
82            readWriteChannel.close();
83        }
84    }
85
86    public void test_illegalLocks() throws IOException {
87        // Cannot acquire an exclusive lock on a read-only file channel
88        try {
89            readOnlyChannel.lock();
90            fail("Acquiring a full exclusive lock on a read only channel should fail.");
91        } catch (NonWritableChannelException ex) {
92            // Expected.
93        }
94
95        // Cannot get a shared lock on a write-only file channel.
96        try {
97            writeOnlyChannel.lock(1, 10, true);
98            fail("Acquiring a shared lock on a write-only channel should fail.");
99        } catch (NonReadableChannelException ex) {
100            // expected
101        }
102    }
103
104    public void test_lockReadWrite() throws IOException {
105        // Acquire an exclusive lock across the entire file.
106        FileLock flock = readWriteChannel.lock();
107        if (flock != null) {
108            flock.release();
109        }
110    }
111
112    public void test_illegalLockParameters() throws IOException {
113        // Cannot lock negative positions
114        try {
115            readOnlyChannel.lock(-1, 10, true);
116            fail("Passing illegal args to lock should fail.");
117        } catch (IllegalArgumentException ex) {
118            // expected
119        }
120        try {
121            writeOnlyChannel.lock(-1, 10, false);
122            fail("Passing illegal args to lock should fail.");
123        } catch (IllegalArgumentException ex) {
124            // expected
125        }
126        try {
127            readWriteChannel.lock(-1, 10, false);
128            fail("Passing illegal args to lock should fail.");
129        } catch (IllegalArgumentException ex) {
130            // expected
131        }
132
133        // Lock a range at the front, shared.
134        FileLock flock1 = readWriteChannel.lock(22, 110, true);
135
136        // Try to acquire an overlapping lock.
137        try {
138            readWriteChannel.lock(75, 210, true);
139        } catch (OverlappingFileLockException exception) {
140            // expected
141            flock1.release();
142        }
143    }
144
145    public void test_lockLLZ() throws IOException {
146        // Lock a range at the front, non-shared.
147        FileLock flock1 = readWriteChannel.lock(0, 10, false);
148
149        // Lock a shared range further in the same file.
150        FileLock flock2 = readWriteChannel.lock(22, 100, true);
151
152        // The spec allows the impl to refuse shared locks
153        flock1.release();
154        flock2.release();
155    }
156
157    public void test_tryLock() throws IOException {
158        try {
159            readOnlyChannel.tryLock();
160            fail("Acquiring a full exclusive lock on a read channel should have thrown an exception.");
161        } catch (NonWritableChannelException ex) {
162            // Expected.
163        }
164    }
165
166    public void test_tryLockLLZ() throws IOException {
167        // It is illegal to request an exclusive lock on a read-only channel
168        try {
169            readOnlyChannel.tryLock(0, 99, false);
170            fail("Acquiring exclusive lock on read-only channel should fail");
171        } catch (NonWritableChannelException ex) {
172            // Expected
173        }
174
175        // It is invalid to request a lock starting before the file start
176        try {
177            readOnlyChannel.tryLock(-99, 0, true);
178            fail("Acquiring an illegal lock value should fail.");
179        } catch (IllegalArgumentException ex) {
180            // expected
181        }
182
183        // Acquire a valid lock
184        FileLock tmpLock = readOnlyChannel.tryLock(0, 10, true);
185        assertTrue(tmpLock.isValid());
186        tmpLock.release();
187
188        // Acquire another valid lock -- and don't release it yet
189        FileLock lock = readOnlyChannel.tryLock(10, 788, true);
190        assertTrue(lock.isValid());
191
192        // Overlapping locks are illegal
193        try {
194            readOnlyChannel.tryLock(1, 23, true);
195            fail("Acquiring an overlapping lock should fail.");
196        } catch (OverlappingFileLockException ex) {
197            // Expected
198        }
199
200        // Adjacent locks are legal
201        FileLock adjacentLock = readOnlyChannel.tryLock(1, 3, true);
202        assertTrue(adjacentLock.isValid());
203        adjacentLock.release();
204
205        // Release longer lived lock
206        lock.release();
207    }
208}
209