diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b48783..f329660 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.0.1 + +- Removed unnecessary builders +- Improved test coverage + # 1.0 - Initial commit diff --git a/pom.xml b/pom.xml index 8b27800..f15e57e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.github.sanyarnd app-locker - 1.0 + 1.0.1 https://github.com/sanyarnd/applocker jar @@ -33,7 +33,6 @@ UTF-8 1.8 - ${java-version} ${java-version} true @@ -147,7 +146,6 @@ xml target/reports/pvs-output.xml - diff --git a/src/main/java/io/github/sanyarnd/applocker/AppLocker.java b/src/main/java/io/github/sanyarnd/applocker/AppLocker.java index 66cd017..fbe15db 100644 --- a/src/main/java/io/github/sanyarnd/applocker/AppLocker.java +++ b/src/main/java/io/github/sanyarnd/applocker/AppLocker.java @@ -23,6 +23,7 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -32,14 +33,14 @@ import lombok.Getter; import lombok.ToString; -import io.github.sanyarnd.applocker.builder.Builder; -import io.github.sanyarnd.applocker.builder.BuilderArgs; import io.github.sanyarnd.applocker.exceptions.LockingBusyException; import io.github.sanyarnd.applocker.exceptions.LockingCommunicationException; import io.github.sanyarnd.applocker.exceptions.LockingException; import io.github.sanyarnd.applocker.exceptions.LockingFailedException; import io.github.sanyarnd.applocker.filesystem.LockNameProvider; +import io.github.sanyarnd.applocker.filesystem.Sha1Provider; import io.github.sanyarnd.applocker.messaging.Client; +import io.github.sanyarnd.applocker.messaging.MessageHandler; import io.github.sanyarnd.applocker.messaging.Server; /** @@ -75,13 +76,13 @@ public final class AppLocker { @Nonnull private final Consumer failedHandler; - public AppLocker(@Nonnull String id, - @Nonnull Path lockPath, - @Nonnull LockNameProvider provider, - @Nullable Server server, - @Nonnull Runnable acquiredHandler, - @Nullable BiConsumer busyHandler, - @Nonnull Consumer failedHandler) { + private AppLocker(@Nonnull String id, + @Nonnull Path lockPath, + @Nonnull LockNameProvider provider, + @Nullable Server server, + @Nonnull Runnable acquiredHandler, + @Nullable BiConsumer busyHandler, + @Nonnull Consumer failedHandler) { this.id = id; this.server = server; this.acquiredHandler = acquiredHandler; @@ -105,7 +106,7 @@ public AppLocker(@Nonnull String id, * @param id AppLocker unique ID * @return builder */ - public static BuilderArgs create(@Nonnull String id) { + public static Builder create(@Nonnull String id) { return new Builder(id); } @@ -221,5 +222,118 @@ private int getPortFromFile() throws IOException { return ByteBuffer.wrap(Files.readAllBytes(portFile)).getInt(); } + /** + * AppLocker builder + * + * @author Alexander Biryukov + */ + public static final class Builder { + @Nonnull + private final String id; + @Nonnull + private Path path = Paths.get("."); + @Nonnull + private LockNameProvider provider = new Sha1Provider(); + @Nullable + private MessageHandler handler = null; + @Nonnull + private Runnable acquiredHandler = () -> {}; + @Nonnull + private Consumer failedHandler = ex -> { throw ex; }; + @Nullable + private BiConsumer busyHandler; + + public Builder(@Nonnull String id) { this.id = id; } + + /** + * Sets the path where the lock file will be stored
+ * Default value is "." (relative) + * + * @param path store path + * @return builder + */ + public Builder setPath(@Nonnull Path path) { + this.path = path; + return this; + } + + /** + * Sets the message handler.
+ * If not set, AppLocker won't support communication features
+ * Default value is null + * + * @param handler message handler + * @return builder + */ + public Builder setMessageHandler(@Nonnull MessageHandler handler) { + this.handler = handler; + return this; + } + + /** + * Sets the name provider.
+ * Provider encodes lock id to filesystem-friendly entry
+ * Default value is {@link Sha1Provider} + * + * @param provider name provider + * @return builder + */ + public Builder setNameProvider(@Nonnull LockNameProvider provider) { + this.provider = provider; + return this; + } + /** + * Successful locking callback.
+ * By default does nothing + * + * @param callback the function to call after successful locking + * @return builder + */ + public Builder acquired(@Nonnull Runnable callback) { + acquiredHandler = callback; + return this; + } + + /** + * Lock is already taken callback.
+ * By default does nothing (null) + * + * @param message message for lock holder + * @param handler answer processing function + * @param answer type + * @return builder + */ + public Builder busy(@Nonnull Serializable message, @Nonnull Consumer handler) { + busyHandler = (appLocker, ex) -> { + T answer = appLocker.sendMessage(message); + handler.accept(answer); + }; + return this; + } + + /** + * Unable to lock for unknown reasons callback.
+ * By default re-throws the exception + * + * @param handler error processing function + * @return builder + */ + public Builder failed(@Nonnull Consumer handler) { + failedHandler = handler; + return this; + } + + /** + * Build AppLocker + * + * @return AppLocker instance + */ + public AppLocker build() { + @SuppressWarnings("unchecked") + Server server = handler != null ? new Server(handler) : null; + + return new AppLocker(id, path, provider, server, acquiredHandler, busyHandler, failedHandler); + } + } } diff --git a/src/main/java/io/github/sanyarnd/applocker/builder/Builder.java b/src/main/java/io/github/sanyarnd/applocker/builder/Builder.java deleted file mode 100644 index 1b66d86..0000000 --- a/src/main/java/io/github/sanyarnd/applocker/builder/Builder.java +++ /dev/null @@ -1,107 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com -// -// Copyright 2019 Alexander Biryukov -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.github.sanyarnd.applocker.builder; - -import java.io.Serializable; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import io.github.sanyarnd.applocker.AppLocker; -import io.github.sanyarnd.applocker.exceptions.LockingBusyException; -import io.github.sanyarnd.applocker.exceptions.LockingException; -import io.github.sanyarnd.applocker.filesystem.LockNameProvider; -import io.github.sanyarnd.applocker.filesystem.Sha1Provider; -import io.github.sanyarnd.applocker.messaging.MessageHandler; -import io.github.sanyarnd.applocker.messaging.Server; - -/** - * AppLocker builder - * - * @author Alexander Biryukov - */ -public final class Builder implements BuilderCommunicationArgs, BuilderArgs { - @Nonnull - private final String id; - @Nonnull - private Path path = Paths.get("."); - @Nonnull - private LockNameProvider provider = new Sha1Provider(); - @Nullable - private MessageHandler handler = null; - @Nonnull - private Runnable acquiredHandler = () -> {}; - @Nonnull - private Consumer failedHandler = ex -> { throw ex; }; - @Nullable - private BiConsumer busyHandler; - - public Builder(@Nonnull String id) { this.id = id; } - - @Override - public BuilderArgs setPath(@Nonnull Path path) { - this.path = path; - return this; - } - - @Override - public BuilderArgs setMessageHandler(@Nonnull MessageHandler handler) { - this.handler = handler; - return this; - } - - @Override - public BuilderArgs setNameProvider(@Nonnull LockNameProvider provider) { - this.provider = provider; - return this; - } - - @Override - public BuilderArgs acquired(@Nonnull Runnable callback) { - acquiredHandler = callback; - return this; - } - - @Override - public BuilderCommunicationArgs busy(@Nonnull Serializable message, @Nonnull Consumer handler) { - busyHandler = (appLocker, ex) -> { - T answer = appLocker.sendMessage(message); - handler.accept(answer); - }; - return this; - } - - @Override - public BuilderArgs failed(@Nonnull Consumer handler) { - failedHandler = handler; - - return this; - } - - @Override - public AppLocker build() { - @SuppressWarnings("unchecked") - Server server = handler != null ? new Server(handler) : null; - - return new AppLocker(id, path, provider, server, acquiredHandler, busyHandler, failedHandler); - } -} diff --git a/src/main/java/io/github/sanyarnd/applocker/builder/BuilderArgs.java b/src/main/java/io/github/sanyarnd/applocker/builder/BuilderArgs.java deleted file mode 100644 index 0df1637..0000000 --- a/src/main/java/io/github/sanyarnd/applocker/builder/BuilderArgs.java +++ /dev/null @@ -1,86 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com -// -// Copyright 2019 Alexander Biryukov -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.github.sanyarnd.applocker.builder; - -import java.io.Serializable; -import java.nio.file.Path; -import java.util.function.Consumer; - -import javax.annotation.Nonnull; - -import io.github.sanyarnd.applocker.AppLocker; -import io.github.sanyarnd.applocker.exceptions.LockingException; -import io.github.sanyarnd.applocker.filesystem.LockNameProvider; -import io.github.sanyarnd.applocker.filesystem.Sha1Provider; - -public interface BuilderArgs { - /** - * Sets the path where the lock file will be stored
- * Default value is "." (relative) - * - * @param path store path - * @return builder - */ - BuilderArgs setPath(@Nonnull Path path); - - /** - * Sets the name provider.
- * Provider encodes lock id to filesystem-friendly entry
- * Default value is {@link Sha1Provider} - * - * @param provider name provider - * @return builder - */ - BuilderArgs setNameProvider(@Nonnull LockNameProvider provider); - - /** - * Successful locking callback.
- * By default does nothing - * - * @param callback the function to call after successful locking - * @return builder - */ - BuilderArgs acquired(@Nonnull Runnable callback); - - /** - * Unable to lock for unknown reasons callback.
- * By default re-throws the exception - * - * @param handler error processing function - * @return builder - */ - BuilderArgs failed(@Nonnull Consumer handler); - - /** - * Lock is already taken callback.
- * By default does nothing (null) - * - * @param message message for lock holder - * @param handler answer processing function - * @param answer type - * @return builder - */ - BuilderCommunicationArgs busy(@Nonnull Serializable message, @Nonnull Consumer handler); - - /** - * Build AppLocker - * - * @return AppLocker instance - */ - AppLocker build(); -} diff --git a/src/main/java/io/github/sanyarnd/applocker/builder/BuilderCommunicationArgs.java b/src/main/java/io/github/sanyarnd/applocker/builder/BuilderCommunicationArgs.java deleted file mode 100644 index d053ee9..0000000 --- a/src/main/java/io/github/sanyarnd/applocker/builder/BuilderCommunicationArgs.java +++ /dev/null @@ -1,34 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com -// -// Copyright 2019 Alexander Biryukov -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.github.sanyarnd.applocker.builder; - -import javax.annotation.Nonnull; - -import io.github.sanyarnd.applocker.messaging.MessageHandler; - -public interface BuilderCommunicationArgs { - /** - * Sets the message handler.
- * If not set, AppLocker won't support communication features
- * Default value is null - * - * @param handler message handler - * @return builder - */ - BuilderArgs setMessageHandler(@Nonnull MessageHandler handler); -} diff --git a/src/test/java/io/github/sanyarnd/applocker/AppLockerHandlersTest.java b/src/test/java/io/github/sanyarnd/applocker/AppLockerHandlersTest.java index c0c7060..bb81df0 100644 --- a/src/test/java/io/github/sanyarnd/applocker/AppLockerHandlersTest.java +++ b/src/test/java/io/github/sanyarnd/applocker/AppLockerHandlersTest.java @@ -51,7 +51,7 @@ public void fail_handler_suppress_exception() { Assertions.assertTrue(l1.isLocked()); Assertions.assertFalse(l2.isLocked()); // test that failed handler is called - Assertions.assertEquals(ret[0], -1); + Assertions.assertEquals(-1, ret[0]); // cleanup l1.unlock(); @@ -70,7 +70,7 @@ public void busy_handler_supersedes_fail_handler_when_suppressing_exception() { Assertions.assertFalse(l2.isLocked()); // test that busy handler is called - Assertions.assertEquals(ret[0], 1); + Assertions.assertEquals(1, ret[0]); // cleanup l1.unlock(); @@ -91,7 +91,7 @@ public void fail_handler_supersedes_fail_handler_when_busy_throws_exception() { Assertions.assertTrue(l1.isLocked()); Assertions.assertFalse(l2.isLocked()); // test that failed handler is called - Assertions.assertEquals(ret[0], -1); + Assertions.assertEquals(-1, ret[0]); // cleanup l1.unlock(); @@ -106,7 +106,7 @@ public void lock_acquired_is_called() { l1.lock(); Assertions.assertTrue(l1.isLocked()); // test that failed handler is called - Assertions.assertEquals(ret[0], 1); + Assertions.assertEquals(1, ret[0]); // cleanup l1.unlock(); diff --git a/src/test/java/io/github/sanyarnd/applocker/AppLockerTest.java b/src/test/java/io/github/sanyarnd/applocker/AppLockerTest.java index 23b7329..46b238f 100644 --- a/src/test/java/io/github/sanyarnd/applocker/AppLockerTest.java +++ b/src/test/java/io/github/sanyarnd/applocker/AppLockerTest.java @@ -121,7 +121,7 @@ public void communication_to_self() { l1.lock(); String messageToSelf = l1.sendMessage("self"); - Assertions.assertEquals(messageToSelf, "self"); + Assertions.assertEquals("self", messageToSelf); // cleanup l1.unlock(); @@ -135,7 +135,7 @@ public void communication_between_two_locks() { l1.lock(); String messageToOther = l2.sendMessage("other"); - Assertions.assertEquals(messageToOther, "other"); + Assertions.assertEquals("other", messageToOther); // cleanup l1.unlock(); @@ -170,13 +170,13 @@ public String handleMessage(@Nonnull String message) { l1.lock(); String messageToOther = l2.sendMessage("whatever"); - Assertions.assertEquals(messageToOther, "1"); + Assertions.assertEquals("1", messageToOther); l1.unlock(); l2.lock(); messageToOther = l1.sendMessage("whatever"); - Assertions.assertEquals(messageToOther, "2"); + Assertions.assertEquals("2", messageToOther); // cleanup l1.unlock(); @@ -199,6 +199,12 @@ public String encrypt(@Nonnull String string) { l1.unlock(); } + @Test + public void to_string() { + AppLocker l1 = AppLocker.create("sameId").build(); + Assertions.assertNotEquals(l1.toString(), null); + } + @Test @EnabledOnOs(OS.WINDOWS) public void invalid_path_windows_throws() { diff --git a/src/test/java/io/github/sanyarnd/applocker/MessagingTest.java b/src/test/java/io/github/sanyarnd/applocker/MessagingTest.java index d07e06b..fd3a3e4 100644 --- a/src/test/java/io/github/sanyarnd/applocker/MessagingTest.java +++ b/src/test/java/io/github/sanyarnd/applocker/MessagingTest.java @@ -17,6 +17,7 @@ package io.github.sanyarnd.applocker; +import java.io.EOFException; import java.io.Serializable; import java.util.ArrayList; @@ -26,6 +27,7 @@ import org.junit.jupiter.api.Test; import io.github.sanyarnd.applocker.exceptions.LockingCommunicationException; +import io.github.sanyarnd.applocker.exceptions.LockingMessageServerException; import io.github.sanyarnd.applocker.messaging.Client; import io.github.sanyarnd.applocker.messaging.MessageHandler; import io.github.sanyarnd.applocker.messaging.Server; @@ -105,6 +107,25 @@ public void client_throws_if_no_server() { Assertions.assertThrows(LockingCommunicationException.class, () -> client.send(message)); } + @Test + public void port_throws_if_no_server() { + final Server server = new Server<>(createEchoHandler()); + + Assertions.assertThrows(LockingCommunicationException.class, server::getPort); + } + + @Test + public void port_throws_if_server_exception() { + final Server server = new Server<>(e -> { + throw new IllegalArgumentException(); + }); + + server.start(); + final Client client = new Client<>(server.getPortBlocking()); + Assertions.assertThrows(LockingCommunicationException.class, () -> client.send("test")); + Assertions.assertThrows(LockingMessageServerException.class, server::getPortBlocking); + } + @Test public void client_throws_1_if_types_do_not_match() { MessageHandler echoHandler = createEchoHandler();