|
|
@@ -0,0 +1,72 @@
|
|
|
+package com.mes.util;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+import java.nio.channels.FileChannel;
|
|
|
+import java.nio.channels.FileLock;
|
|
|
+import java.nio.channels.OverlappingFileLockException;
|
|
|
+import java.nio.file.StandardOpenOption;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Prevents multiple instances of the client from running at the same time.
|
|
|
+ */
|
|
|
+public final class LockUtil {
|
|
|
+ private static final LockUtil INSTANCE = new LockUtil();
|
|
|
+ private static final String LOCK_FILE_NAME = "mesclient-op170.lock";
|
|
|
+
|
|
|
+ private FileChannel channel;
|
|
|
+ private FileLock lock;
|
|
|
+ private boolean checked;
|
|
|
+ private boolean active;
|
|
|
+
|
|
|
+ private LockUtil() {
|
|
|
+ }
|
|
|
+
|
|
|
+ public static LockUtil getInstance() {
|
|
|
+ return INSTANCE;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns true when another client instance already owns the lock.
|
|
|
+ */
|
|
|
+ public synchronized boolean isAppActive() {
|
|
|
+ if (checked) {
|
|
|
+ return active;
|
|
|
+ }
|
|
|
+ checked = true;
|
|
|
+ File lockFile = new File(System.getProperty("java.io.tmpdir"), LOCK_FILE_NAME);
|
|
|
+ try {
|
|
|
+ channel = FileChannel.open(lockFile.toPath(),
|
|
|
+ StandardOpenOption.CREATE, StandardOpenOption.WRITE);
|
|
|
+ lock = channel.tryLock();
|
|
|
+ active = lock == null;
|
|
|
+ if (!active) {
|
|
|
+ Runtime.getRuntime().addShutdownHook(new Thread(this::release, "mesclient-lock-release"));
|
|
|
+ }
|
|
|
+ } catch (OverlappingFileLockException | IOException e) {
|
|
|
+ active = true;
|
|
|
+ release();
|
|
|
+ }
|
|
|
+ return active;
|
|
|
+ }
|
|
|
+
|
|
|
+ private synchronized void release() {
|
|
|
+ try {
|
|
|
+ if (lock != null && lock.isValid()) {
|
|
|
+ lock.release();
|
|
|
+ }
|
|
|
+ } catch (IOException ignored) {
|
|
|
+ // The process is exiting; there is nothing useful to recover here.
|
|
|
+ } finally {
|
|
|
+ try {
|
|
|
+ if (channel != null && channel.isOpen()) {
|
|
|
+ channel.close();
|
|
|
+ }
|
|
|
+ } catch (IOException ignored) {
|
|
|
+ // The operating system releases the lock when the process exits.
|
|
|
+ }
|
|
|
+ lock = null;
|
|
|
+ channel = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|