Skip to content

Commit

Permalink
Version 1.0.3
Browse files Browse the repository at this point in the history
- Breaking API name changes
- Improved JavaDoc
- Refactoring
- Added mvnw executable for Linux and Mac
  • Loading branch information
sanyarnd committed May 21, 2019
1 parent 4331488 commit c8d3336
Show file tree
Hide file tree
Showing 23 changed files with 532 additions and 200 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
target/
!.mvn/wrapper/maven-wrapper.jar
.mvn/wrapper/maven-wrapper.jar

### STS ###
.apt_generated
Expand Down
Binary file removed .mvn/wrapper/maven-wrapper.jar
Binary file not shown.
12 changes: 5 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,15 @@ addons:
token:
secure: $SONAR_API_KEY

install: mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent install org.jacoco:jacoco-maven-plugin:report -B -V

before_script:
- "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | sudo bash"
before_install:
- chmod +x mvnw
install:
mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent install org.jacoco:jacoco-maven-plugin:report -B -V

after_success:
- mvn pvsstudio:pvsCredentials
- mvn pvsstudio:pvsAnalyze
- mvn sonar:sonar -DskipTests=true
- fossa init
- fossa analyze

deploy:
- provider: releases
Expand All @@ -43,7 +41,7 @@ deploy:
on:
tags: true
- provider: script
script: "cp .m2/settings.xml $HOME/.m2/settings.xml && mvn deploy"
script: "mvn --settings .m2/settings.xml deploy"
skip_cleanup: true
on:
tags: true
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 1.0.3
- API changes
- Improved javadoc
- Internal re-organization
- Missing maven wrapper executable for *nix

# 1.0.2
- `AppLocker.Builder`'s `busy` method now supports `Runnable` callback
- javadoc and sources are now distributed along with the package
Expand Down
127 changes: 64 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,82 +1,83 @@
# AppLocker
[![Build Status](https://travis-ci.com/sanyarnd/applocker.svg?branch=master)](https://travis-ci.com/sanyarnd/applocker)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=io.github.sanyarnd%3Aapp-locker&metric=coverage)](https://sonarcloud.io/dashboard?id=io.github.sanyarnd%3Aapp-locker)
[![Download](https://api.bintray.com/packages/sanya-rnd/maven-projects/applocker/images/download.svg)](https://bintray.com/sanya-rnd/maven-projects/applocker/_latestVersion)
[![FOSSA Status](https://app.fossa.com/api/projects/custom%2B8815%2Fgithub.com%2Fsanyarnd%2Fapplocker.svg?type=shield)](https://app.fossa.com/projects/custom%2B8815%2Fgithub.com%2Fsanyarnd%2Fapplocker?ref=badge_shield)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

AppLocker library adds single instance application functionality, allowing exactly 1 running instance of the application.

Library is compatible with any JDK8+ version.

Library has very small footprint (20-30kb) and zero dependencies.
AppLocker library provides single instance functionality, allowing exactly 1 running instance of your application.

# Features
* File-system based locking mechanism
* IPC: optional communication between already running application and any process which is trying to acquire the same lock

# Download

Visit [releases page](https://github.com/sanyarnd/applocker/releases) or [bintray artifactory](https://bintray.com/sanya-rnd/maven-projects/applocker).
* Safe: based on file channel locking, lock will be released even in case of power outrage
* Can communicate with instance which's acquired the lock
* Small memory footprint (~20kb)
* No transitive dependencies
* JDK8+ support

# How to use
Handlers:
# Usage
Get the `AppLocker`:
```java
AppLocker locker = AppLocker.create("lockID")
.setPath(Paths.get(".")) // where to store locks (default: ".")
.setIdEncoder(this::encode) // how to encode lock files (default: "SHA-1")
.setMessageHandler(e -> e) // handle messages which are sent with locker#send or #onBusy (default: NULL)
.build(); // create instance
```
public void main() {
final AppLocker locker = AppLocker.create("Unique Lock ID") // identify your application
.setPath(Paths.get("path/to/store/locks")) // we can decide where to store locks (".", ".cache" etc)
.busy(LockMessage.TO_FRONT, this::closeApp) // handles situations, like: failed to lock because `Unique Lock ID` is already taken
.setMessageHandler((LockMessage msg) -> { // message handler will recieve messages from `.busy` and answer back
if (msg == LockMessage.TO_FRONT) { // there is only one active message handler for each lock id
Ui.run(...);
}
return LockMessage.CLOSE; // return answer
})
.failed(this::logAndExit) // handles situations, like: provided path for lock storage is non-writable by user, also handles `busy error` if busy handler is missing
.acquired(this::logLockAcquiring) // callback function, which is called if acquiring the lock was successful
.build(); // create AppLocker instance with provided parameters

// try lock
locker.lock();
}
enum LockMessage {
CLOSE, TO_FRONT
}
void logAndExit(@Nonnull LockingException ex) {
log.error("An error occurred during locking", ex);
closeApplication();
There are two ways how to handle errors.

I encourage you to try smart (fluent) builder:
compact, easy to read and provides expecting functionality right off the bat:
```java
AppLocker locker = AppLocker.create("lockID")
.onSuccess(this::test) // success callback (default: NULL)
.onBusy("close", this::logAndExit) // send message to the instance which currently owns the lock and invoke callback (default: NULL)
.onFail(this::logErrorAndExit) // if a serious error happened during the lock (default: re-throw)
.build();
locker.lock();
}
```

LockMessage closeApp(LockMessage message) {
log.info("Application is already running");
log.info("Other application answer: " + message);
// in this example we don't really care for an answer, close the app anyway
closeApplication();
If it's not suited for you for some reason, use exceptions mechanism:
```java
AppLocker locker = AppLocker.create("lockID").build();
try {
locker.lock();
} catch (LockingBusyException ex) {
} catch (LockingCommunicationException ex) {
} catch (LockingMessageServerException ex) {
} catch (LockingFailedException ex) {
}
```

void logLockAcquiring() {
log.info("AppLock is acquired");
}
# Download
Maven:
```xml
<dependency>
<groupId>io.github.sanyarnd</groupId>
<artifactId>app-locker</artifactId>
<version>1.0.3</version>
</dependency>

<repositories>
<repository>
<id>bintray-sanya-rnd-maven-projects</id>
<name>bintray</name>
<url>https://dl.bintray.com/sanya-rnd/maven-projects</url>
</repository>
</repositories>
```
Gradle:
```gradle
compile 'io.github.sanyarnd:app-locker:1.0.3'
Exceptions:
```
public void main() {
final AppLocker locker = AppLocker.create("Unique Lock ID")
.setPath(Paths.get("path/to/store/locks"))
.build();
try {
locker.lock();
} catch (LockingBusyException ex) {
...
} catch (LockingFailedException ex) {
...
} catch (...) {
}
repositories {
maven {
url "https://dl.bintray.com/sanya-rnd/maven-projects"
}
}
```
For more information visit [bintray](https://bintray.com/sanya-rnd/maven-projects/applocker).

Standalone jars are available on [releases](https://github.com/sanyarnd/applocker/releases) page.


#Changelog
To see what has changed in recent versions of AppLocker, see the [CHANGELOG.md](CHANGELOG.md)
Loading

0 comments on commit c8d3336

Please sign in to comment.