alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (Lock.java)

This example Java source code file (Lock.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

asynchronousfilechannel, executionexception, filelock, inetsocketaddress, ioexception, iohandler, lockslavemirror, net, network, nio, random, runtimeexception, socketchannel, string, terminator, threading, threads, timeoutexception, util, write

The Lock.java Java example source code

/*
 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


/* @test
 * @bug 4607272 6814948 6842687
 * @summary Unit test for AsynchronousFileChannel#lock method
 */

import java.net.*;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.file.*;
import static java.nio.file.StandardOpenOption.*;
import java.nio.channels.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Random;
import java.util.concurrent.*;

public class Lock {

    static final Random rand = new Random();

    public static void main(String[] args) throws Exception {
        if (args.length > 0 && args[0].equals("-lockslave")) {
            int port = Integer.parseInt(args[1]);
            runLockSlave(port);
            System.exit(0);
        }

        LockSlaveMirror slave = startLockSlave();
        try {

            // create temporary file
            File blah = File.createTempFile("blah", null);
            blah.deleteOnExit();

            // run tests
            testLockProtocol(blah, slave);
            testAsyncClose(blah, slave);

            // eagerly clean-up
            blah.delete();

        } finally {
            slave.shutdown();
        }
    }

    // test locking protocol
    static void testLockProtocol(File file, LockSlaveMirror slave)
        throws Exception
    {
        FileLock fl;

        // slave VM opens file and acquires exclusive lock
        slave.open(file.getPath()).lock();

        AsynchronousFileChannel ch = AsynchronousFileChannel
            .open(file.toPath(), READ, WRITE);

        // this VM tries to acquire lock
        // (lock should not be acquire until released by slave VM)
        Future<FileLock> result = ch.lock();
        try {
            result.get(2, TimeUnit.SECONDS);
            throw new RuntimeException("Timeout expected");
        } catch (TimeoutException x) {
        }

        // slave VM releases lock
        slave.unlock();

        // this VM should now acquire lock
        fl = result.get();
        fl.release();

        // slave VM acquires lock on range
        slave.lock(0, 10, false);

        // this VM acquires lock on non-overlapping range
        fl = ch.lock(10, 10, false).get();
        fl.release();

        // done
        ch.close();
        slave.close();
    }

    // test close of channel with outstanding lock operation
    static void testAsyncClose(File file, LockSlaveMirror slave) throws Exception {
        // slave VM opens file and acquires exclusive lock
        slave.open(file.getPath()).lock();

        for (int i=0; i<100; i++) {
            AsynchronousFileChannel ch = AsynchronousFileChannel
                .open(file.toPath(), READ, WRITE);

            // try to lock file (should not complete because file is locked by slave)
            Future<FileLock> result = ch.lock();
            try {
                result.get(rand.nextInt(100), TimeUnit.MILLISECONDS);
                throw new RuntimeException("Timeout expected");
            } catch (TimeoutException x) {
            }

            // close channel with lock operation outstanding
            ch.close();

            // operation should complete with AsynchronousCloseException
            try {
                result.get();
                throw new RuntimeException("ExecutionException expected");
            } catch (ExecutionException x) {
                if (!(x.getCause() instanceof AsynchronousCloseException)) {
                    x.getCause().printStackTrace();
                    throw new RuntimeException("AsynchronousCloseException expected");
                }
            }
        }

        slave.close();
    }

    // starts a "lock slave" in another process, returning a mirror object to
    // control the slave
    static LockSlaveMirror startLockSlave() throws Exception {
        ServerSocketChannel ssc = ServerSocketChannel.open()
            .bind(new InetSocketAddress(0));
        int port = ((InetSocketAddress)(ssc.getLocalAddress())).getPort();

        String sep = FileSystems.getDefault().getSeparator();

        String command = System.getProperty("java.home") +
            sep + "bin" + sep + "java";
        String testClasses = System.getProperty("test.classes");
        if (testClasses != null)
            command += " -cp " + testClasses;
        command += " Lock -lockslave " + port;

        Process p = Runtime.getRuntime().exec(command);
        IOHandler.handle(p.getInputStream());
        IOHandler.handle(p.getErrorStream());

        // wait for slave to connect
        SocketChannel sc = ssc.accept();
        return new LockSlaveMirror(sc);
    }

    // commands that the slave understands
    static final String OPEN_CMD    = "open";
    static final String CLOSE_CMD   = "close";
    static final String LOCK_CMD    = "lock";
    static final String UNLOCK_CMD  = "unlock";
    static final char TERMINATOR    = ';';

    // provides a proxy to a "lock slave"
    static class LockSlaveMirror {
        private final SocketChannel sc;

        LockSlaveMirror(SocketChannel sc) {
            this.sc = sc;
        }

        private void sendCommand(String cmd, String... params)
            throws IOException
        {
            for (String s: params) {
                cmd += " " + s;
            }
            cmd += TERMINATOR;

            ByteBuffer buf = Charset.defaultCharset().encode(cmd);
            while (buf.hasRemaining()) {
                sc.write(buf);
            }

            // wait for ack
            buf = ByteBuffer.allocate(1);
            int n = sc.read(buf);
            if (n != 1)
                throw new RuntimeException("Reply expected");
            if (buf.get(0) != TERMINATOR)
                throw new RuntimeException("Terminated expected");
        }

        LockSlaveMirror open(String file) throws IOException {
            sendCommand(OPEN_CMD, file);
            return this;
        }

        void close() throws IOException {
            sendCommand(CLOSE_CMD);
        }

        LockSlaveMirror lock() throws IOException {
            sendCommand(LOCK_CMD);
            return this;
        }


        LockSlaveMirror lock(long position, long size, boolean shared)
            throws IOException
        {
            sendCommand(LOCK_CMD, position + "," + size + "," + shared);
            return this;
        }

        LockSlaveMirror unlock() throws IOException {
            sendCommand(UNLOCK_CMD);
            return this;
        }

        void shutdown() throws IOException {
            sc.close();
        }
    }

    // Helper class to direct process output to the parent System.out
    static class IOHandler implements Runnable {
        private final InputStream in;

        IOHandler(InputStream in) {
            this.in = in;
        }

        static void handle(InputStream in) {
            IOHandler handler = new IOHandler(in);
            Thread thr = new Thread(handler);
            thr.setDaemon(true);
            thr.start();
        }

        public void run() {
            try {
                byte b[] = new byte[100];
                for (;;) {
                    int n = in.read(b);
                    if (n < 0) return;
                    for (int i=0; i<n; i++) {
                        System.out.print((char)b[i]);
                    }
                }
            } catch (IOException ioe) { }
        }
    }

    // slave process that responds to simple commands a socket connection
    static void runLockSlave(int port) throws Exception {

        // establish connection to parent
        SocketChannel sc = SocketChannel.open(new InetSocketAddress(port));
        ByteBuffer buf = ByteBuffer.allocateDirect(1024);

        FileChannel fc = null;
        FileLock fl = null;
        try {
            for (;;) {

                // read command (ends with ";")
                buf.clear();
                int n, last = 0;
                do {
                    n = sc.read(buf);
                    if (n < 0)
                        return;
                    if (n == 0)
                        throw new AssertionError();
                    last += n;
                } while (buf.get(last-1) != TERMINATOR);

                // decode into command and optional parameter
                buf.flip();
                String s = Charset.defaultCharset().decode(buf).toString();
                int sp = s.indexOf(" ");
                String cmd = (sp < 0) ? s.substring(0, s.length()-1) :
                    s.substring(0, sp);
                String param = (sp < 0) ? "" : s.substring(sp+1, s.length()-1);

                // execute
                if (cmd.equals(OPEN_CMD)) {
                    if (fc != null)
                        throw new RuntimeException("File already open");
                    fc = FileChannel.open(Paths.get(param),READ, WRITE);
                }
                if (cmd.equals(CLOSE_CMD)) {
                    if (fc == null)
                        throw new RuntimeException("No file open");
                    fc.close();
                    fc = null;
                    fl = null;
                }
                if (cmd.equals(LOCK_CMD)) {
                    if (fl != null)
                        throw new RuntimeException("Already holding lock");

                    if (param.length() == 0) {
                        fl = fc.lock();
                    } else {
                        String[] values = param.split(",");
                        if (values.length != 3)
                            throw new RuntimeException("Lock parameter invalid");
                        long position = Long.parseLong(values[0]);
                        long size = Long.parseLong(values[1]);
                        boolean shared = Boolean.parseBoolean(values[2]);
                        fl = fc.lock(position, size, shared);
                    }
                }

                if (cmd.equals(UNLOCK_CMD)) {
                    if (fl == null)
                        throw new RuntimeException("Not holding lock");
                    fl.release();
                    fl = null;
                }

                // send reply
                byte[] reply = { TERMINATOR };
                n = sc.write(ByteBuffer.wrap(reply));
            }

        } finally {
            sc.close();
            if (fc != null) fc.close();
        }
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java Lock.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.