1 /*
   2  * Copyright (c) 2012, 2014, Oracle and/or its affiliates.
   3  * All rights reserved. Use is subject to license terms.
   4  *
   5  * This file is available and licensed under the following license:
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  *
  11  *  - Redistributions of source code must retain the above copyright
  12  *    notice, this list of conditions and the following disclaimer.
  13  *  - Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in
  15  *    the documentation and/or other materials provided with the distribution.
  16  *  - Neither the name of Oracle Corporation nor the names of its
  17  *    contributors may be used to endorse or promote products derived
  18  *    from this software without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31  */
  32 package com.oracle.javafx.scenebuilder.app.util;
  33 
  34 import java.io.IOException;
  35 import java.io.RandomAccessFile;
  36 import java.nio.channels.FileLock;
  37 import java.nio.file.FileAlreadyExistsException;
  38 import java.nio.file.Files;
  39 import java.nio.file.Path;
  40 import java.util.Timer;
  41 import java.util.TimerTask;
  42 
  43 /**
  44  * This class implements a mutex using FileLock.
  45  * Two processes which want to be in mutual exclusion should:
  46  *      1) create an instance of FileMutex using the same file
  47  *      2) call FileMutex.lock() or FileMutex.tryLock()
  48  */
  49 class FileMutex {
  50 
  51     private final Path lockFile;
  52     private RandomAccessFile lockRAF;
  53     private FileLock lock;
  54 
  55     public FileMutex(Path lockFile) {
  56         assert lockFile != null;
  57         this.lockFile = lockFile;
  58     }
  59 
  60     public Path getLockFile() {
  61         return lockFile;
  62     }
  63 
  64     public void lock(long timeout) throws IOException {
  65         assert lockRAF == null;
  66         assert lock == null;
  67 
  68         createFileChannel();
  69         assert lockRAF != null;
  70         final Timer timer = new Timer();
  71         timer.schedule(new InterruptTask(), timeout);
  72         lock = lockRAF.getChannel().lock();
  73         timer.cancel();
  74         assert lock != null;
  75     }
  76 
  77     public boolean tryLock() throws IOException {
  78         assert lockRAF == null;
  79         assert lock == null;
  80 
  81         createFileChannel();
  82         assert lockRAF != null;
  83         lock = lockRAF.getChannel().tryLock();
  84         if (lock == null) {
  85             lockRAF.close();
  86             lockRAF = null;
  87         }
  88 
  89         return lock != null;
  90     }
  91 
  92     public void unlock() throws IOException {
  93         assert lockRAF != null;
  94         assert lock != null;
  95         assert lock.channel() == lockRAF.getChannel();
  96 
  97         lock.release();
  98         lock = null;
  99         lockRAF.close();
 100         lockRAF = null;
 101     }
 102 
 103     public boolean isLocked() {
 104         return lock != null;
 105     }
 106 
 107 
 108     /*
 109      * Private
 110      */
 111 
 112     private void createFileChannel() throws IOException {
 113         try {
 114             Files.createFile(lockFile);
 115         } catch(FileAlreadyExistsException x) {
 116             // Someone else already created it
 117         }
 118         lockRAF = new RandomAccessFile(lockFile.toFile(), "rw"); //NOI18N
 119     }
 120 
 121     private static class InterruptTask extends TimerTask {
 122         @Override
 123         public void run() {
 124             Thread.currentThread().interrupt();
 125         }
 126     }
 127 
 128 //    public static void main(String[] args) throws IOException {
 129 //        final Path mutexPath = Paths.get(System.getProperty("user.home"), "test.mtx");
 130 //        final FileMutex fm = new FileMutex(mutexPath);
 131 //        for (int i = 0; i < 100000; i++) {
 132 //            fm.lock();
 133 //            fm.unlock();
 134 //        }
 135 //    }
 136 }