From 0a922a30abde5acd9118deca67138af2febb8a70 Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Wed, 14 Feb 2018 13:27:11 +0300 Subject: [PATCH 01/58] Redesigned Bytes.put(index, byte) logic --- CHANGELOG.md | 6 ++++++ pom.xml | 4 ++-- src/main/java/io/appulse/utils/Bytes.java | 8 ++++++-- src/test/java/io/appulse/utils/BytesTest.java | 11 +++++++++-- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe746a5..cb0d04b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add more tests. - Add `JavaDoc`. +## [1.3.2](https://github.com/appulse-projects/utils-java/releases/tag/1.3.2) - 2018-02-14 + +### Changed + +- Redesigned `Bytes.put(index, byte)` logic, now it moves `limit`. + ## [1.3.1](https://github.com/appulse-projects/utils-java/releases/tag/1.3.1) - 2018-02-09 Minor release with unsigned numbers support. diff --git a/pom.xml b/pom.xml index ed241ed..d3e1976 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ limitations under the License. io.appulse utils-java - 1.3.1 + 1.3.2 jar @@ -62,7 +62,7 @@ limitations under the License. https://github.com/appulse-projects/utils-java scm:git:https://github.com/appulse-projects/utils-java.git scm:git:https://github.com/appulse-projects/utils-java.git - 1.3.1 + 1.3.2 diff --git a/src/main/java/io/appulse/utils/Bytes.java b/src/main/java/io/appulse/utils/Bytes.java index 821e5f8..8322e1d 100644 --- a/src/main/java/io/appulse/utils/Bytes.java +++ b/src/main/java/io/appulse/utils/Bytes.java @@ -86,7 +86,11 @@ public Bytes put (byte value) { } public Bytes put (int index, byte value) { - buffer.put(index, value); + if (index < limit) { + buffer.put(index, value); + } else { + put(value); + } return this; } @@ -100,7 +104,7 @@ public Bytes put (@NonNull byte[] bytes) { public Bytes put (int index, @NonNull byte[] bytes) { checkCapacity(index, bytes.length); IntStream.range(index, index + bytes.length).forEach(it -> { - buffer.put(it, bytes[it - index]); + put(it, bytes[it - index]); }); return this; } diff --git a/src/test/java/io/appulse/utils/BytesTest.java b/src/test/java/io/appulse/utils/BytesTest.java index d8d4e36..b1b5eb9 100644 --- a/src/test/java/io/appulse/utils/BytesTest.java +++ b/src/test/java/io/appulse/utils/BytesTest.java @@ -103,8 +103,15 @@ public void limit () { bytes.put4B(4); assertThat(bytes.limit()).isEqualTo(4); - Bytes wrapped = Bytes.wrap(new byte[] { 1 }); - assertThat(wrapped.limit()).isEqualTo(1); + Bytes wrapped = Bytes.wrap(new byte[] { 1, 0 }); + assertThat(wrapped.array()).isEqualTo(new byte[] { 1, 0 }); + assertThat(wrapped.limit()).isEqualTo(2); + + wrapped.position(wrapped.limit()); + wrapped.put(1, new byte[] { 2, 3 }); + assertThat(wrapped.array()).isEqualTo(new byte[] { 1, 2, 3 }); + assertThat(wrapped.limit()).isEqualTo(3); + assertThat(wrapped.position()).isEqualTo(3); } @Test From f834b52ba6e6cde6a45010581d022c6e75e1a2aa Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Wed, 14 Feb 2018 15:32:01 +0300 Subject: [PATCH 02/58] Update readme --- CHANGELOG.md | 2 ++ README.md | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb0d04b..42ef8f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [1.3.2](https://github.com/appulse-projects/utils-java/releases/tag/1.3.2) - 2018-02-14 +Minor release with simple bug fix. + ### Changed - Redesigned `Bytes.put(index, byte)` logic, now it moves `limit`. diff --git a/README.md b/README.md index 89ef9e8..3ea0a15 100644 --- a/README.md +++ b/README.md @@ -34,9 +34,9 @@ $> mvn clean compile [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ -[INFO] Total time: 12.712 s -[INFO] Finished at: 2018-02-01T15:23:30+03:00 -[INFO] Final Memory: 44M/585M +[INFO] Total time: 10.522 s +[INFO] Finished at: 2018-02-14T15:31:22+03:00 +[INFO] Final Memory: 43M/512M [INFO] ------------------------------------------------------------------------ ``` @@ -54,7 +54,7 @@ $> mvn clean test [INFO] [INFO] Results: [INFO] -[INFO] Tests run: 22, Failures: 0, Errors: 0, Skipped: 0 +[INFO] Tests run: 26, Failures: 0, Errors: 0, Skipped: 0 [INFO] ... ``` From bc637918fa43aba2665e520a4ce3e6908c9e22d5 Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Thu, 15 Mar 2018 21:05:47 +0300 Subject: [PATCH 03/58] Small refactoring --- .codestyle/checkstyle.xml | 13 +- .codestyle/findbugs.xml | 3 + .codestyle/pmd.xml | 165 ++++-------------- CHANGELOG.md | 9 + pom.xml | 22 ++- .../java/io/appulse/utils/SocketUtils.java | 2 +- .../java/io/appulse/utils/BytesUtilsTest.java | 6 +- .../io/appulse/utils/ReflectionUtilsTest.java | 84 ++++----- 8 files changed, 110 insertions(+), 194 deletions(-) diff --git a/.codestyle/checkstyle.xml b/.codestyle/checkstyle.xml index 030c74c..bb32d79 100644 --- a/.codestyle/checkstyle.xml +++ b/.codestyle/checkstyle.xml @@ -52,12 +52,6 @@ limitations under the License. - - - - - - @@ -194,7 +188,7 @@ limitations under the License. - + @@ -321,9 +315,6 @@ limitations under the License. - @@ -362,7 +353,6 @@ limitations under the License. - @@ -372,7 +362,6 @@ limitations under the License. - diff --git a/.codestyle/findbugs.xml b/.codestyle/findbugs.xml index 87761fc..9e57b78 100644 --- a/.codestyle/findbugs.xml +++ b/.codestyle/findbugs.xml @@ -23,4 +23,7 @@ limitations under the License. + + + diff --git a/.codestyle/pmd.xml b/.codestyle/pmd.xml index ac86087..4c55656 100644 --- a/.codestyle/pmd.xml +++ b/.codestyle/pmd.xml @@ -23,144 +23,55 @@ limitations under the License. PMD Rules - - + - - - - - - - - - + + + + + + + + + + + + + + + - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - + + - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - + - - - - - + + diff --git a/CHANGELOG.md b/CHANGELOG.md index 42ef8f6..71a54b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add more tests. - Add `JavaDoc`. +## [1.3.3](https://github.com/appulse-projects/utils-java/releases/tag/1.3.3) - 2018-03-15 + +Small refactoring. + +### Changed + +- Updated dependencies. +- Corrected codestyle files. + ## [1.3.2](https://github.com/appulse-projects/utils-java/releases/tag/1.3.2) - 2018-02-14 Minor release with simple bug fix. diff --git a/pom.xml b/pom.xml index d3e1976..7b048d3 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ limitations under the License. io.appulse utils-java - 1.3.2 + 1.3.3 jar @@ -62,7 +62,7 @@ limitations under the License. https://github.com/appulse-projects/utils-java scm:git:https://github.com/appulse-projects/utils-java.git scm:git:https://github.com/appulse-projects/utils-java.git - 1.3.2 + 1.3.3 @@ -105,7 +105,7 @@ limitations under the License. com.google.code.findbugs annotations - 3.0.1u2 + 3.0.1 provided @@ -124,7 +124,7 @@ limitations under the License. org.assertj assertj-core - 3.9.0 + 3.9.1 test @@ -148,9 +148,10 @@ limitations under the License. org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + 3.0.0 -Xdoclint:none + -Xdoclint:none true UTF-8 UTF-8 @@ -174,7 +175,7 @@ limitations under the License. org.apache.maven.plugins maven-surefire-plugin - 2.20.1 + 2.21.0 false @@ -189,7 +190,7 @@ limitations under the License. org.apache.maven.plugins maven-failsafe-plugin - 2.20.1 + 2.21.0 **/*IntegrationTest.java @@ -232,11 +233,14 @@ limitations under the License. org.apache.maven.plugins maven-pmd-plugin - 3.8 + 3.9.0 ${project.build.sourceEncoding} ${maven.compiler.source} true + true + true + true false ${project.basedir}/.codestyle/pmd.xml @@ -277,7 +281,7 @@ limitations under the License. true false codestyleFolder=${project.basedir}/.codestyle - false + true diff --git a/src/main/java/io/appulse/utils/SocketUtils.java b/src/main/java/io/appulse/utils/SocketUtils.java index 65cbc6a..b014296 100644 --- a/src/main/java/io/appulse/utils/SocketUtils.java +++ b/src/main/java/io/appulse/utils/SocketUtils.java @@ -40,7 +40,7 @@ public static Optional findFreePort () { } public static Optional findFreePort (int from, int to) { - for (int port = from; port <= to; port++) { + for (int port = to; port >= from; port--) { if (isPortAvailable(port)) { return of(port); } diff --git a/src/test/java/io/appulse/utils/BytesUtilsTest.java b/src/test/java/io/appulse/utils/BytesUtilsTest.java index 59057fe..3533166 100644 --- a/src/test/java/io/appulse/utils/BytesUtilsTest.java +++ b/src/test/java/io/appulse/utils/BytesUtilsTest.java @@ -16,17 +16,17 @@ package io.appulse.utils; -import static org.assertj.core.api.Assertions.assertThat; import static lombok.AccessLevel.PRIVATE; +import static org.assertj.core.api.Assertions.assertThat; import java.io.IOException; -import java.nio.ByteBuffer; import java.io.InputStream; +import java.nio.ByteBuffer; import java.util.Arrays; -import org.junit.Test; import lombok.experimental.FieldDefaults; import lombok.val; +import org.junit.Test; public class BytesUtilsTest { diff --git a/src/test/java/io/appulse/utils/ReflectionUtilsTest.java b/src/test/java/io/appulse/utils/ReflectionUtilsTest.java index ef7f7db..bd92a17 100644 --- a/src/test/java/io/appulse/utils/ReflectionUtilsTest.java +++ b/src/test/java/io/appulse/utils/ReflectionUtilsTest.java @@ -29,61 +29,61 @@ */ public class ReflectionUtilsTest { - @Test - public void getFieldValueFrom () { - ChildClass object = new ChildClass("Artem", 27); + @Test + public void getFieldValueFrom () { + ChildClass object = new ChildClass("Artem", 27); - assertThat(ReflectionUtils.getFieldValueFrom(object, "name")) - .isPresent() - .hasValue("Artem"); + assertThat(ReflectionUtils.getFieldValueFrom(object, "name")) + .isPresent() + .hasValue("Artem"); - assertThat(ReflectionUtils.getFieldValueFrom(object, "age")) - .isPresent() - .hasValue(27); + assertThat(ReflectionUtils.getFieldValueFrom(object, "age")) + .isPresent() + .hasValue(27); - assertThat(ReflectionUtils.getFieldValueFrom(object, "popa")) - .isNotPresent(); - } + assertThat(ReflectionUtils.getFieldValueFrom(object, "popa")) + .isNotPresent(); + } - @Test - public void invokeMethodOf () { - ChildClass object = new ChildClass("Artem", 27); + @Test + public void invokeMethodOf () { + ChildClass object = new ChildClass("Artem", 27); - assertThat(ReflectionUtils.invokeMethodOf(object, "getName")) - .isNotNull() - .isEqualTo("Artem"); + assertThat(ReflectionUtils.invokeMethodOf(object, "getName")) + .isNotNull() + .isEqualTo("Artem"); - assertThat(ReflectionUtils.invokeMethodOf(object, "getAge")) - .isNotNull() - .isEqualTo(27); + assertThat(ReflectionUtils.invokeMethodOf(object, "getAge")) + .isNotNull() + .isEqualTo(27); - assertThat(object.isFlag()).isFalse(); - assertThat(ReflectionUtils.invokeMethodOf(object, "setFlag", true)) - .isNull(); - assertThat(object.isFlag()).isTrue(); + assertThat(object.isFlag()).isFalse(); + assertThat(ReflectionUtils.invokeMethodOf(object, "setFlag", true)) + .isNull(); + assertThat(object.isFlag()).isTrue(); - assertThat(ReflectionUtils.invokeMethodOf(object, "popa")) - .isNull(); - } + assertThat(ReflectionUtils.invokeMethodOf(object, "popa")) + .isNull(); + } - @Getter - @RequiredArgsConstructor - class ParentClass { + @Getter + @RequiredArgsConstructor + class ParentClass { - private final int age; - } + private final int age; + } - @Getter - class ChildClass extends ParentClass { + @Getter + class ChildClass extends ParentClass { - private final String name; + private final String name; - @Setter - private boolean flag; + @Setter + private boolean flag; - ChildClass (String name, int age) { - super(age); - this.name = name; - } + ChildClass (String name, int age) { + super(age); + this.name = name; } + } } From 9e5d9bdc0158a915a6df24b4637e95a97c320fd2 Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Thu, 22 Mar 2018 22:59:47 +0300 Subject: [PATCH 04/58] Add tests and threads helpers --- CHANGELOG.md | 9 + pom.xml | 29 ++- .../io/appulse/utils/test/TestAppender.java | 40 ++++ .../utils/test/TestMethodNamePrinter.java | 39 ++++ .../utils/threads/AppulseExecutors.java | 75 +++++++ .../utils/threads/AppulseThreadFactory.java | 91 +++++++++ .../ExecutorServiceWithClientTrace.java | 53 +++++ .../ExecutorServiceWithTimeMonitor.java | 53 +++++ .../executor/ExecutorServiceWrapper.java | 75 +++++++ ...heduledExecutorServiceWithClientTrace.java | 53 +++++ .../ScheduledExecutorServiceWrapper.java | 66 +++++++ .../builder/ExecutorServiceBuilder.java | 183 ++++++++++++++++++ .../executor/builder/ForkJoinPoolBuilder.java | 89 +++++++++ .../ScheduledExecutorServiceBuilder.java | 137 +++++++++++++ .../threads/AppulseThreadFactoryTest.java | 68 +++++++ .../ExecutorServiceWithClientTraceTest.java | 64 ++++++ .../ExecutorServiceWithTimeMonitorTest.java | 75 +++++++ src/test/resources/logback-test.xml | 30 +++ 18 files changed, 1221 insertions(+), 8 deletions(-) create mode 100644 src/main/java/io/appulse/utils/test/TestAppender.java create mode 100644 src/main/java/io/appulse/utils/test/TestMethodNamePrinter.java create mode 100644 src/main/java/io/appulse/utils/threads/AppulseExecutors.java create mode 100644 src/main/java/io/appulse/utils/threads/AppulseThreadFactory.java create mode 100644 src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java create mode 100644 src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitor.java create mode 100644 src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWrapper.java create mode 100644 src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWithClientTrace.java create mode 100644 src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWrapper.java create mode 100644 src/main/java/io/appulse/utils/threads/executor/builder/ExecutorServiceBuilder.java create mode 100644 src/main/java/io/appulse/utils/threads/executor/builder/ForkJoinPoolBuilder.java create mode 100644 src/main/java/io/appulse/utils/threads/executor/builder/ScheduledExecutorServiceBuilder.java create mode 100644 src/test/java/io/appulse/utils/threads/AppulseThreadFactoryTest.java create mode 100644 src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java create mode 100644 src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitorTest.java create mode 100644 src/test/resources/logback-test.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 71a54b8..158adcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add more tests. - Add `JavaDoc`. +## [1.5.0](https://github.com/appulse-projects/utils-java/releases/tag/1.5.0) - 2018-03-22 + +Added tests and threads helpers. + +### Added + +- Threads helpers: executor wrappers, customizable thread factory and executor builders. +- Test helpers. + ## [1.3.3](https://github.com/appulse-projects/utils-java/releases/tag/1.3.3) - 2018-03-15 Small refactoring. diff --git a/pom.xml b/pom.xml index 7b048d3..d6c1485 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ limitations under the License. io.appulse utils-java - 1.3.3 + 1.5.0 jar @@ -62,7 +62,7 @@ limitations under the License. https://github.com/appulse-projects/utils-java scm:git:https://github.com/appulse-projects/utils-java.git scm:git:https://github.com/appulse-projects/utils-java.git - 1.3.3 + 1.5.0 @@ -102,6 +102,25 @@ limitations under the License. provided + + org.slf4j + slf4j-api + 1.7.25 + + + io.appulse + logging-java + 1.0.2 + provided + + + + junit + junit + 4.12 + provided + + com.google.code.findbugs annotations @@ -115,12 +134,6 @@ limitations under the License. provided - - junit - junit - 4.12 - test - org.assertj assertj-core diff --git a/src/main/java/io/appulse/utils/test/TestAppender.java b/src/main/java/io/appulse/utils/test/TestAppender.java new file mode 100644 index 0000000..95baa97 --- /dev/null +++ b/src/main/java/io/appulse/utils/test/TestAppender.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.test; + +import java.util.LinkedList; +import java.util.List; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +@SuppressFBWarnings("MS_MUTABLE_COLLECTION_PKGPROTECT") +public class TestAppender extends AppenderBase { + + public static final List EVENTS = new LinkedList<>(); + + @Override + protected void append (ILoggingEvent eventObject) { + EVENTS.add(eventObject); + } +} diff --git a/src/main/java/io/appulse/utils/test/TestMethodNamePrinter.java b/src/main/java/io/appulse/utils/test/TestMethodNamePrinter.java new file mode 100644 index 0000000..5d02c54 --- /dev/null +++ b/src/main/java/io/appulse/utils/test/TestMethodNamePrinter.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.test; + +import lombok.val; + +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +@SuppressWarnings("PMD.SystemPrintln") +public class TestMethodNamePrinter extends TestWatcher { + + @Override + protected void starting (Description description) { + val message = String.format("%nRUNNING TEST: %s.%s%n", + description.getClassName(), + description.getMethodName()); + System.out.println(message); + } +} diff --git a/src/main/java/io/appulse/utils/threads/AppulseExecutors.java b/src/main/java/io/appulse/utils/threads/AppulseExecutors.java new file mode 100644 index 0000000..55fe4ef --- /dev/null +++ b/src/main/java/io/appulse/utils/threads/AppulseExecutors.java @@ -0,0 +1,75 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.threads; + +import static java.lang.Integer.MAX_VALUE; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.MINUTES; + +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.SynchronousQueue; + +import io.appulse.utils.threads.executor.builder.ExecutorServiceBuilder; +import io.appulse.utils.threads.executor.builder.ForkJoinPoolBuilder; +import io.appulse.utils.threads.executor.builder.ScheduledExecutorServiceBuilder; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +public final class AppulseExecutors { + + public static ExecutorServiceBuilder newFixedThreadPool (int threads) { + return new ExecutorServiceBuilder() + .corePoolSize(threads) + .maxPoolSize(threads) + .keepAliveTime(0L) + .unit(MILLISECONDS); + } + + public static ForkJoinPoolBuilder newWorkStealingPool () { + return new ForkJoinPoolBuilder() + .parallelism(Runtime.getRuntime().availableProcessors()) + .threadFactory(ForkJoinPool.defaultForkJoinWorkerThreadFactory) + .asyncMode(true); + } + + public static ExecutorServiceBuilder newSingleThreadExecutor () { + return new ExecutorServiceBuilder() + .corePoolSize(1) + .maxPoolSize(1) + .keepAliveTime(0L) + .unit(MILLISECONDS); + } + + public static ExecutorServiceBuilder newCachedThreadPool () { + return new ExecutorServiceBuilder() + .corePoolSize(0) + .maxPoolSize(MAX_VALUE) + .keepAliveTime(1L) + .unit(MINUTES) + .queue(new SynchronousQueue<>()); + } + + public static ScheduledExecutorServiceBuilder newScheduledThreadPool () { + return new ScheduledExecutorServiceBuilder(); + } + + private AppulseExecutors () { + } +} diff --git a/src/main/java/io/appulse/utils/threads/AppulseThreadFactory.java b/src/main/java/io/appulse/utils/threads/AppulseThreadFactory.java new file mode 100644 index 0000000..37ad8d5 --- /dev/null +++ b/src/main/java/io/appulse/utils/threads/AppulseThreadFactory.java @@ -0,0 +1,91 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.threads; + +import static java.lang.Thread.NORM_PRIORITY; +import static java.util.Locale.ROOT; +import static java.util.Optional.ofNullable; +import static lombok.AccessLevel.PRIVATE; + +import java.lang.Thread.UncaughtExceptionHandler; +import java.util.Optional; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicLong; + +import lombok.Builder; +import lombok.NonNull; +import lombok.experimental.FieldDefaults; +import lombok.val; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +@SuppressWarnings("PMD.DoNotUseThreads") +@FieldDefaults(level = PRIVATE, makeFinal = true) +public final class AppulseThreadFactory implements ThreadFactory { + + ThreadFactory parent; + + int priority; + + Optional name; + + AtomicLong threadCount; + + Optional daemon; + + Optional uncaughtExceptionHandler; + + @Builder + public AppulseThreadFactory (String name, Boolean daemon, Integer priority, ThreadFactory parent, + UncaughtExceptionHandler uncaughtExceptionHandler + ) { + this.name = ofNullable(name); + threadCount = this.name + .filter(it -> it.contains("%d")) + .map(it -> new AtomicLong(1)) + .orElse(null); + + this.daemon = ofNullable(daemon); + this.uncaughtExceptionHandler = ofNullable(uncaughtExceptionHandler); + + this.priority = ofNullable(priority) + .orElse(NORM_PRIORITY); + + this.parent = ofNullable(parent) + .orElse(Executors.defaultThreadFactory()); + } + + @Override + public Thread newThread (@NonNull Runnable runnable) { + val thread = parent.newThread(runnable); + thread.setPriority(priority); + + name.map(it -> ofNullable(threadCount) + .map(counter -> String.format(ROOT, it, counter.getAndIncrement())) + .orElse(it) + ) + .ifPresent(thread::setName); + + daemon.ifPresent(thread::setDaemon); + uncaughtExceptionHandler.ifPresent(thread::setUncaughtExceptionHandler); + return thread; + } +} diff --git a/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java new file mode 100644 index 0000000..3c9e586 --- /dev/null +++ b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.threads.executor; + +import java.util.concurrent.ExecutorService; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import lombok.val; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +@Slf4j +@SuppressWarnings("PMD.DoNotUseThreads") +public final class ExecutorServiceWithClientTrace extends ExecutorServiceWrapper { + + public ExecutorServiceWithClientTrace (ExecutorService delegate) { + super(delegate); + } + + @Override + public void execute (@NonNull Runnable command) { + val clientStack = new Exception("Client stack trace"); + val threadName = Thread.currentThread().getName(); + + super.execute(() -> { + try { + command.run(); + } catch (Exception ex) { + log.error("Exception '{}' in task submitted from thread '{}' here:", + ex.getClass().getSimpleName(), threadName, clientStack); + throw ex; + } + }); + } +} diff --git a/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitor.java b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitor.java new file mode 100644 index 0000000..6fde350 --- /dev/null +++ b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitor.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.threads.executor; + +import java.util.concurrent.ExecutorService; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import lombok.val; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +@Slf4j +@SuppressWarnings("PMD.DoNotUseThreads") +public final class ExecutorServiceWithTimeMonitor extends ExecutorServiceWrapper { + + public ExecutorServiceWithTimeMonitor (ExecutorService delegate) { + super(delegate); + } + + @Override + public void execute (@NonNull Runnable command) { + val submitTime = System.currentTimeMillis(); + super.execute(() -> { + long startTime = System.currentTimeMillis(); + long queueDuration = startTime - submitTime; + log.debug("Task {} spent {}ms in queue", command, queueDuration); + try { + command.run(); + } finally { + long endTime = System.currentTimeMillis() - startTime; + log.debug("Task {} end after {}ms", command, endTime); + } + }); + } +} diff --git a/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWrapper.java b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWrapper.java new file mode 100644 index 0000000..913311a --- /dev/null +++ b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWrapper.java @@ -0,0 +1,75 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.threads.executor; + +import static lombok.AccessLevel.PRIVATE; +import static lombok.AccessLevel.PROTECTED; + +import java.util.List; +import java.util.concurrent.AbstractExecutorService; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; + +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +@SuppressWarnings("PMD.DoNotUseThreads") +@RequiredArgsConstructor(access = PROTECTED) +@FieldDefaults(level = PRIVATE, makeFinal = true) +abstract class ExecutorServiceWrapper extends AbstractExecutorService { + + @NonNull + @Getter(PROTECTED) + ExecutorService delegate; + + @Override + public void execute (Runnable command) { + delegate.execute(command); + } + + @Override + public void shutdown () { + delegate.shutdown(); + } + + @Override + public List shutdownNow () { + return delegate.shutdownNow(); + } + + @Override + public boolean isShutdown () { + return delegate.isShutdown(); + } + + @Override + public boolean isTerminated () { + return delegate.isTerminated(); + } + + @Override + public boolean awaitTermination (long timeout, TimeUnit unit) throws InterruptedException { + return delegate.awaitTermination(timeout, unit); + } +} diff --git a/src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWithClientTrace.java b/src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWithClientTrace.java new file mode 100644 index 0000000..2d15b73 --- /dev/null +++ b/src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWithClientTrace.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.threads.executor; + +import java.util.concurrent.ScheduledExecutorService; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import lombok.val; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +@Slf4j +@SuppressWarnings("PMD.DoNotUseThreads") +public final class ScheduledExecutorServiceWithClientTrace extends ScheduledExecutorServiceWrapper { + + public ScheduledExecutorServiceWithClientTrace(ScheduledExecutorService delegate) { + super(delegate); + } + + @Override + public void execute (@NonNull Runnable command) { + val clientStack = new Exception("Client stack trace"); + val threadName = Thread.currentThread().getName(); + + super.execute(() -> { + try { + command.run(); + } catch (Exception ex) { + log.error("Exception {} in task submitted from thread {} here:", + ex, threadName, clientStack); + throw ex; + } + }); + } +} diff --git a/src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWrapper.java b/src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWrapper.java new file mode 100644 index 0000000..532bf4a --- /dev/null +++ b/src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWrapper.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.threads.executor; + +import static lombok.AccessLevel.PRIVATE; +import static lombok.AccessLevel.PROTECTED; + +import java.util.concurrent.Callable; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +@SuppressWarnings("PMD.DoNotUseThreads") +@FieldDefaults(level = PRIVATE, makeFinal = true) +abstract class ScheduledExecutorServiceWrapper extends ExecutorServiceWrapper implements ScheduledExecutorService { + + @Getter(PROTECTED) + ScheduledExecutorService delegate; + + protected ScheduledExecutorServiceWrapper (ScheduledExecutorService delegate) { + super(delegate); + this.delegate = delegate; + } + + @Override + public ScheduledFuture schedule (Runnable command, long delay, TimeUnit unit) { + return delegate.schedule(command, delay, unit); + } + + @Override + public ScheduledFuture schedule (Callable callable, long delay, TimeUnit unit) { + return delegate.schedule(callable, delay, unit); + } + + @Override + public ScheduledFuture scheduleAtFixedRate (Runnable command, long initialDelay, long period, TimeUnit unit) { + return delegate.scheduleAtFixedRate(command, initialDelay, period, unit); + } + + @Override + public ScheduledFuture scheduleWithFixedDelay (Runnable command, long initialDelay, long delay, TimeUnit unit) { + return delegate.scheduleWithFixedDelay(command, initialDelay, delay, unit); + } +} diff --git a/src/main/java/io/appulse/utils/threads/executor/builder/ExecutorServiceBuilder.java b/src/main/java/io/appulse/utils/threads/executor/builder/ExecutorServiceBuilder.java new file mode 100644 index 0000000..d8cab0c --- /dev/null +++ b/src/main/java/io/appulse/utils/threads/executor/builder/ExecutorServiceBuilder.java @@ -0,0 +1,183 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.threads.executor.builder; + +import static java.util.Optional.ofNullable; +import static lombok.AccessLevel.PRIVATE; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import io.appulse.utils.threads.executor.ExecutorServiceWithClientTrace; +import io.appulse.utils.threads.executor.ExecutorServiceWithTimeMonitor; + +import lombok.NonNull; +import lombok.experimental.FieldDefaults; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +@SuppressWarnings({ + "PMD.DoNotUseThreads", + "PMD.AvoidLiteralsInIfCondition", + "PMD.CyclomaticComplexity" +}) +@FieldDefaults(level = PRIVATE) +public final class ExecutorServiceBuilder { + + private static final RejectedExecutionHandler DEFAULT_HANDLER = new ThreadPoolExecutor.AbortPolicy(); + + int corePoolSize; + + int maxPoolSize; + + long keepAliveTime; + + TimeUnit unit; + + BlockingQueue queue; + + int queueLimit; + + boolean clientTrace; + + boolean timeLogging; + + ThreadFactory threadFactory; + + RejectedExecutionHandler handler; + + public ExecutorServiceBuilder corePoolSize (int value) { + if (value < 1) { + throw new IllegalArgumentException("Core pool size must be greater than 0"); + } + this.corePoolSize = value; + return this; + } + + public ExecutorServiceBuilder maxPoolSize (int value) { + if (value < 1) { + throw new IllegalArgumentException("Max pool size must be greater than 0"); + } + this.maxPoolSize = value; + return this; + } + + public ExecutorServiceBuilder keepAliveTime (long value) { + if (value < 0L) { + throw new IllegalArgumentException("Keep alive time must be greater than 0"); + } + this.keepAliveTime = value; + return this; + } + + public ExecutorServiceBuilder unit (@NonNull TimeUnit value) { + this.unit = value; + return this; + } + + public ExecutorServiceBuilder queue (@NonNull BlockingQueue value) { + this.queue = value; + return this; + } + + public ExecutorServiceBuilder queueLimit (int value) { + if (value < 1) { + throw new IllegalArgumentException("Queue limit must be greater than 1"); + } + this.queueLimit = value; + return this; + } + + public ExecutorServiceBuilder enableClientTrace () { + return clientTrace(true); + } + + public ExecutorServiceBuilder clientTrace (boolean value) { + this.clientTrace = value; + return this; + } + + public ExecutorServiceBuilder enableTimeLogging () { + return timeLogging(true); + } + + public ExecutorServiceBuilder timeLogging (boolean value) { + this.timeLogging = value; + return this; + } + + public ExecutorServiceBuilder threadFactory (@NonNull ThreadFactory value) { + this.threadFactory = value; + return this; + } + + public ExecutorServiceBuilder handler (@NonNull RejectedExecutionHandler value) { + this.handler = value; + return this; + } + + public ExecutorService build () { + if (corePoolSize < 1) { + throw new IllegalArgumentException("Core pool size must be greater than 0"); + } + if (maxPoolSize < corePoolSize) { + maxPoolSize = corePoolSize; + } + + if (queueLimit > 0 && queue != null) { + throw new IllegalArgumentException("I couldn't set queue limit and queue simultaneously"); + } else if (queueLimit > 0) { + queue = new LinkedBlockingQueue<>(queueLimit); + } else if (queue == null) { + queue = new LinkedBlockingQueue<>(); + } + + threadFactory = ofNullable(threadFactory) + .orElse(Executors.defaultThreadFactory()); + + handler = ofNullable(handler) + .orElse(DEFAULT_HANDLER); + + ExecutorService result = new ThreadPoolExecutor( + corePoolSize, + maxPoolSize, + keepAliveTime, + unit, + queue, + threadFactory, + handler + ); + + if (clientTrace) { + result = new ExecutorServiceWithClientTrace(result); + } + + if (timeLogging) { + result = new ExecutorServiceWithTimeMonitor(result); + } + return result; + } +} diff --git a/src/main/java/io/appulse/utils/threads/executor/builder/ForkJoinPoolBuilder.java b/src/main/java/io/appulse/utils/threads/executor/builder/ForkJoinPoolBuilder.java new file mode 100644 index 0000000..a16a723 --- /dev/null +++ b/src/main/java/io/appulse/utils/threads/executor/builder/ForkJoinPoolBuilder.java @@ -0,0 +1,89 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.threads.executor.builder; + +import static java.util.Optional.ofNullable; +import static java.util.concurrent.ForkJoinPool.defaultForkJoinWorkerThreadFactory; +import static lombok.AccessLevel.PRIVATE; + +import java.lang.Thread.UncaughtExceptionHandler; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory; + +import lombok.NonNull; +import lombok.experimental.FieldDefaults; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +@SuppressWarnings("PMD.AvoidLiteralsInIfCondition") +@FieldDefaults(level = PRIVATE) +public final class ForkJoinPoolBuilder { + + int parallelism; + + ForkJoinWorkerThreadFactory threadFactory; + + UncaughtExceptionHandler handler; + + boolean asyncMode = true; + + public ForkJoinPoolBuilder parallelism (int value) { + if (value < 1) { + throw new IllegalArgumentException("Parallelism must be greater than 0"); + } + this.parallelism = value; + return this; + } + + public ForkJoinPoolBuilder threadFactory (@NonNull ForkJoinWorkerThreadFactory value) { + this.threadFactory = value; + return this; + } + + public ForkJoinPoolBuilder handler (@NonNull UncaughtExceptionHandler value) { + this.handler = value; + return this; + } + + public ForkJoinPoolBuilder enableAsyncMode () { + return asyncMode(true); + } + + public ForkJoinPoolBuilder asyncMode (boolean value) { + this.asyncMode = value; + return this; + } + + public ForkJoinPool build () { + if (parallelism < 1) { + parallelism = Runtime.getRuntime().availableProcessors(); + } + + threadFactory = ofNullable(threadFactory) + .orElse(defaultForkJoinWorkerThreadFactory); + + return new ForkJoinPool( + parallelism, + threadFactory, + handler, + asyncMode + ); + } +} diff --git a/src/main/java/io/appulse/utils/threads/executor/builder/ScheduledExecutorServiceBuilder.java b/src/main/java/io/appulse/utils/threads/executor/builder/ScheduledExecutorServiceBuilder.java new file mode 100644 index 0000000..89c48a4 --- /dev/null +++ b/src/main/java/io/appulse/utils/threads/executor/builder/ScheduledExecutorServiceBuilder.java @@ -0,0 +1,137 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.threads.executor.builder; + +import static java.util.Optional.ofNullable; +import static lombok.AccessLevel.PRIVATE; + +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; + +import io.appulse.utils.threads.executor.ScheduledExecutorServiceWithClientTrace; + +import lombok.NonNull; +import lombok.experimental.FieldDefaults; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +@SuppressWarnings("PMD.AvoidLiteralsInIfCondition") +@FieldDefaults(level = PRIVATE) +public final class ScheduledExecutorServiceBuilder { + + private static final RejectedExecutionHandler DEFAULT_HANDLER = new ThreadPoolExecutor.AbortPolicy(); + + int poolSize = 1; + + boolean continueExistingPeriodicTasksAfterShutdownPolicy; + + boolean executeExistingDelayedTasksAfterShutdownPolicy = true; + + boolean removeOnCancelPolicy; + + boolean useClientTrace; + + ThreadFactory threadFactory; + + RejectedExecutionHandler handler; + + public ScheduledExecutorServiceBuilder poolSize (int value) { + if (value < 1) { + throw new IllegalArgumentException("Pool size must be greater than 0"); + } + this.poolSize = value; + return this; + } + + public ScheduledExecutorServiceBuilder continueExistingPeriodicTasksAfterShutdownPolicy () { + return continueExistingPeriodicTasksAfterShutdownPolicy(true); + } + + public ScheduledExecutorServiceBuilder continueExistingPeriodicTasksAfterShutdownPolicy (boolean value) { + this.continueExistingPeriodicTasksAfterShutdownPolicy = value; + return this; + } + + public ScheduledExecutorServiceBuilder executeExistingDelayedTasksAfterShutdownPolicy () { + return executeExistingDelayedTasksAfterShutdownPolicy(true); + } + + public ScheduledExecutorServiceBuilder executeExistingDelayedTasksAfterShutdownPolicy (boolean value) { + this.executeExistingDelayedTasksAfterShutdownPolicy = value; + return this; + } + + public ScheduledExecutorServiceBuilder removeOnCancelPolicy () { + return removeOnCancelPolicy(true); + } + + public ScheduledExecutorServiceBuilder removeOnCancelPolicy (boolean value) { + this.removeOnCancelPolicy = value; + return this; + } + + public ScheduledExecutorServiceBuilder clientTrace () { + return clientTrace(true); + } + + public ScheduledExecutorServiceBuilder clientTrace (boolean value) { + this.useClientTrace = value; + return this; + } + + public ScheduledExecutorServiceBuilder threadFactory (@NonNull ThreadFactory value) { + this.threadFactory = value; + return this; + } + + public ScheduledExecutorServiceBuilder handler (@NonNull RejectedExecutionHandler value) { + this.handler = value; + return this; + } + + public ScheduledExecutorService build () { + if (poolSize < 1) { + throw new IllegalArgumentException("Pool size must be greater than 0"); + } + + threadFactory = ofNullable(threadFactory) + .orElse(Executors.defaultThreadFactory()); + + handler = ofNullable(handler) + .orElse(DEFAULT_HANDLER); + + ScheduledThreadPoolExecutor result = new ScheduledThreadPoolExecutor( + poolSize, + threadFactory, + handler + ); + result.setContinueExistingPeriodicTasksAfterShutdownPolicy(continueExistingPeriodicTasksAfterShutdownPolicy); + result.setExecuteExistingDelayedTasksAfterShutdownPolicy(executeExistingDelayedTasksAfterShutdownPolicy); + result.setRemoveOnCancelPolicy(removeOnCancelPolicy); + + return useClientTrace + ? new ScheduledExecutorServiceWithClientTrace(result) + : result; + } +} diff --git a/src/test/java/io/appulse/utils/threads/AppulseThreadFactoryTest.java b/src/test/java/io/appulse/utils/threads/AppulseThreadFactoryTest.java new file mode 100644 index 0000000..a539088 --- /dev/null +++ b/src/test/java/io/appulse/utils/threads/AppulseThreadFactoryTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.threads; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ThreadFactory; + +import org.junit.Test; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +public class AppulseThreadFactoryTest { + + @Test + public void simpleName () throws Exception { + CompletableFuture future = new CompletableFuture<>(); + + AppulseThreadFactory.builder() + .name("popa") + .build() + .newThread(() -> future.complete(Thread.currentThread().getName())) + .start(); + + assertThat(future.get(1, SECONDS)) + .isEqualTo("popa"); + } + + @Test + public void nameWithCount () throws Exception { + ThreadFactory factory = AppulseThreadFactory.builder() + .name("popa-%d") + .build(); + + CompletableFuture future1 = new CompletableFuture<>(); + factory.newThread(() -> future1.complete(Thread.currentThread().getName())) + .start(); + + assertThat(future1.get(1, SECONDS)) + .isEqualTo("popa-1"); + + CompletableFuture future2 = new CompletableFuture<>(); + factory.newThread(() -> future2.complete(Thread.currentThread().getName())) + .start(); + + assertThat(future2.get(1, SECONDS)) + .isEqualTo("popa-2"); + } +} diff --git a/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java b/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java new file mode 100644 index 0000000..8cac0cc --- /dev/null +++ b/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.threads.executor; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static java.util.stream.Collectors.joining; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.ExecutorService; + +import io.appulse.utils.test.TestAppender; +import io.appulse.utils.threads.AppulseExecutors; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import lombok.val; +import org.junit.Before; +import org.junit.Test; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +public class ExecutorServiceWithClientTraceTest { + + @Before + public void before () { + TestAppender.EVENTS.clear(); + } + + @Test + public void test () throws InterruptedException { + ExecutorService service = AppulseExecutors.newSingleThreadExecutor() + .enableClientTrace() + .build(); + + service.execute(() -> { + throw new RuntimeException("boom!"); + }); + + SECONDS.sleep(1); + + val logs = TestAppender.EVENTS.stream() + .map(ILoggingEvent::getFormattedMessage) + .collect(joining("\n")); + + assertThat(logs) + .containsPattern("Exception '\\S+' in task submitted from thread '\\S+' here:"); + } +} diff --git a/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitorTest.java b/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitorTest.java new file mode 100644 index 0000000..afd0ea1 --- /dev/null +++ b/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitorTest.java @@ -0,0 +1,75 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.threads.executor; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static java.util.stream.Collectors.joining; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; + +import io.appulse.utils.test.TestAppender; +import io.appulse.utils.threads.AppulseExecutors; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import lombok.val; +import org.junit.Before; +import org.junit.Test; + +/** + * + * @author Artem Labazin + * @since 1.5.0 + */ +public class ExecutorServiceWithTimeMonitorTest { + + @Before + public void before () { + TestAppender.EVENTS.clear(); + } + + @Test + public void monitor () throws Exception { + ExecutorService service = AppulseExecutors.newSingleThreadExecutor() + .enableTimeLogging() + .build(); + + service.execute(() -> { + try { + SECONDS.sleep(3); + } catch (Exception ex) { + } + }); + + Future future = service.submit(() -> { + try { + SECONDS.sleep(1); + } catch (Exception ex) { + } + }); + + future.get(5, SECONDS); + + val logs = TestAppender.EVENTS.stream() + .map(ILoggingEvent::getFormattedMessage) + .collect(joining("\n")); + + assertThat(logs).containsPattern("Task \\S+ spent \\d+ms in queue"); + assertThat(logs).containsPattern("Task \\S+ end after \\d+ms"); + } +} diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml new file mode 100644 index 0000000..cf335f3 --- /dev/null +++ b/src/test/resources/logback-test.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + From f45ecbd5ea39d654f223cba98bcdeb1cdfed81a5 Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Sat, 7 Apr 2018 20:04:24 +0300 Subject: [PATCH 05/58] Add fancy logging for ExecutorServiceWithClientTraceTest. --- CHANGELOG.md | 8 +++++ pom.xml | 4 +-- .../ExecutorServiceWithClientTrace.java | 30 ++++++++++++++++--- .../ExecutorServiceWithClientTraceTest.java | 2 +- 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 158adcd..717bc8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add more tests. - Add `JavaDoc`. +## [1.5.1](https://github.com/appulse-projects/utils-java/releases/tag/1.5.1) - 2018-04-07 + +Add fancy logging for `ExecutorServiceWithClientTraceTest`. + +### Changed + +- No more re-throw exception in `ExecutorServiceWithClientTraceTest`. + ## [1.5.0](https://github.com/appulse-projects/utils-java/releases/tag/1.5.0) - 2018-03-22 Added tests and threads helpers. diff --git a/pom.xml b/pom.xml index d6c1485..619d1a5 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ limitations under the License. io.appulse utils-java - 1.5.0 + 1.5.1 jar @@ -62,7 +62,7 @@ limitations under the License. https://github.com/appulse-projects/utils-java scm:git:https://github.com/appulse-projects/utils-java.git scm:git:https://github.com/appulse-projects/utils-java.git - 1.5.0 + 1.5.1 diff --git a/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java index 3c9e586..0ac9a08 100644 --- a/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java +++ b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java @@ -31,23 +31,45 @@ @SuppressWarnings("PMD.DoNotUseThreads") public final class ExecutorServiceWithClientTrace extends ExecutorServiceWrapper { + private static final String EXCEPTION_SEPARATOR = "------ submitted from: ------"; + public ExecutorServiceWithClientTrace (ExecutorService delegate) { super(delegate); } @Override public void execute (@NonNull Runnable command) { - val clientStack = new Exception("Client stack trace"); + Exception clientStack = new Exception("Client stack trace"); val threadName = Thread.currentThread().getName(); super.execute(() -> { try { command.run(); } catch (Exception ex) { - log.error("Exception '{}' in task submitted from thread '{}' here:", - ex.getClass().getSimpleName(), threadName, clientStack); - throw ex; + log.error("Exception during task execution submitted from thread '{}'", + threadName, merge(clientStack, ex)); } }); } + + private Throwable merge (Exception local, Exception remote) { + Throwable result = remote; + + val remoteStackTrace = remote.getStackTrace(); + val localStackTrace = local.getStackTrace(); + + val newStackTrace = new StackTraceElement[localStackTrace.length + remoteStackTrace.length]; + System.arraycopy(remoteStackTrace, 0, newStackTrace, 0, remoteStackTrace.length); + + newStackTrace[remoteStackTrace.length] = new StackTraceElement( + EXCEPTION_SEPARATOR, + "", + "", + -1 + ); + System.arraycopy(localStackTrace, 1, newStackTrace, remoteStackTrace.length + 1, localStackTrace.length - 1); + + result.setStackTrace(newStackTrace); + return result; + } } diff --git a/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java b/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java index 8cac0cc..c7de2e4 100644 --- a/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java +++ b/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java @@ -59,6 +59,6 @@ public void test () throws InterruptedException { .collect(joining("\n")); assertThat(logs) - .containsPattern("Exception '\\S+' in task submitted from thread '\\S+' here:"); + .containsPattern("Exception during task execution submitted from thread '\\S+'"); } } From 9e37539d4bf094370186da8ada0f7811c6624351 Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Sun, 22 Apr 2018 01:42:12 +0300 Subject: [PATCH 06/58] Speed-up unsigned functions --- CHANGELOG.md | 9 +++++ pom.xml | 2 +- .../java/io/appulse/utils/BytesUtils.java | 40 +++++++++++++++---- .../ExecutorServiceWithClientTrace.java | 1 + .../java/io/appulse/utils/BytesUtilsTest.java | 6 +++ 5 files changed, 50 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 717bc8c..d398fed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add more tests. - Add `JavaDoc`. +## [1.5.2](https://github.com/appulse-projects/utils-java/releases/tag/1.5.2) - 2018-04-22 + +Speed-up unsigned functions execution. + +### Changed + +- byte/short/int unsigned functions became more fast. +- Catched exception in `ExecutorServiceWithClientTraceTest` rethrows again. + ## [1.5.1](https://github.com/appulse-projects/utils-java/releases/tag/1.5.1) - 2018-04-07 Add fancy logging for `ExecutorServiceWithClientTraceTest`. diff --git a/pom.xml b/pom.xml index 619d1a5..dd34fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ limitations under the License. io.appulse utils-java - 1.5.1 + 1.5.2 jar diff --git a/src/main/java/io/appulse/utils/BytesUtils.java b/src/main/java/io/appulse/utils/BytesUtils.java index 2f5ec65..cb09fc9 100644 --- a/src/main/java/io/appulse/utils/BytesUtils.java +++ b/src/main/java/io/appulse/utils/BytesUtils.java @@ -93,7 +93,7 @@ public static byte[] asBytes (double value) { * @since 1.3.1 */ public static short asUnsignedByte (byte value) { - return asUnsignedByte(new byte[] { value }); + return (short) (value & 0xff); } /** @@ -111,7 +111,20 @@ public static short asUnsignedByte (@NonNull byte[] bytes) { public static short asShort (@NonNull byte[] bytes) { val aligned = align(bytes, Short.BYTES); - return (short) ((aligned[0] << 8) | (aligned[1] & 0xff)); + return (short) ((aligned[0] << 8) | (aligned[1] & 0xff)); + } + + /** + * Transforms byte array to unsigned short integer value as integer. + * + * @param value signed short value + * + * @return unsigned short as integer + * + * @since 1.5.2 + */ + public static int asUnsignedShort (short value) { + return value & 0xFFFF; } /** @@ -119,7 +132,7 @@ public static short asShort (@NonNull byte[] bytes) { * * @param bytes byte array * - * @return unsigned short integer + * @return unsigned short as integer * * @since 1.3.1 */ @@ -129,23 +142,36 @@ public static int asUnsignedShort (@NonNull byte[] bytes) { public static char asChar (@NonNull byte[] bytes) { val aligned = align(bytes, Short.BYTES); - return (char) ((aligned[0] << 8) | (aligned[1] & 0xff)); + return (char) ((aligned[0] << 8) | (aligned[1] & 0xff)); } public static int asInteger (@NonNull byte[] bytes) { val aligned = align(bytes, Integer.BYTES); return (aligned[0] << 24) | ((aligned[1] & 0xff) << 16) - | ((aligned[2] & 0xff) << 8) + | ((aligned[2] & 0xff) << 8) | (aligned[3] & 0xff); } + /** + * Transforms byte array to unsigned integer value as long integer. + * + * @param value signed integer value + * + * @return unsigned integer as long + * + * @since 1.5.2 + */ + public static long asUnsignedInteger (int value) { + return value & 0x00000000FFFFFFFFL; + } + /** * Transforms byte array to unsigned integer value as long integer. * * @param bytes byte array * - * @return unsigned integer + * @return unsigned integer as long * * @since 1.3.1 */ @@ -161,7 +187,7 @@ public static long asLong (@NonNull byte[] bytes) { | (((long) aligned[3] & 0xff) << 32) | (((long) aligned[4] & 0xff) << 24) | (((long) aligned[5] & 0xff) << 16) - | (((long) aligned[6] & 0xff) << 8) + | (((long) aligned[6] & 0xff) << 8) | ((long) aligned[7] & 0xff); } diff --git a/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java index 0ac9a08..3858a7d 100644 --- a/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java +++ b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java @@ -48,6 +48,7 @@ public void execute (@NonNull Runnable command) { } catch (Exception ex) { log.error("Exception during task execution submitted from thread '{}'", threadName, merge(clientStack, ex)); + throw ex; } }); } diff --git a/src/test/java/io/appulse/utils/BytesUtilsTest.java b/src/test/java/io/appulse/utils/BytesUtilsTest.java index 3533166..2dc5500 100644 --- a/src/test/java/io/appulse/utils/BytesUtilsTest.java +++ b/src/test/java/io/appulse/utils/BytesUtilsTest.java @@ -117,6 +117,9 @@ public void asUnsignedShort () { assertThat(BytesUtils.asUnsignedShort(bytes)) .isEqualTo(62994); + + assertThat(BytesUtils.asUnsignedShort((short) -1)) + .isEqualTo(65535); } @Test @@ -164,6 +167,9 @@ public void asUnsignedInteger () { assertThat(BytesUtils.asUnsignedInteger(bytes)) .isEqualTo(4_100_000_000L); + + assertThat(BytesUtils.asUnsignedInteger(-1)) + .isEqualTo(4_294_967_295L); } @Test From 3930bbbba4f9a15b08619277f5a3414abdcd785d Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Tue, 22 May 2018 13:55:36 +0300 Subject: [PATCH 07/58] Created ExceptionUtils helper class --- CHANGELOG.md | 9 ++++ pom.xml | 2 +- .../java/io/appulse/utils/ExceptionUtils.java | 50 +++++++++++++++++++ .../io/appulse/utils/ExceptionUtilsTest.java | 47 +++++++++++++++++ 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/main/java/io/appulse/utils/ExceptionUtils.java create mode 100644 src/test/java/io/appulse/utils/ExceptionUtilsTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index d398fed..e87ba19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add more tests. - Add `JavaDoc`. +## [1.6.0](https://github.com/appulse-projects/utils-java/releases/tag/1.6.0) - 2018-05-22 + +Created ExceptionUtils helper class. + +### Added + +- `ExceptionUtils` helper class. +- Add `ExceptionUtils`.`softException` wrapper for sneaky throws exceptions. + ## [1.5.2](https://github.com/appulse-projects/utils-java/releases/tag/1.5.2) - 2018-04-22 Speed-up unsigned functions execution. diff --git a/pom.xml b/pom.xml index dd34fb7..a3f0120 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ limitations under the License. io.appulse utils-java - 1.5.2 + 1.6.0 jar diff --git a/src/main/java/io/appulse/utils/ExceptionUtils.java b/src/main/java/io/appulse/utils/ExceptionUtils.java new file mode 100644 index 0000000..05dae75 --- /dev/null +++ b/src/main/java/io/appulse/utils/ExceptionUtils.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils; + +/** + * Different exception helpers. + * + * @author Artem Labazin + * @since 1.6.0 + */ +public final class ExceptionUtils { + + /** + * Removes 'checkedness' of the setted exception. It works like @{code @SneakyThrows} annotation in Project Lombok. + *

+ * For more information, see this: + * http://johannesbrodwall.com/2018/05/15/a-wicked-java-trick-to-make-the-jvm-forget-to-check-exceptions/ + * + * @param ex checked exception. + * + * @return exception withoud checkedness. + * + * @since 1.6.0 + */ + public static RuntimeException softException (Exception ex) { + return checkednessRemover(ex); + } + + @SuppressWarnings("unchecked") + private static T checkednessRemover (Exception ex) throws T { + throw (T) ex; + } + + private ExceptionUtils () { + } +} diff --git a/src/test/java/io/appulse/utils/ExceptionUtilsTest.java b/src/test/java/io/appulse/utils/ExceptionUtilsTest.java new file mode 100644 index 0000000..a870ac3 --- /dev/null +++ b/src/test/java/io/appulse/utils/ExceptionUtilsTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils; + +import static io.appulse.utils.ExceptionUtils.softException; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.io.IOException; + +import org.junit.Test; + +/** + * + * @author Artem Labazin + * @since 1.6.0 + */ +public class ExceptionUtilsTest { + + @Test + public void test () { + assertThat(doSomething(true)).isTrue(); + + assertThatThrownBy(() -> doSomething(false)).isExactlyInstanceOf(IOException.class); + } + + private boolean doSomething (boolean value) { + if (value) { + return value; + } + throw softException(new IOException()); + } +} From 0023b90f2983d3d7b81e1414efc1a687ec284c11 Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Thu, 24 May 2018 19:13:39 +0300 Subject: [PATCH 08/58] Created AnnotationUtils helper class --- CHANGELOG.md | 10 + pom.xml | 6 +- .../io/appulse/utils/AnnotationUtils.java | 248 ++++++++++++++++++ .../io/appulse/utils/AnnotationUtilsTest.java | 150 +++++++++++ 4 files changed, 411 insertions(+), 3 deletions(-) create mode 100644 src/main/java/io/appulse/utils/AnnotationUtils.java create mode 100644 src/test/java/io/appulse/utils/AnnotationUtilsTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index e87ba19..3344939 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add more tests. - Add `JavaDoc`. +## [1.7.0](https://github.com/appulse-projects/utils-java/releases/tag/1.7.0) - 2018-05-24 + +Created AnnotationUtils helper class. + +### Added + +- `AnnotationUtils` helper class. +- `AnnotationUtils`.`findAnnotation` method for deep searching annotations. +- `AnnotationUtils`.`isInJavaLangAnnotationPackage` method for determining user's/java annotations. + ## [1.6.0](https://github.com/appulse-projects/utils-java/releases/tag/1.6.0) - 2018-05-22 Created ExceptionUtils helper class. diff --git a/pom.xml b/pom.xml index a3f0120..252ec0a 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ limitations under the License. io.appulse utils-java - 1.6.0 + 1.7.0 jar @@ -62,7 +62,7 @@ limitations under the License. https://github.com/appulse-projects/utils-java scm:git:https://github.com/appulse-projects/utils-java.git scm:git:https://github.com/appulse-projects/utils-java.git - 1.5.1 + 1.7.0 @@ -161,7 +161,7 @@ limitations under the License. org.apache.maven.plugins maven-javadoc-plugin - 3.0.0 + 2.10.4 -Xdoclint:none -Xdoclint:none diff --git a/src/main/java/io/appulse/utils/AnnotationUtils.java b/src/main/java/io/appulse/utils/AnnotationUtils.java new file mode 100644 index 0000000..5d21982 --- /dev/null +++ b/src/main/java/io/appulse/utils/AnnotationUtils.java @@ -0,0 +1,248 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils; + +import static java.util.Optional.ofNullable; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Stream; + +/** + * Different annotation helpers. + * + * @author Artem Labazin + * @since 1.7.0 + */ +public final class AnnotationUtils { + + /** + * Find a single {@link Annotation} of {@code annotationType} on the + * supplied {@link Class}, traversing its interfaces, annotations, and + * superclasses if the annotation is not directly present on + * the given class itself. + *

+ * This method explicitly handles class-level annotations which are not + * declared as {@link java.lang.annotation.Inherited inherited} as well + * as meta-annotations and annotations on interfaces. + *

+ * The algorithm operates as follows: + *

    + *
  1. Search for the annotation on the given class and return it if found. + *
  2. Recursively search through all annotations that the given class declares. + *
  3. Recursively search through all interfaces that the given class declares. + *
  4. Recursively search through the superclass hierarchy of the given class. + *
+ *

+ * Note: in this context, the term recursively means that the search + * process continues by returning to step #1 with the current interface, + * annotation, or superclass as the class to look for annotations on. + * + * @param clazz the class to look for annotations on + * + * @param annotationType the annotation type to look for, both locally and as a meta-annotation + * + * @return the first matching annotation + * + * @since 1.7.0 + */ + public static Optional findAnnotation (Class clazz, Class annotationType) { + T result = findAnnotation(clazz, annotationType, new HashSet<>()); + return ofNullable(result); + } + + /** + * Find a single {@link Annotation} of {@code annotationType} on the + * supplied {@link AnnotatedElement}. + *

+ * Meta-annotations will be searched if the annotation is not + * directly present on the supplied element. + *

+ * Warning: this method operates generically on + * annotated elements. In other words, this method does not execute + * specialized search algorithms for classes or methods. If you require + * the more specific semantics of {@link #findAnnotation(Class, Class)} + * or {@link #findAnnotation(Method, Class)}, invoke one of those methods + * instead. + * + * @param annotatedElement the {@code AnnotatedElement} on which to find the annotation + * + * @param annotationType the annotation type to look for, both locally and as a meta-annotation + * + * @return the first matching annotation + * + * @since 1.7.0 + */ + public static Optional findAnnotation (AnnotatedElement annotatedElement, + Class annotationType + ) { + T result = findAnnotation(annotatedElement, annotationType, new HashSet<>()); + return ofNullable(result); + } + + /** + * Find a single {@link Annotation} of {@code annotationType} on the supplied + * {@link Method}, traversing its super methods (i.e., from superclasses and + * interfaces) if the annotation is not directly present on the given + * method itself. + *

+ * Correctly handles bridge {@link Method Methods} generated by the compiler. + *

+ * Meta-annotations will be searched if the annotation is not + * directly present on the method. + *

+ * Annotations on methods are not inherited by default, so we need to handle + * this explicitly. + * + * @param method the method to look for annotations on + * + * @param annotationType the annotation type to look for + * + * @return the first matching annotation + * + * @since 1.7.0 + */ + public static Optional findAnnotation (Method method, Class annotationType) { + T result = findAnnotation(method, annotationType, new HashSet<>()); + return ofNullable(result); + } + + /** + * Determine if the supplied {@link Annotation} is defined in the core JDK {@code java.lang.annotation} package. + * + * @param annotation the annotation to check + * + * @return {@code true} if the annotation is in the {@code java.lang.annotation} package + * + * @since 1.7.0 + */ + public static boolean isInJavaLangAnnotationPackage (Annotation annotation) { + return annotation != null && isInJavaLangAnnotationPackage(annotation.annotationType()); + } + + /** + * Determine if the {@link Annotation} with the supplied name is defined in the core JDK {@code java.lang.annotation} package. + * + * @param annotationType the annotation type to check + * + * @return {@code true} if the annotation is in the {@code java.lang.annotation} package + * + * @since 1.7.0 + */ + public static boolean isInJavaLangAnnotationPackage (Class annotationType) { + return annotationType != null && isInJavaLangAnnotationPackage(annotationType.getName()); + } + + /** + * Determine if the {@link Annotation} with the supplied name is defined in the core JDK {@code java.lang.annotation} package. + * + * @param annotationType the name of the annotation type to check + * + * @return {@code true} if the annotation is in the {@code java.lang.annotation} package + * + * @since 1.7.0 + */ + public static boolean isInJavaLangAnnotationPackage (String annotationType) { + return annotationType != null && annotationType.startsWith("java.lang.annotation"); + } + + private static T findAnnotation (Method method, + Class annotationType, + Set visited + ) { + T result = findAnnotation((AnnotatedElement) method, annotationType, visited); + if (result != null) { + return result; + } + Class declaringClass = method.getDeclaringClass(); + return ofNullable(declaringClass.getSuperclass()) + .filter(it -> it != Object.class) + .map(it -> findAnnotation(it, method, annotationType, visited)) + .filter(Objects::nonNull) + .orElseGet(() -> Stream.of(declaringClass.getInterfaces()) + .map(it -> findAnnotation(it, method, annotationType, visited)) + .filter(Objects::nonNull) + .findAny() + .orElse(null)); + } + + private static T findAnnotation (Class clazz, + Method method, + Class annotationType, + Set visited + ) { + return Stream.of(clazz.getDeclaredMethods()) + .filter(it -> method.getName().equals(it.getName())) + .filter(it -> Arrays.equals(method.getParameterTypes(), it.getParameterTypes())) + .findAny() + .map(it -> findAnnotation(it, annotationType, visited)) + .orElse(null); + } + + private static T findAnnotation (Class clazz, + Class annotationType, + Set visited + ) { + T result = findAnnotation((AnnotatedElement) clazz, annotationType, visited); + if (result != null) { + return result; + } + for (Class type : clazz.getInterfaces()) { + T annotation = findAnnotation(type, annotationType, visited); + if (annotation != null) { + return annotation; + } + } + Class superclass = clazz.getSuperclass(); + if (superclass == null || Object.class == superclass) { + return null; + } + return findAnnotation(superclass, annotationType, visited); + } + + @SuppressWarnings("unchecked") + private static T findAnnotation (AnnotatedElement annotatedElement, + Class annotationType, + Set visited + ) { + Annotation[] declaredAnnotations = annotatedElement.getDeclaredAnnotations(); + for (Annotation annotation : declaredAnnotations) { + if (annotation.annotationType() == annotationType) { + return (T) annotation; + } + } + for (Annotation annotation : declaredAnnotations) { + if (isInJavaLangAnnotationPackage(annotation) || !visited.add(annotation)) { + continue; + } + T result = findAnnotation(annotation.annotationType(), annotationType, visited); + if (result != null) { + return result; + } + } + return null; + } + + private AnnotationUtils () { + } +} diff --git a/src/test/java/io/appulse/utils/AnnotationUtilsTest.java b/src/test/java/io/appulse/utils/AnnotationUtilsTest.java new file mode 100644 index 0000000..1ab7f45 --- /dev/null +++ b/src/test/java/io/appulse/utils/AnnotationUtilsTest.java @@ -0,0 +1,150 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static org.assertj.core.api.Assertions.assertThat; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.junit.Test; + +/** + * + * @author alabazin + */ +public class AnnotationUtilsTest { + + @Test + public void testType1 () { + String str = AnnotationUtils.findAnnotation(Child.class, ChildAnnotation.class) + .map(ChildAnnotation::value) + .orElse(""); + + assertThat(str).isEqualTo("annotated parent type"); + } + + @Test + public void testType2 () { + String str = AnnotationUtils.findAnnotation(Child.class, ParentAnnotation.class) + .map(ParentAnnotation::value) + .orElse(""); + + assertThat(str).isEqualTo("annotated child type"); + } + + @Test + public void testType3 () { + String str = AnnotationUtils.findAnnotation(Parent.class, ParentAnnotation.class) + .map(ParentAnnotation::value) + .orElse(""); + + assertThat(str).isEqualTo("annotated annotation"); + } + + @Test + public void testMethod1 () throws NoSuchMethodException { + Method method = Child.class.getMethod("method"); + String str = AnnotationUtils.findAnnotation(method, ChildAnnotation.class) + .map(ChildAnnotation::value) + .orElse(""); + + assertThat(str).isEqualTo("annotated parent method"); + } + + @Test + public void testMethod2 () throws NoSuchMethodException { + Method method = Child.class.getMethod("method"); + String str = AnnotationUtils.findAnnotation(method, ParentAnnotation.class) + .map(ParentAnnotation::value) + .orElse(""); + + assertThat(str).isEqualTo("annotated child method"); + } + + @Test + public void testMethod3 () throws NoSuchMethodException { + Method method = Parent.class.getMethod("method"); + String str = AnnotationUtils.findAnnotation(method, ParentAnnotation.class) + .map(ParentAnnotation::value) + .orElse(""); + + assertThat(str).isEqualTo("annotated annotation"); + } + + @Test + public void testField1 () throws NoSuchFieldException { + Field field = Child.class.getDeclaredField("field"); + String str = AnnotationUtils.findAnnotation(field, ChildAnnotation.class) + .map(ChildAnnotation::value) + .orElse(""); + + assertThat(str).isEqualTo("annotated child field"); + } + + @Test + public void testField2 () throws NoSuchFieldException { + Field field = Child.class.getDeclaredField("field"); + String str = AnnotationUtils.findAnnotation(field, ParentAnnotation.class) + .map(ParentAnnotation::value) + .orElse(""); + + assertThat(str).isEqualTo("annotated annotation"); + } + + @Target({ANNOTATION_TYPE, METHOD, FIELD, TYPE}) + @Retention(RUNTIME) + public @interface ParentAnnotation { + + String value (); + } + + @Target({ANNOTATION_TYPE, METHOD, FIELD, TYPE}) + @Retention(RUNTIME) + @ParentAnnotation("annotated annotation") + public @interface ChildAnnotation { + + String value (); + } + + @ChildAnnotation("annotated parent type") + public static class Parent { + + @ChildAnnotation("annotated parent method") + public void method () { + } + } + + @ParentAnnotation("annotated child type") + public static class Child extends Parent { + + @ChildAnnotation("annotated child field") + String field; + + @Override + @ParentAnnotation("annotated child method") + public void method () { + } + } +} From 0dacb1d97da0b19a93cd2a9003500a3e693d4c7f Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Mon, 28 May 2018 00:23:32 +0300 Subject: [PATCH 09/58] Created SerializationUtils helper class and RoundRobin collection wrapper --- CHANGELOG.md | 12 ++ pom.xml | 4 +- .../java/io/appulse/utils/RoundRobin.java | 91 ++++++++++ .../io/appulse/utils/SerializationUtils.java | 145 +++++++++++++++ .../exception/SerializationException.java | 52 ++++++ .../java/io/appulse/utils/RoundRobinTest.java | 38 ++++ .../appulse/utils/SerializationUtilsTest.java | 168 ++++++++++++++++++ 7 files changed, 508 insertions(+), 2 deletions(-) create mode 100644 src/main/java/io/appulse/utils/RoundRobin.java create mode 100644 src/main/java/io/appulse/utils/SerializationUtils.java create mode 100644 src/main/java/io/appulse/utils/exception/SerializationException.java create mode 100644 src/test/java/io/appulse/utils/RoundRobinTest.java create mode 100644 src/test/java/io/appulse/utils/SerializationUtilsTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 3344939..8d1a334 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add more tests. - Add `JavaDoc`. +## [1.8.0](https://github.com/appulse-projects/utils-java/releases/tag/1.8.0) - 2018-05-25 + +Created SerializationUtils helper class and RoundRobin collection wrapper. + +### Added + +- `SerializationUtils` helper class. +- `SerializationUtils`.`serialize` method for converting object to a byte array. +- `SerializationUtils`.`deserialize` method for creating object from an array of bytes. +- `SerializationException` exception thrown when the Serialization process fails. +- `RoundRobin` collection wrapper. + ## [1.7.0](https://github.com/appulse-projects/utils-java/releases/tag/1.7.0) - 2018-05-24 Created AnnotationUtils helper class. diff --git a/pom.xml b/pom.xml index 252ec0a..371d42e 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ limitations under the License. io.appulse utils-java - 1.7.0 + 1.8.0 jar @@ -62,7 +62,7 @@ limitations under the License. https://github.com/appulse-projects/utils-java scm:git:https://github.com/appulse-projects/utils-java.git scm:git:https://github.com/appulse-projects/utils-java.git - 1.7.0 + 1.8.0 diff --git a/src/main/java/io/appulse/utils/RoundRobin.java b/src/main/java/io/appulse/utils/RoundRobin.java new file mode 100644 index 0000000..23d1bc5 --- /dev/null +++ b/src/main/java/io/appulse/utils/RoundRobin.java @@ -0,0 +1,91 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils; + +import static lombok.AccessLevel.PRIVATE; + +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicInteger; + +import lombok.NonNull; +import lombok.experimental.FieldDefaults; + +/** + * Round robin collection wrapper. + * + * @author Artem Labazin + * @since 1.8.0 + */ +@FieldDefaults(level = PRIVATE) +public final class RoundRobin { + + final AtomicInteger position = new AtomicInteger(0); + + final T[] elements; + + volatile int size; + + @SuppressWarnings("unchecked") + public RoundRobin (@NonNull T... elements) { + if (elements.length == 0) { + throw new IllegalArgumentException("Elements array is empty"); + } + this.elements = elements; + size = elements.length; + } + + @SuppressWarnings("unchecked") + public RoundRobin (@NonNull Collection collection) { + if (collection.isEmpty()) { + throw new IllegalArgumentException("Elements collection is empty"); + } + size = collection.size(); + + Class elementType = collection.iterator() + .next() + .getClass(); + + this.elements = (T[]) Array.newInstance(elementType, size); + + Iterator iterator = collection.iterator(); + int counter = 0; + while (iterator.hasNext()) { + elements[counter] = iterator.next(); + counter++; + } + } + + public T getNext () { + int index = getNextIndex(); + return elements[index]; + } + + private int getNextIndex () { + while (true) { + int current = position.get(); + int next = current + 1; + if (next >= size) { + next = 0; + } + if (position.compareAndSet(current, next)) { + return current; + } + } + } +} diff --git a/src/main/java/io/appulse/utils/SerializationUtils.java b/src/main/java/io/appulse/utils/SerializationUtils.java new file mode 100644 index 0000000..333fd3d --- /dev/null +++ b/src/main/java/io/appulse/utils/SerializationUtils.java @@ -0,0 +1,145 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; + +import io.appulse.utils.exception.SerializationException; + +import lombok.NonNull; +import lombok.val; + +/** + * Different serialization helpers. + * + * @author Artem Labazin + * @since 1.8.0 + */ +public final class SerializationUtils { + + /** + * Serializes an {@code Object} to the specified stream. + *

+ * The stream will be closed once the object is written. This avoids the need for a finally clause, and maybe also + * exception handling, in the application code. + *

+ * The stream passed in is not buffered internally within this method. This is the responsibility of your application + * if desired. + * + * @param object the object to serialize to bytes, may be null + * + * @param outputStream the stream to write to, must not be null + * + * @throws NullPointerException if {@code outputStream} is {@code null} + * + * @throws SerializationException (runtime) if the serialization fails + * + * @since 1.8.0 + */ + public static void serialize (Serializable object, @NonNull OutputStream outputStream) { + try (val objectOutputStream = new ObjectOutputStream(outputStream)) { + objectOutputStream.writeObject(object); + } catch (IOException ex) { + throw new SerializationException(ex); + } + } + + /** + * Serializes an {@code Object} to a byte array for storage/serialization. + * + * @param obj the object to serialize to bytes + * + * @return a byte[] with the converted Serializable + * + * @throws SerializationException (runtime) if the serialization fails + * + * @since 1.8.0 + */ + public static byte[] serialize (Serializable obj) { + val byteArrayOutputStream = new ByteArrayOutputStream(512); + serialize(obj, byteArrayOutputStream); + return byteArrayOutputStream.toByteArray(); + } + + /** + * Deserializes an {@code Object} from the specified stream. + *

+ * The stream will be closed once the object is written. This avoids the need for a finally clause, and maybe also + * exception handling, in the application code. + *

+ * The stream passed in is not buffered internally within this method. This is the responsibility of your application + * if desired. + *

+ * If the call site incorrectly types the return value, a {@link ClassCastException} is thrown from the call site. + * Without Generics in this declaration, the call site must type cast and can cause the same ClassCastException. Note + * that in both cases, the ClassCastException is in the call site, not in this method. + * + * @param the object type to be deserialized + * + * @param inputStream the serialized object input stream, must not be null + * + * @return the deserialized object + * + * @throws NullPointerException if {@code inputStream} is {@code null} + * + * @throws SerializationException (runtime) if the serialization fails + * + * @since 1.8.0 + */ + public static T deserialize (@NonNull InputStream inputStream) { + try (val objectInputStream = new ObjectInputStream(inputStream)) { + @SuppressWarnings("unchecked") + T obj = (T) objectInputStream.readObject(); + return obj; + } catch (ClassNotFoundException | IOException ex) { + throw new SerializationException(ex); + } + } + + /** + * Deserializes a single {@code Object} from an array of bytes. + *

+ * If the call site incorrectly types the return value, a {@link ClassCastException} is thrown from the call site. + * Without Generics in this declaration, the call site must type cast and can cause the same ClassCastException. Note + * that in both cases, the ClassCastException is in the call site, not in this method. + * + * @param the object type to be deserialized + * + * @param objectData the serialized object, must not be null + * + * @return the deserialized object + * + * @throws NullPointerException if {@code objectData} is {@code null} + * + * @throws SerializationException (runtime) if the serialization fails + * + * @since 1.8.0 + */ + public static T deserialize (@NonNull byte[] objectData) { + return deserialize(new ByteArrayInputStream(objectData)); + } + + private SerializationUtils() { + } +} diff --git a/src/main/java/io/appulse/utils/exception/SerializationException.java b/src/main/java/io/appulse/utils/exception/SerializationException.java new file mode 100644 index 0000000..b4dad07 --- /dev/null +++ b/src/main/java/io/appulse/utils/exception/SerializationException.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.exception; + +/** + * Exception thrown when the Serialization process fails. + *

+ * The original error is wrapped within this one. + *

+ * #NotThreadSafe# because Throwable is not thread-safe. + * + * @author Artem Labazin + * @since 1.8.0 + */ +public class SerializationException extends RuntimeException { + + private static final long serialVersionUID = 8179675064137603549L; + + public SerializationException() { + super(); + } + + public SerializationException(String message) { + super(message); + } + + public SerializationException(String message, Throwable cause) { + super(message, cause); + } + + public SerializationException(Throwable cause) { + super(cause); + } + + public SerializationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/test/java/io/appulse/utils/RoundRobinTest.java b/src/test/java/io/appulse/utils/RoundRobinTest.java new file mode 100644 index 0000000..295c3ef --- /dev/null +++ b/src/test/java/io/appulse/utils/RoundRobinTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +/** + * @author Artem Labazin + * @since 1.8.0 + */ +public class RoundRobinTest { + + @Test + public void test () { + RoundRobin roundRobin = new RoundRobin<>("one", "two"); + assertThat(roundRobin.getNext()).isEqualTo("one"); + assertThat(roundRobin.getNext()).isEqualTo("two"); + assertThat(roundRobin.getNext()).isEqualTo("one"); + assertThat(roundRobin.getNext()).isEqualTo("two"); + assertThat(roundRobin.getNext()).isEqualTo("one"); + } +} diff --git a/src/test/java/io/appulse/utils/SerializationUtilsTest.java b/src/test/java/io/appulse/utils/SerializationUtilsTest.java new file mode 100644 index 0000000..97dfa1c --- /dev/null +++ b/src/test/java/io/appulse/utils/SerializationUtilsTest.java @@ -0,0 +1,168 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.util.HashMap; + +import io.appulse.utils.exception.SerializationException; + +import lombok.val; +import org.junit.Test; + +/** + * + * @author alabazin + */ +public class SerializationUtilsTest { + + @Test + public void testSerializeStream () throws Exception { + HashMap map = new HashMap<>(2); + map.put("foo", "foo"); + map.put("bar", 7); + + val streamTest = new ByteArrayOutputStream(); + SerializationUtils.serialize(map, streamTest); + + val streamReal = new ByteArrayOutputStream(); + val objectOutputStream = new ObjectOutputStream(streamReal); + objectOutputStream.writeObject(map); + objectOutputStream.flush(); + objectOutputStream.close(); + + val testBytes = streamTest.toByteArray(); + val realBytes = streamReal.toByteArray(); + + assertThat(testBytes.length).isEqualTo(realBytes.length); + assertThat(realBytes).isEqualTo(testBytes); + } + + @Test + public void testSerializeStreamUnserializable () throws Exception { + HashMap map = new HashMap<>(2); + map.put("foo", "foo"); + map.put("bar", 7); + map.put(new Object(), new Object()); + + val streamTest = new ByteArrayOutputStream(); + assertThatThrownBy(() -> SerializationUtils.serialize(map, streamTest)) + .isExactlyInstanceOf(SerializationException.class); + } + + @Test + public void testSerializeStreamNullObj () throws Exception { + val streamTest = new ByteArrayOutputStream(); + SerializationUtils.serialize(null, streamTest); + + val streamReal = new ByteArrayOutputStream(); + val objectOutputStream = new ObjectOutputStream(streamReal); + objectOutputStream.writeObject(null); + objectOutputStream.flush(); + objectOutputStream.close(); + + val testBytes = streamTest.toByteArray(); + val realBytes = streamReal.toByteArray(); + + assertThat(testBytes.length).isEqualTo(realBytes.length); + assertThat(realBytes).isEqualTo(testBytes); + } + + @Test + public void testSerializeStreamObjNull () throws Exception { + assertThatThrownBy(() -> SerializationUtils.serialize(new HashMap<>(), null)) + .isExactlyInstanceOf(NullPointerException.class); + } + + @Test + public void testSerializeStreamNullNull () throws Exception { + assertThatThrownBy(() -> SerializationUtils.serialize(null, null)) + .isExactlyInstanceOf(NullPointerException.class); + } + + @Test + public void testSerializeException () throws Exception { + val outputStream = new OutputStream() { + + @Override + public void write (final int arg0) throws IOException { + throw new IOException("popa"); + } + }; + + assertThatThrownBy(() -> SerializationUtils.serialize(new HashMap<>(), outputStream)) + .isExactlyInstanceOf(SerializationException.class) + .hasMessage("java.io.IOException: popa"); + } + + @Test + public void testDeserializeBytes () throws Exception { + HashMap map = new HashMap<>(2); + map.put("foo", "foo"); + map.put("bar", 7); + + val byteArrayOutputStream = new ByteArrayOutputStream(); + val objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); + objectOutputStream.writeObject(map); + objectOutputStream.flush(); + objectOutputStream.close(); + + val result = SerializationUtils.deserialize(byteArrayOutputStream.toByteArray()); + assertThat(result).isNotNull(); + assertThat(result).isInstanceOf(HashMap.class); + assertThat(result == map).isFalse(); + + HashMap testMap = (HashMap) result; + assertThat(testMap.get("foo")).isEqualTo(map.get("foo")); + assertThat(testMap.get("foo") == map.get("foo")).isFalse(); + + assertThat(testMap.get("bar")).isEqualTo(map.get("bar")); + assertThat(testMap.get("bar") == map.get("bar")).isFalse(); + + assertThat(testMap).isEqualTo(map); + } + + @Test + public void testDeserializeBytesOfNull () throws IOException { + val byteArrayOutputStream = new ByteArrayOutputStream(); + val objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); + objectOutputStream.writeObject(null); + objectOutputStream.flush(); + objectOutputStream.close(); + + val result = SerializationUtils.deserialize(byteArrayOutputStream.toByteArray()); + assertThat(result).isNull(); + } + + @Test + public void testDeserializeBytesNull () { + assertThatThrownBy(() -> SerializationUtils.deserialize((byte[]) null)) + .isExactlyInstanceOf(NullPointerException.class); + } + + @Test + public void testDeserializeBytesBadStream () { + assertThatThrownBy(() -> SerializationUtils.deserialize(new byte[0])) + .isExactlyInstanceOf(SerializationException.class); + } +} From 07f485664ff9e6455d9a28bf531d9d71e3aa1cb4 Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Mon, 28 May 2018 00:42:26 +0300 Subject: [PATCH 10/58] Exclude unused PMD rule --- .codestyle/pmd.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/.codestyle/pmd.xml b/.codestyle/pmd.xml index 4c55656..2da7c89 100644 --- a/.codestyle/pmd.xml +++ b/.codestyle/pmd.xml @@ -70,6 +70,7 @@ limitations under the License. + From 290cc8cb5198657183353b635f7abcf84cd6f158 Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Tue, 11 Sep 2018 19:13:21 +0300 Subject: [PATCH 11/58] Add LRU cache --- CHANGELOG.md | 6 +++ pom.xml | 14 +++---- src/main/java/io/appulse/utils/LruCache.java | 43 ++++++++++++++++++++ 3 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 src/main/java/io/appulse/utils/LruCache.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d1a334..e7ae326 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add more tests. - Add `JavaDoc`. +## [1.9.0](https://github.com/appulse-projects/utils-java/releases/tag/1.9.0) - 2018-09-11 + +### Added + +- Created `LruCache` implementation. + ## [1.8.0](https://github.com/appulse-projects/utils-java/releases/tag/1.8.0) - 2018-05-25 Created SerializationUtils helper class and RoundRobin collection wrapper. diff --git a/pom.xml b/pom.xml index 371d42e..fe8261f 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ limitations under the License. io.appulse utils-java - 1.8.0 + 1.9.0 jar @@ -62,7 +62,7 @@ limitations under the License. https://github.com/appulse-projects/utils-java scm:git:https://github.com/appulse-projects/utils-java.git scm:git:https://github.com/appulse-projects/utils-java.git - 1.8.0 + 1.9.0 @@ -98,7 +98,7 @@ limitations under the License. org.projectlombok lombok - 1.16.20 + 1.18.2 provided @@ -110,7 +110,7 @@ limitations under the License. io.appulse logging-java - 1.0.2 + 1.1.0 provided @@ -124,7 +124,7 @@ limitations under the License. com.google.code.findbugs annotations - 3.0.1 + 3.0.1u2 provided @@ -137,7 +137,7 @@ limitations under the License. org.assertj assertj-core - 3.9.1 + 3.11.1 test @@ -277,7 +277,7 @@ limitations under the License. com.puppycrawl.tools checkstyle - 8.8 + 8.12 diff --git a/src/main/java/io/appulse/utils/LruCache.java b/src/main/java/io/appulse/utils/LruCache.java new file mode 100644 index 0000000..5856558 --- /dev/null +++ b/src/main/java/io/appulse/utils/LruCache.java @@ -0,0 +1,43 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils; + +import java.util.LinkedHashMap; +import java.util.Map.Entry; + +/** + * LRU cache implementation based on {@code LinkedHashMap} + * + * @author Artem Labazin + * @since 1.9.0 + */ +public class LruCache extends LinkedHashMap { + + private static final long serialVersionUID = -1100634446524987320L; + + private final int maxSize; + + public LruCache (int maxSize) { + super(maxSize + 1, 1.0F, true); + this.maxSize = maxSize; + } + + @Override + protected boolean removeEldestEntry (Entry eldest) { + return size() > maxSize; + } +} From bdf1663b94848dbbd35fe01dbd3071aa953433c9 Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Tue, 25 Sep 2018 17:36:56 +0300 Subject: [PATCH 12/58] Add new resource utils functions --- CHANGELOG.md | 14 ++ pom.xml | 4 +- .../java/io/appulse/utils/ResourceUtils.java | 200 ++++++++++++++++++ .../io/appulse/utils/cache/FifoCache.java | 49 +++++ .../appulse/utils/{ => cache}/LruCache.java | 12 +- .../io/appulse/utils/ResourceUtilsTest.java | 16 ++ src/test/resources/folder/file-1.txt | 1 + src/test/resources/folder/file-11.txt | 1 + src/test/resources/folder/file-2.md | 1 + src/test/resources/folder/file-3.exe | 1 + src/test/resources/folder/file-4.html | 1 + src/test/resources/folder/garbage.txt | 1 + 12 files changed, 296 insertions(+), 5 deletions(-) create mode 100644 src/main/java/io/appulse/utils/cache/FifoCache.java rename src/main/java/io/appulse/utils/{ => cache}/LruCache.java (81%) create mode 100644 src/test/resources/folder/file-1.txt create mode 100644 src/test/resources/folder/file-11.txt create mode 100644 src/test/resources/folder/file-2.md create mode 100644 src/test/resources/folder/file-3.exe create mode 100644 src/test/resources/folder/file-4.html create mode 100644 src/test/resources/folder/garbage.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index e7ae326..0e1ef7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add more tests. - Add `JavaDoc`. +## [1.10.0](https://github.com/appulse-projects/utils-java/releases/tag/1.10.0) - 2018-09-25 + +### Added + +- `FifoCache` implementation; +- `ResourceUtils.getResourceUrls` function for flexible searching resource files; +- `ResourceUtils.get*Content` functions for extracting resource files content; +- A test for checking `ResourceUtils.getResourceUrls` and `ResourceUtils.get*Content` functions. + +### Changed + +- `ResourceUtils.getResource` are deprecated, use `ResourceUtils.get*Content` functions; +- `LruCache` and `FifoCache` moved to `io.appulse.utils.cache` package. + ## [1.9.0](https://github.com/appulse-projects/utils-java/releases/tag/1.9.0) - 2018-09-11 ### Added diff --git a/pom.xml b/pom.xml index fe8261f..0e216f9 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ limitations under the License. io.appulse utils-java - 1.9.0 + 1.10.0 jar @@ -62,7 +62,7 @@ limitations under the License. https://github.com/appulse-projects/utils-java scm:git:https://github.com/appulse-projects/utils-java.git scm:git:https://github.com/appulse-projects/utils-java.git - 1.9.0 + 1.10.0 diff --git a/src/main/java/io/appulse/utils/ResourceUtils.java b/src/main/java/io/appulse/utils/ResourceUtils.java index a2fa2bb..5babccd 100644 --- a/src/main/java/io/appulse/utils/ResourceUtils.java +++ b/src/main/java/io/appulse/utils/ResourceUtils.java @@ -20,11 +20,25 @@ import static java.util.Optional.empty; import static java.util.Optional.of; +import java.io.File; import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLDecoder; import java.nio.charset.Charset; +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; import java.util.Optional; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.regex.Pattern; +import java.util.stream.Stream; import lombok.NonNull; +import lombok.SneakyThrows; import lombok.val; /** @@ -34,11 +48,76 @@ */ public final class ResourceUtils { + @Deprecated public static Optional getResource (@NonNull String name) { return getResource(name, UTF_8); } + @Deprecated public static Optional getResource (@NonNull String name, @NonNull Charset charset) { + return getTextContent(name, charset); + } + + /** + * Returns bytes content of a resource file by its URL. + * + * @param url adress to a resource. + * + * @return file's bytes representation, if exists, or empty. + * + * @since 1.10.0 + */ + public static Optional getBytesContent (@NonNull URL url) { + try { + InputStream inputStream = url.openStream(); + byte[] bytes = BytesUtils.read(inputStream); + return of(bytes); + } catch (Exception ex) { + return empty(); + } + } + + /** + * Returns text content of a resource file by its URL. + * + * @param url adress to a resource. + * + * @param charset text content charset. + * + * @return file's text representation, if exists, or empty. + * + * @since 1.10.0 + */ + public static Optional getTextContent (@NonNull URL url, @NonNull Charset charset) { + return getBytesContent(url) + .map(it -> new String(it, charset)); + } + + /** + * Returns a concrete resource content by its name. + * + * @param name file's name + * + * @return file's text representation, if exists, or empty. + * + * @since 1.10.0 + */ + public static Optional getTextContent (@NonNull String name) { + return getTextContent(name, UTF_8); + } + + /** + * Returns a concrete resource content by its name. + * + * @param name file's name + * + * @param charset text content charset. + * + * @return file's text representation, if exists, or empty. + * + * @since 1.10.0 + */ + public static Optional getTextContent (@NonNull String name, @NonNull Charset charset) { val classLoader = Thread.currentThread().getContextClassLoader(); InputStream inputStream = classLoader.getResourceAsStream(name); if (inputStream == null) { @@ -53,6 +132,127 @@ public static Optional getResource (@NonNull String name, @NonNull Chars return of(string); } + /** + * Returns text content of a resource file by its URL. + * + * @param url adress to a resource. + * + * @return file's text representation, if exists, or empty. + * + * @since 1.10.0 + */ + public static Optional getTextContent (@NonNull URL url) { + return getTextContent(url, UTF_8); + } + + /** + * Searches resource files in specific folder and by glob-pattern. + *

+ * It uses glob-like pattern sysytem...honestly speaking only '*' and '?' signs. + * + * @param folder where to search the files + * + * @param glob files name glob-pattern + * + * @return the URLs of found files + * + * @since 1.10.0 + */ + public static List getResourceUrls (@NonNull String folder, @NonNull String glob) { + Pattern pattern = of(glob) + .map(Pattern::quote) + .map(it -> it.replace("*", "\\E.*\\Q")) + .map(it -> it.replace("?", "\\E.\\Q")) + .map(it -> '^' + it + '$') + .map(Pattern::compile) + .orElseThrow(RuntimeException::new); + + return getResourceUrls(folder, pattern); + } + + /** + * Searches resource files in specific folder and by pattern. + * + * @param folder where to search the files + * + * @param pattern files name pattern + * + * @return the URLs of found files + * + * @since 1.10.0 + */ + @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") + @SneakyThrows + public static List getResourceUrls (@NonNull String folder, @NonNull Pattern pattern) { + List result = new LinkedList<>(); + + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + Enumeration urls = classLoader.getResources(folder); + + while (urls.hasMoreElements()) { + URL url = urls.nextElement(); + if (url == null) { + continue; + } + + switch (url.getProtocol()) { + case "file": + toFile(url) + .map(file -> file.isFile() + ? new File[]{ file } + : file.listFiles() + ) + .filter(Objects::nonNull) + .ifPresent(files -> Stream.of(files) + .filter(it -> pattern.matcher(it.getName()).matches()) + .map(it -> { + try { + return it.toURI().toURL(); + } catch (Exception ex) { + return null; + } + }) + .filter(Objects::nonNull) + .forEach(result::add)); + break; + case "jar": + String dirname = of(folder) + .filter(it -> it.endsWith("/")) + .orElseGet(() -> folder + '/'); + + String path = url.getPath(); + String jarPath = path.substring(5, path.indexOf('!')); + + try (JarFile jar = new JarFile(URLDecoder.decode(jarPath, UTF_8.name()))) { + jar.stream() + .map(JarEntry::getName) + .filter(it -> it.startsWith(dirname)) + .filter(it -> pattern.matcher(it).matches()) + .map(it -> classLoader.getResource(it)) + .forEach(result::add); + } + break; + default: + throw new UnsupportedOperationException("unsupported protocol " + url.getProtocol()); + } + } + + return result; + } + + private static Optional toFile (URL url) throws URISyntaxException { + URI uri = url.toURI(); + try { + return of(new File(uri)); + } catch (Exception ex1) { + try { + return of(new File(uri.getPath())); + } catch (Exception ex2) { + return empty(); + } + } + } + private ResourceUtils () { } } diff --git a/src/main/java/io/appulse/utils/cache/FifoCache.java b/src/main/java/io/appulse/utils/cache/FifoCache.java new file mode 100644 index 0000000..0c93382 --- /dev/null +++ b/src/main/java/io/appulse/utils/cache/FifoCache.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.cache; + +import static lombok.AccessLevel.PRIVATE; + +import java.util.LinkedHashMap; +import java.util.Map.Entry; + +import lombok.experimental.FieldDefaults; + + +/** + * FIFO cache implementation based on {@code LinkedHashMap}. + * + * @author Artem Labazin + * @since 1.10.0 + */ +@FieldDefaults(level = PRIVATE, makeFinal = true) +public class FifoCache extends LinkedHashMap { + + private static final long serialVersionUID = 2326368924657010098L; + + int maxSize; + + public FifoCache (int maxSize) { + super(maxSize + 1, 1.0F, false); + this.maxSize = maxSize; + } + + @Override + protected boolean removeEldestEntry (Entry eldest) { + return size() > maxSize; + } +} diff --git a/src/main/java/io/appulse/utils/LruCache.java b/src/main/java/io/appulse/utils/cache/LruCache.java similarity index 81% rename from src/main/java/io/appulse/utils/LruCache.java rename to src/main/java/io/appulse/utils/cache/LruCache.java index 5856558..7a7ed7d 100644 --- a/src/main/java/io/appulse/utils/LruCache.java +++ b/src/main/java/io/appulse/utils/cache/LruCache.java @@ -14,22 +14,28 @@ * limitations under the License. */ -package io.appulse.utils; +package io.appulse.utils.cache; + +import static lombok.AccessLevel.PRIVATE; import java.util.LinkedHashMap; import java.util.Map.Entry; +import lombok.experimental.FieldDefaults; + + /** - * LRU cache implementation based on {@code LinkedHashMap} + * LRU cache implementation based on {@code LinkedHashMap}. * * @author Artem Labazin * @since 1.9.0 */ +@FieldDefaults(level = PRIVATE, makeFinal = true) public class LruCache extends LinkedHashMap { private static final long serialVersionUID = -1100634446524987320L; - private final int maxSize; + int maxSize; public LruCache (int maxSize) { super(maxSize + 1, 1.0F, true); diff --git a/src/test/java/io/appulse/utils/ResourceUtilsTest.java b/src/test/java/io/appulse/utils/ResourceUtilsTest.java index ca54506..e54193b 100644 --- a/src/test/java/io/appulse/utils/ResourceUtilsTest.java +++ b/src/test/java/io/appulse/utils/ResourceUtilsTest.java @@ -16,8 +16,12 @@ package io.appulse.utils; +import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; +import java.util.List; +import java.util.Optional; + import org.junit.Test; /** @@ -39,4 +43,16 @@ public void notExist () { assertThat(ResourceUtils.getResource("/not-exist.txt")) .isNotPresent(); } + + @Test + public void getResourceUrls () { + List list = ResourceUtils.getResourceUrls("folder", "file-?.*") + .stream() + .map(ResourceUtils::getTextContent) + .map(Optional::get) + .map(String::trim) + .collect(toList()); + + assertThat(list).contains("Artem", "Liza", "Milada", "Thais"); + } } diff --git a/src/test/resources/folder/file-1.txt b/src/test/resources/folder/file-1.txt new file mode 100644 index 0000000..9945cf2 --- /dev/null +++ b/src/test/resources/folder/file-1.txt @@ -0,0 +1 @@ +Artem diff --git a/src/test/resources/folder/file-11.txt b/src/test/resources/folder/file-11.txt new file mode 100644 index 0000000..721187e --- /dev/null +++ b/src/test/resources/folder/file-11.txt @@ -0,0 +1 @@ +popa diff --git a/src/test/resources/folder/file-2.md b/src/test/resources/folder/file-2.md new file mode 100644 index 0000000..5e8e667 --- /dev/null +++ b/src/test/resources/folder/file-2.md @@ -0,0 +1 @@ +Liza diff --git a/src/test/resources/folder/file-3.exe b/src/test/resources/folder/file-3.exe new file mode 100644 index 0000000..a13a1cb --- /dev/null +++ b/src/test/resources/folder/file-3.exe @@ -0,0 +1 @@ +Milada diff --git a/src/test/resources/folder/file-4.html b/src/test/resources/folder/file-4.html new file mode 100644 index 0000000..a4ae7ee --- /dev/null +++ b/src/test/resources/folder/file-4.html @@ -0,0 +1 @@ +Thais diff --git a/src/test/resources/folder/garbage.txt b/src/test/resources/folder/garbage.txt new file mode 100644 index 0000000..f98f434 --- /dev/null +++ b/src/test/resources/folder/garbage.txt @@ -0,0 +1 @@ +popa2 From 186acfd0351fc4a46a9c409f5d8fd80a7999222f Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Wed, 13 Feb 2019 20:20:35 +0300 Subject: [PATCH 13/58] Add maven wrapper --- .mvn/wrapper/MavenWrapperDownloader.java | 110 +++++++++ .mvn/wrapper/maven-wrapper.properties | 1 + mvnw | 286 +++++++++++++++++++++++ mvnw.cmd | 161 +++++++++++++ 4 files changed, 558 insertions(+) create mode 100644 .mvn/wrapper/MavenWrapperDownloader.java create mode 100644 .mvn/wrapper/maven-wrapper.properties create mode 100755 mvnw create mode 100644 mvnw.cmd diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000..fa4f7b4 --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,110 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you 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. +*/ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = + "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: : " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..cd0d451 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/mvnw b/mvnw new file mode 100755 index 0000000..5551fde --- /dev/null +++ b/mvnw @@ -0,0 +1,286 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + wget "$jarUrl" -O "$wrapperJarPath" + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + curl -o "$wrapperJarPath" "$jarUrl" + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..0e344f6 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,161 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" +FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + echo Found %WRAPPER_JAR% +) else ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% From 9a86a5d73b1bf250969317366d57f88fc1bb2064 Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Wed, 13 Feb 2019 22:53:50 +0300 Subject: [PATCH 14/58] Update dependencies and copyright --- pom.xml | 200 ++++++++++++++---- src/main/java/io/appulse/utils/Bytes.java | 2 +- .../java/io/appulse/utils/RoundRobin.java | 3 +- .../utils/threads/AppulseExecutors.java | 1 + .../io/appulse/utils/AnnotationUtilsTest.java | 20 +- src/test/java/io/appulse/utils/BytesTest.java | 18 +- .../java/io/appulse/utils/BytesUtilsTest.java | 32 +-- .../io/appulse/utils/ExceptionUtilsTest.java | 6 +- .../io/appulse/utils/ReflectionUtilsTest.java | 8 +- .../io/appulse/utils/ResourceUtilsTest.java | 10 +- .../java/io/appulse/utils/RoundRobinTest.java | 6 +- .../appulse/utils/SerializationUtilsTest.java | 24 +-- .../io/appulse/utils/SocketUtilsTest.java | 6 +- .../threads/AppulseThreadFactoryTest.java | 8 +- .../utils/threads/FutureUtilsTests.java} | 20 +- .../ExecutorServiceWithClientTraceTest.java | 12 +- .../ExecutorServiceWithTimeMonitorTest.java | 13 +- 17 files changed, 246 insertions(+), 143 deletions(-) rename src/{main/java/io/appulse/utils/test/TestMethodNamePrinter.java => test/java/io/appulse/utils/threads/FutureUtilsTests.java} (55%) diff --git a/pom.xml b/pom.xml index 0e216f9..473cdcc 100644 --- a/pom.xml +++ b/pom.xml @@ -24,18 +24,22 @@ limitations under the License. io.appulse utils-java - 1.10.0 + 1.11.0 jar UTF-8 UTF-8 - 1.8 - 1.8 + ${java.vm.specification.version} - 1.8 - 1.8 + ${java.version} + ${java.version} + + ${java.version} + ${java.version} + + false Utils @@ -62,7 +66,7 @@ limitations under the License. https://github.com/appulse-projects/utils-java scm:git:https://github.com/appulse-projects/utils-java.git scm:git:https://github.com/appulse-projects/utils-java.git - 1.10.0 + 1.11.0 @@ -98,7 +102,7 @@ limitations under the License. org.projectlombok lombok - 1.18.2 + 1.18.6 provided @@ -115,16 +119,48 @@ limitations under the License. - junit - junit - 4.12 - provided + org.junit.jupiter + junit-jupiter-engine + 5.4.0 + test + + + org.junit.jupiter + junit-jupiter-params + 5.4.0 + test - com.google.code.findbugs - annotations - 3.0.1u2 + org.assertj + assertj-core + 3.11.1 + test + + + + org.mockito + mockito-core + 2.24.0 + test + + + org.mockito + mockito-junit-jupiter + 2.24.0 + test + + + + net.jcip + jcip-annotations + 1.0 + provided + + + com.github.spotbugs + spotbugs-annotations + 3.1.11 provided @@ -133,17 +169,15 @@ limitations under the License. 3.0.2 provided - - - org.assertj - assertj-core - 3.11.1 - test - + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + org.apache.maven.plugins maven-source-plugin @@ -158,20 +192,50 @@ limitations under the License. + + pl.project13.maven + git-commit-id-plugin + 2.2.6 + + + git-infos + + revision + + + + + true + false + true + false + git + + ${project.build.outputDirectory}/git.properties + + yyyy-MM-dd'T'HH:mm:ssZ + ${project.basedir}/.git + + git.closest.tag.commit.count + git.closest.tag.name + + + + org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + 3.0.1 -Xdoclint:none -Xdoclint:none true - UTF-8 - UTF-8 - UTF-8 + ${project.build.sourceEncoding} + ${project.build.sourceEncoding} + ${project.build.sourceEncoding} true protected - 1.8 + ${java.version} true @@ -188,14 +252,21 @@ limitations under the License. org.apache.maven.plugins maven-surefire-plugin - 2.21.0 + 2.22.1 + ${skipAllTests} false **/*Test.java + **/*Tests.java + **/Test*.java + **/it/** **/*IntegrationTest.java + **/*IntegrationTests.java + **/*IT.java + **/IT*.java @@ -203,14 +274,19 @@ limitations under the License. org.apache.maven.plugins maven-failsafe-plugin - 2.21.0 + 2.22.1 + ${skipAllTests} + false **/*IntegrationTest.java + **/*IntegrationTests.java + **/*IT.java + **/IT*.java + **/it/**/*Test.java + **/it/**/*Tests.java + **/it/**/Test*.java - - **/*Test.java - @@ -224,9 +300,9 @@ limitations under the License. - org.codehaus.mojo - findbugs-maven-plugin - 3.0.5 + com.github.spotbugs + spotbugs-maven-plugin + 3.1.11 Max Low @@ -235,22 +311,22 @@ limitations under the License. - analyze-compile - compile + spotbugs-validation + verify check + org.apache.maven.plugins maven-pmd-plugin - 3.9.0 + 3.11.0 ${project.build.sourceEncoding} ${maven.compiler.source} - true true true true @@ -261,7 +337,8 @@ limitations under the License. - package + pmd-validation + verify check @@ -272,18 +349,18 @@ limitations under the License. org.apache.maven.plugins maven-checkstyle-plugin - 2.17 + 3.0.0 com.puppycrawl.tools checkstyle - 8.12 + 8.17 - validate - validate + checkstyle-validation + verify check @@ -327,7 +404,7 @@ limitations under the License. sign-artifacts - verify + install sign @@ -336,4 +413,39 @@ limitations under the License. + + + + module-java + + [9,12) + + + + + maven-compiler-plugin + + ${java.version} + + + + maven-surefire-plugin + + + --illegal-access=permit + + + + + maven-failsafe-plugin + + + --illegal-access=permit + + + + + + + diff --git a/src/main/java/io/appulse/utils/Bytes.java b/src/main/java/io/appulse/utils/Bytes.java index 8322e1d..f4699c7 100644 --- a/src/main/java/io/appulse/utils/Bytes.java +++ b/src/main/java/io/appulse/utils/Bytes.java @@ -65,7 +65,7 @@ public static Bytes allocate (int capacity) { BytesDelegateGets gets; @NonFinal - @Getter(value = PACKAGE) + @Getter(PACKAGE) ByteBuffer buffer; @NonFinal diff --git a/src/main/java/io/appulse/utils/RoundRobin.java b/src/main/java/io/appulse/utils/RoundRobin.java index 23d1bc5..603cb50 100644 --- a/src/main/java/io/appulse/utils/RoundRobin.java +++ b/src/main/java/io/appulse/utils/RoundRobin.java @@ -19,6 +19,7 @@ import static lombok.AccessLevel.PRIVATE; import java.lang.reflect.Array; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.concurrent.atomic.AtomicInteger; @@ -46,7 +47,7 @@ public RoundRobin (@NonNull T... elements) { if (elements.length == 0) { throw new IllegalArgumentException("Elements array is empty"); } - this.elements = elements; + this.elements = Arrays.copyOf(elements, elements.length); size = elements.length; } diff --git a/src/main/java/io/appulse/utils/threads/AppulseExecutors.java b/src/main/java/io/appulse/utils/threads/AppulseExecutors.java index 55fe4ef..9369f79 100644 --- a/src/main/java/io/appulse/utils/threads/AppulseExecutors.java +++ b/src/main/java/io/appulse/utils/threads/AppulseExecutors.java @@ -32,6 +32,7 @@ * @author Artem Labazin * @since 1.5.0 */ +@SuppressWarnings("PMD.ClassNamingConventions") public final class AppulseExecutors { public static ExecutorServiceBuilder newFixedThreadPool (int threads) { diff --git a/src/test/java/io/appulse/utils/AnnotationUtilsTest.java b/src/test/java/io/appulse/utils/AnnotationUtilsTest.java index 1ab7f45..18549bc 100644 --- a/src/test/java/io/appulse/utils/AnnotationUtilsTest.java +++ b/src/test/java/io/appulse/utils/AnnotationUtilsTest.java @@ -28,16 +28,16 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * * @author alabazin */ -public class AnnotationUtilsTest { +class AnnotationUtilsTest { @Test - public void testType1 () { + void testType1 () { String str = AnnotationUtils.findAnnotation(Child.class, ChildAnnotation.class) .map(ChildAnnotation::value) .orElse(""); @@ -46,7 +46,7 @@ public void testType1 () { } @Test - public void testType2 () { + void testType2 () { String str = AnnotationUtils.findAnnotation(Child.class, ParentAnnotation.class) .map(ParentAnnotation::value) .orElse(""); @@ -55,7 +55,7 @@ public void testType2 () { } @Test - public void testType3 () { + void testType3 () { String str = AnnotationUtils.findAnnotation(Parent.class, ParentAnnotation.class) .map(ParentAnnotation::value) .orElse(""); @@ -64,7 +64,7 @@ public void testType3 () { } @Test - public void testMethod1 () throws NoSuchMethodException { + void testMethod1 () throws NoSuchMethodException { Method method = Child.class.getMethod("method"); String str = AnnotationUtils.findAnnotation(method, ChildAnnotation.class) .map(ChildAnnotation::value) @@ -74,7 +74,7 @@ public void testMethod1 () throws NoSuchMethodException { } @Test - public void testMethod2 () throws NoSuchMethodException { + void testMethod2 () throws NoSuchMethodException { Method method = Child.class.getMethod("method"); String str = AnnotationUtils.findAnnotation(method, ParentAnnotation.class) .map(ParentAnnotation::value) @@ -84,7 +84,7 @@ public void testMethod2 () throws NoSuchMethodException { } @Test - public void testMethod3 () throws NoSuchMethodException { + void testMethod3 () throws NoSuchMethodException { Method method = Parent.class.getMethod("method"); String str = AnnotationUtils.findAnnotation(method, ParentAnnotation.class) .map(ParentAnnotation::value) @@ -94,7 +94,7 @@ public void testMethod3 () throws NoSuchMethodException { } @Test - public void testField1 () throws NoSuchFieldException { + void testField1 () throws NoSuchFieldException { Field field = Child.class.getDeclaredField("field"); String str = AnnotationUtils.findAnnotation(field, ChildAnnotation.class) .map(ChildAnnotation::value) @@ -104,7 +104,7 @@ public void testField1 () throws NoSuchFieldException { } @Test - public void testField2 () throws NoSuchFieldException { + void testField2 () throws NoSuchFieldException { Field field = Child.class.getDeclaredField("field"); String str = AnnotationUtils.findAnnotation(field, ParentAnnotation.class) .map(ParentAnnotation::value) diff --git a/src/test/java/io/appulse/utils/BytesTest.java b/src/test/java/io/appulse/utils/BytesTest.java index b1b5eb9..4f81d20 100644 --- a/src/test/java/io/appulse/utils/BytesTest.java +++ b/src/test/java/io/appulse/utils/BytesTest.java @@ -19,17 +19,17 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * * @author Artem Labazin * @since 1.0.0 */ -public class BytesTest { +class BytesTest { @Test - public void wrap () { + void wrap () { byte[] expected = new byte[] { 1, 2, 3 }; Bytes bytes = Bytes.wrap(expected); @@ -48,7 +48,7 @@ public void wrap () { } @Test - public void position () { + void position () { Bytes bytes = Bytes.allocate(4); assertThat(bytes.position()).isEqualTo(0); @@ -64,7 +64,7 @@ public void position () { } @Test - public void clear () { + void clear () { Bytes bytes = Bytes.allocate() .put1B(1); @@ -78,7 +78,7 @@ public void clear () { } @Test - public void array () { + void array () { Bytes bytes = Bytes.allocate(); assertThat(bytes.array()) @@ -96,7 +96,7 @@ public void array () { } @Test - public void limit () { + void limit () { Bytes bytes = Bytes.allocate(2); assertThat(bytes.limit()).isEqualTo(0); @@ -115,7 +115,7 @@ public void limit () { } @Test - public void remaining () { + void remaining () { Bytes bytes = Bytes.allocate(2); assertThat(bytes.remaining()).isEqualTo(0); @@ -130,7 +130,7 @@ public void remaining () { } @Test - public void unsignedTest () { + void unsignedTest () { Bytes bytes = Bytes.allocate() .put1B(254) .put2B(62994) diff --git a/src/test/java/io/appulse/utils/BytesUtilsTest.java b/src/test/java/io/appulse/utils/BytesUtilsTest.java index 2dc5500..b2496f7 100644 --- a/src/test/java/io/appulse/utils/BytesUtilsTest.java +++ b/src/test/java/io/appulse/utils/BytesUtilsTest.java @@ -26,12 +26,12 @@ import lombok.experimental.FieldDefaults; import lombok.val; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class BytesUtilsTest { +class BytesUtilsTest { @Test - public void asBytes () { + void asBytes () { assertThat(BytesUtils.asBytes('a')) .isEqualTo(new byte[] { 0, 97 }); @@ -55,13 +55,13 @@ public void asBytes () { } @Test - public void concatenate () { + void concatenate () { assertThat(BytesUtils.concatenate(new byte[] { 1 }, new byte[] { 2 }, new byte[] { 3 })) .isEqualTo(new byte[] { 1, 2, 3 }); } @Test - public void align () { + void align () { assertThat(BytesUtils.align(new byte[] { 1 }, 4)) .isEqualTo(new byte[] { 0, 0, 0, 1 }); @@ -70,7 +70,7 @@ public void align () { } @Test - public void asUnsignedByte () { + void asUnsignedByte () { val bytes = ByteBuffer.allocate(Byte.BYTES) .put((byte) 254) .array(); @@ -83,7 +83,7 @@ public void asUnsignedByte () { } @Test - public void asShort () { + void asShort () { val bytes1 = ByteBuffer.allocate(Short.BYTES) .putShort(Short.MAX_VALUE) .array(); @@ -107,7 +107,7 @@ public void asShort () { } @Test - public void asUnsignedShort () { + void asUnsignedShort () { val bytes = ByteBuffer.allocate(Short.BYTES) .putShort((short) 62994) .array(); @@ -123,7 +123,7 @@ public void asUnsignedShort () { } @Test - public void asChar () { + void asChar () { val bytes = ByteBuffer.allocate(Character.BYTES) .putChar('z') .array(); @@ -133,7 +133,7 @@ public void asChar () { } @Test - public void asInteger () { + void asInteger () { val bytes1 = ByteBuffer.allocate(Integer.BYTES) .putInt(Integer.MAX_VALUE) .array(); @@ -157,7 +157,7 @@ public void asInteger () { } @Test - public void asUnsignedInteger () { + void asUnsignedInteger () { val bytes = ByteBuffer.allocate(Integer.BYTES) .putInt((int) 4_100_000_000L) .array(); @@ -173,7 +173,7 @@ public void asUnsignedInteger () { } @Test - public void asLong () { + void asLong () { val bytes1 = ByteBuffer.allocate(Long.BYTES) .putLong(Long.MAX_VALUE) .array(); @@ -197,7 +197,7 @@ public void asLong () { } @Test - public void asFloat () { + void asFloat () { val bytes1 = ByteBuffer.allocate(Float.BYTES) .putFloat(Float.MAX_VALUE) .array(); @@ -221,7 +221,7 @@ public void asFloat () { } @Test - public void asDouble () { + void asDouble () { val bytes1 = ByteBuffer.allocate(Double.BYTES) .putDouble(Double.MAX_VALUE) .array(); @@ -245,7 +245,7 @@ public void asDouble () { } @Test - public void read () throws Exception { + void read () throws Exception { byte[] expected = "Hello world".getBytes(); assertThat(BytesUtils.read(new CustomInputStream(expected))) @@ -253,7 +253,7 @@ public void read () throws Exception { } @Test - public void readWithLength () throws Exception { + void readWithLength () throws Exception { byte[] bytes = "Hello world".getBytes(); byte[] expected = Arrays.copyOfRange(bytes, 0, 2); diff --git a/src/test/java/io/appulse/utils/ExceptionUtilsTest.java b/src/test/java/io/appulse/utils/ExceptionUtilsTest.java index a870ac3..45316a1 100644 --- a/src/test/java/io/appulse/utils/ExceptionUtilsTest.java +++ b/src/test/java/io/appulse/utils/ExceptionUtilsTest.java @@ -22,17 +22,17 @@ import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * * @author Artem Labazin * @since 1.6.0 */ -public class ExceptionUtilsTest { +class ExceptionUtilsTest { @Test - public void test () { + void test () { assertThat(doSomething(true)).isTrue(); assertThatThrownBy(() -> doSomething(false)).isExactlyInstanceOf(IOException.class); diff --git a/src/test/java/io/appulse/utils/ReflectionUtilsTest.java b/src/test/java/io/appulse/utils/ReflectionUtilsTest.java index bd92a17..9caa2b2 100644 --- a/src/test/java/io/appulse/utils/ReflectionUtilsTest.java +++ b/src/test/java/io/appulse/utils/ReflectionUtilsTest.java @@ -21,16 +21,16 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * * @author Artem Labazin */ -public class ReflectionUtilsTest { +class ReflectionUtilsTest { @Test - public void getFieldValueFrom () { + void getFieldValueFrom () { ChildClass object = new ChildClass("Artem", 27); assertThat(ReflectionUtils.getFieldValueFrom(object, "name")) @@ -46,7 +46,7 @@ public void getFieldValueFrom () { } @Test - public void invokeMethodOf () { + void invokeMethodOf () { ChildClass object = new ChildClass("Artem", 27); assertThat(ReflectionUtils.invokeMethodOf(object, "getName")) diff --git a/src/test/java/io/appulse/utils/ResourceUtilsTest.java b/src/test/java/io/appulse/utils/ResourceUtilsTest.java index e54193b..bb417e3 100644 --- a/src/test/java/io/appulse/utils/ResourceUtilsTest.java +++ b/src/test/java/io/appulse/utils/ResourceUtilsTest.java @@ -22,30 +22,30 @@ import java.util.List; import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * * @author Artem Labazin * @since 1.3.0 */ -public class ResourceUtilsTest { +class ResourceUtilsTest { @Test - public void getResource () { + void getResource () { assertThat(ResourceUtils.getResource("/test.txt")) .isPresent() .hasValue("Hello world!\n"); } @Test - public void notExist () { + void notExist () { assertThat(ResourceUtils.getResource("/not-exist.txt")) .isNotPresent(); } @Test - public void getResourceUrls () { + void getResourceUrls () { List list = ResourceUtils.getResourceUrls("folder", "file-?.*") .stream() .map(ResourceUtils::getTextContent) diff --git a/src/test/java/io/appulse/utils/RoundRobinTest.java b/src/test/java/io/appulse/utils/RoundRobinTest.java index 295c3ef..a9cee19 100644 --- a/src/test/java/io/appulse/utils/RoundRobinTest.java +++ b/src/test/java/io/appulse/utils/RoundRobinTest.java @@ -18,16 +18,16 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * @author Artem Labazin * @since 1.8.0 */ -public class RoundRobinTest { +class RoundRobinTest { @Test - public void test () { + void test () { RoundRobin roundRobin = new RoundRobin<>("one", "two"); assertThat(roundRobin.getNext()).isEqualTo("one"); assertThat(roundRobin.getNext()).isEqualTo("two"); diff --git a/src/test/java/io/appulse/utils/SerializationUtilsTest.java b/src/test/java/io/appulse/utils/SerializationUtilsTest.java index 97dfa1c..d09ffab 100644 --- a/src/test/java/io/appulse/utils/SerializationUtilsTest.java +++ b/src/test/java/io/appulse/utils/SerializationUtilsTest.java @@ -28,16 +28,16 @@ import io.appulse.utils.exception.SerializationException; import lombok.val; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * * @author alabazin */ -public class SerializationUtilsTest { +class SerializationUtilsTest { @Test - public void testSerializeStream () throws Exception { + void testSerializeStream () throws Exception { HashMap map = new HashMap<>(2); map.put("foo", "foo"); map.put("bar", 7); @@ -59,7 +59,7 @@ public void testSerializeStream () throws Exception { } @Test - public void testSerializeStreamUnserializable () throws Exception { + void testSerializeStreamUnserializable () throws Exception { HashMap map = new HashMap<>(2); map.put("foo", "foo"); map.put("bar", 7); @@ -71,7 +71,7 @@ public void testSerializeStreamUnserializable () throws Exception { } @Test - public void testSerializeStreamNullObj () throws Exception { + void testSerializeStreamNullObj () throws Exception { val streamTest = new ByteArrayOutputStream(); SerializationUtils.serialize(null, streamTest); @@ -89,19 +89,19 @@ public void testSerializeStreamNullObj () throws Exception { } @Test - public void testSerializeStreamObjNull () throws Exception { + void testSerializeStreamObjNull () throws Exception { assertThatThrownBy(() -> SerializationUtils.serialize(new HashMap<>(), null)) .isExactlyInstanceOf(NullPointerException.class); } @Test - public void testSerializeStreamNullNull () throws Exception { + void testSerializeStreamNullNull () throws Exception { assertThatThrownBy(() -> SerializationUtils.serialize(null, null)) .isExactlyInstanceOf(NullPointerException.class); } @Test - public void testSerializeException () throws Exception { + void testSerializeException () throws Exception { val outputStream = new OutputStream() { @Override @@ -116,7 +116,7 @@ public void write (final int arg0) throws IOException { } @Test - public void testDeserializeBytes () throws Exception { + void testDeserializeBytes () throws Exception { HashMap map = new HashMap<>(2); map.put("foo", "foo"); map.put("bar", 7); @@ -143,7 +143,7 @@ public void testDeserializeBytes () throws Exception { } @Test - public void testDeserializeBytesOfNull () throws IOException { + void testDeserializeBytesOfNull () throws IOException { val byteArrayOutputStream = new ByteArrayOutputStream(); val objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(null); @@ -155,13 +155,13 @@ public void testDeserializeBytesOfNull () throws IOException { } @Test - public void testDeserializeBytesNull () { + void testDeserializeBytesNull () { assertThatThrownBy(() -> SerializationUtils.deserialize((byte[]) null)) .isExactlyInstanceOf(NullPointerException.class); } @Test - public void testDeserializeBytesBadStream () { + void testDeserializeBytesBadStream () { assertThatThrownBy(() -> SerializationUtils.deserialize(new byte[0])) .isExactlyInstanceOf(SerializationException.class); } diff --git a/src/test/java/io/appulse/utils/SocketUtilsTest.java b/src/test/java/io/appulse/utils/SocketUtilsTest.java index c43f74d..2f862c4 100644 --- a/src/test/java/io/appulse/utils/SocketUtilsTest.java +++ b/src/test/java/io/appulse/utils/SocketUtilsTest.java @@ -20,17 +20,17 @@ import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * * @author Artem Labazin * @since 1.2.0 */ -public class SocketUtilsTest { +class SocketUtilsTest { @Test - public void isPortAvailable () { + void isPortAvailable () { Optional port = SocketUtils.findFreePort(); assertThat(port).isPresent(); assertThat(SocketUtils.isPortAvailable(port.get())).isTrue(); diff --git a/src/test/java/io/appulse/utils/threads/AppulseThreadFactoryTest.java b/src/test/java/io/appulse/utils/threads/AppulseThreadFactoryTest.java index a539088..5a62ea6 100644 --- a/src/test/java/io/appulse/utils/threads/AppulseThreadFactoryTest.java +++ b/src/test/java/io/appulse/utils/threads/AppulseThreadFactoryTest.java @@ -22,17 +22,17 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ThreadFactory; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * * @author Artem Labazin * @since 1.5.0 */ -public class AppulseThreadFactoryTest { +class AppulseThreadFactoryTest { @Test - public void simpleName () throws Exception { + void simpleName () throws Exception { CompletableFuture future = new CompletableFuture<>(); AppulseThreadFactory.builder() @@ -46,7 +46,7 @@ public void simpleName () throws Exception { } @Test - public void nameWithCount () throws Exception { + void nameWithCount () throws Exception { ThreadFactory factory = AppulseThreadFactory.builder() .name("popa-%d") .build(); diff --git a/src/main/java/io/appulse/utils/test/TestMethodNamePrinter.java b/src/test/java/io/appulse/utils/threads/FutureUtilsTests.java similarity index 55% rename from src/main/java/io/appulse/utils/test/TestMethodNamePrinter.java rename to src/test/java/io/appulse/utils/threads/FutureUtilsTests.java index 5d02c54..50861d7 100644 --- a/src/main/java/io/appulse/utils/test/TestMethodNamePrinter.java +++ b/src/test/java/io/appulse/utils/threads/FutureUtilsTests.java @@ -14,26 +14,14 @@ * limitations under the License. */ -package io.appulse.utils.test; - -import lombok.val; - -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; +package io.appulse.utils.threads; /** * * @author Artem Labazin - * @since 1.5.0 + * @since 1.11.0 */ -@SuppressWarnings("PMD.SystemPrintln") -public class TestMethodNamePrinter extends TestWatcher { +public class FutureUtilsTests { + - @Override - protected void starting (Description description) { - val message = String.format("%nRUNNING TEST: %s.%s%n", - description.getClassName(), - description.getMethodName()); - System.out.println(message); - } } diff --git a/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java b/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java index c7de2e4..5f5bb3f 100644 --- a/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java +++ b/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java @@ -27,23 +27,23 @@ import ch.qos.logback.classic.spi.ILoggingEvent; import lombok.val; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * * @author Artem Labazin * @since 1.5.0 */ -public class ExecutorServiceWithClientTraceTest { +class ExecutorServiceWithClientTraceTest { - @Before - public void before () { + @BeforeEach + void before () { TestAppender.EVENTS.clear(); } @Test - public void test () throws InterruptedException { + void test () throws InterruptedException { ExecutorService service = AppulseExecutors.newSingleThreadExecutor() .enableClientTrace() .build(); diff --git a/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitorTest.java b/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitorTest.java index afd0ea1..d5f8d1a 100644 --- a/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitorTest.java +++ b/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitorTest.java @@ -28,23 +28,24 @@ import ch.qos.logback.classic.spi.ILoggingEvent; import lombok.val; -import org.junit.Before; -import org.junit.Test; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * * @author Artem Labazin * @since 1.5.0 */ -public class ExecutorServiceWithTimeMonitorTest { +class ExecutorServiceWithTimeMonitorTest { - @Before - public void before () { + @BeforeEach + void before () { TestAppender.EVENTS.clear(); } @Test - public void monitor () throws Exception { + void monitor () throws Exception { ExecutorService service = AppulseExecutors.newSingleThreadExecutor() .enableTimeLogging() .build(); From 7a155885c9d89457b10ee07f11c8a4bb0dfd3909 Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Thu, 14 Feb 2019 10:43:27 +0300 Subject: [PATCH 15/58] Add future utility class --- .../io/appulse/utils/threads/FutureUtils.java | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/main/java/io/appulse/utils/threads/FutureUtils.java diff --git a/src/main/java/io/appulse/utils/threads/FutureUtils.java b/src/main/java/io/appulse/utils/threads/FutureUtils.java new file mode 100644 index 0000000..1be12ab --- /dev/null +++ b/src/main/java/io/appulse/utils/threads/FutureUtils.java @@ -0,0 +1,94 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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.appulse.utils.threads; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import lombok.NonNull; +import lombok.val; + +/** + * Different future helpers. + * + * @author Artem Labazin + * @since 1.11.0 + */ +public final class FutureUtils { + + /** + * Creates {@link CompletableFuture} instance and completes it with specified exception. + * + * @param throwable the exception + * + * @return completed exceptionally {@link CompletableFuture} instance. + */ + public static CompletableFuture completedExceptionally (Throwable throwable) { + val future = new CompletableFuture(); + future.completeExceptionally(throwable); + return future; + } + + /** + * Returns first completed future, which didn't throw an exception. + * + * @param futures array of futures. + * + * @return first non-exceptional completed future. + */ + public static CompletableFuture firstCompletedWithoutException (@NonNull CompletionStage... futures) { + val stream = Stream.of(futures); + return firstCompletedWithoutException(stream); + } + + /** + * Returns first completed future, which didn't throw an exception. + * + * @param futures list of futures. + * + * @return first non-exceptional completed future. + */ + public static CompletableFuture firstCompletedWithoutException (@NonNull List> futures) { + val stream = futures.stream(); + return firstCompletedWithoutException(stream); + } + + // https://stackoverflow.com/a/34163913 + private static CompletableFuture firstCompletedWithoutException (Stream> stream) { + val result = new CompletableFuture(); + val complete = (Consumer) result::complete; + + val futures = stream + .map(it -> it.thenAccept(complete)) + .toArray(CompletableFuture[]::new); + + CompletableFuture.allOf(futures) + .exceptionally(ex -> { + result.completeExceptionally(ex); + return null; + }); + + return result; + } + + private FutureUtils () { + throw new UnsupportedOperationException(); + } +} From f5aed35e10e3fda007673e207faeb6aab2d59207 Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Thu, 14 Feb 2019 10:43:37 +0300 Subject: [PATCH 16/58] Add tests for future utility class --- .../utils/threads/FutureUtilsTests.java | 79 ++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/src/test/java/io/appulse/utils/threads/FutureUtilsTests.java b/src/test/java/io/appulse/utils/threads/FutureUtilsTests.java index 50861d7..945d66b 100644 --- a/src/test/java/io/appulse/utils/threads/FutureUtilsTests.java +++ b/src/test/java/io/appulse/utils/threads/FutureUtilsTests.java @@ -16,12 +16,89 @@ package io.appulse.utils.threads; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.locks.LockSupport; + +import lombok.SneakyThrows; +import lombok.val; +import org.junit.jupiter.api.Test; + /** * * @author Artem Labazin * @since 1.11.0 */ -public class FutureUtilsTests { +class FutureUtilsTests { + + @Test + void completedExceptionally () { + val future = FutureUtils.completedExceptionally(new RuntimeException()); + + assertThat(future) + .isCompletedExceptionally(); + + assertThatThrownBy(() -> future.get()) + .isInstanceOf(ExecutionException.class) + .hasCauseInstanceOf(RuntimeException.class); + } + + @Test + @SneakyThrows + void firstCompletedWithoutException1 () { + List> futures = Arrays.asList( + CompletableFuture.supplyAsync(() -> { + throw new RuntimeException("failing immediately"); + }), + CompletableFuture.supplyAsync(() -> { + // delayed to demonstrate that the solution will wait for all completions + // to ensure it doesn't miss a possible successful computation + LockSupport.parkNanos(SECONDS.toNanos(5)); + throw new RuntimeException("failing later"); + }) + ); + + CompletableFuture result = FutureUtils.firstCompletedWithoutException(futures); + + SECONDS.sleep(6); + + assertThat(result) + .isCompletedExceptionally(); + + assertThatThrownBy(() -> result.get()) + .isInstanceOf(ExecutionException.class) + .hasCauseInstanceOf(RuntimeException.class) + .hasMessage("java.lang.RuntimeException: failing immediately"); + } + + @Test + @SneakyThrows + void firstCompletedWithoutException2 () { + List> futures = Arrays.asList( + CompletableFuture.supplyAsync(() -> { + LockSupport.parkNanos(SECONDS.toNanos(10)); + return "with 10s delay"; + }), + CompletableFuture.supplyAsync(() -> { + throw new RuntimeException("failing immediately"); } + ), + CompletableFuture.supplyAsync(() -> { + LockSupport.parkNanos(SECONDS.toNanos(5)); + return "with 5s delay"; + }) + ); + + CompletableFuture result = FutureUtils.firstCompletedWithoutException(futures); + SECONDS.sleep(6); + assertThat(result) + .isCompletedWithValue("with 5s delay"); + } } From 9cf7362e19aab8706722587e61801575b12efb3c Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Thu, 14 Feb 2019 10:46:03 +0300 Subject: [PATCH 17/58] Add changelog's record --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e1ef7d..4a27ce2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add more tests. - Add `JavaDoc`. +## [1.11.0](https://github.com/appulse-projects/utils-java/releases/tag/1.11.0) - 2019-02-14 + +### Added + +- [FutureUtils](./src/main/java/io/appulse/utils/threads/FutureUtils.java) helper class; +- [Tests](./src/test/java/io/appulse/utils/threads/FutureUtilsTests.java) for `FutureUtils`. + +### Changed + +- Updated `pom` dependencies; +- Fixed copyright year. + ## [1.10.0](https://github.com/appulse-projects/utils-java/releases/tag/1.10.0) - 2018-09-25 ### Added From 6d561aba09a9c8e04ef012729e34a062eca12bf1 Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Sat, 16 Feb 2019 19:07:59 +0300 Subject: [PATCH 18/58] Add future wrapper --- .codestyle/checkstyle.xml | 2 +- .codestyle/findbugs.xml | 2 +- .codestyle/license_for_check.txt | 2 +- .codestyle/pmd.xml | 2 +- .settings.xml | 2 +- CHANGELOG.md | 12 ++++ CONTRIBUTING.md | 2 +- README.md | 2 +- pom.xml | 8 +-- .../io/appulse/utils/AnnotationUtils.java | 2 +- src/main/java/io/appulse/utils/Bytes.java | 2 +- .../io/appulse/utils/BytesDelegateGets.java | 2 +- .../io/appulse/utils/BytesDelegatePuts.java | 2 +- .../java/io/appulse/utils/BytesUtils.java | 2 +- .../java/io/appulse/utils/ExceptionUtils.java | 2 +- .../io/appulse/utils/ReflectionUtils.java | 2 +- .../java/io/appulse/utils/ResourceUtils.java | 2 +- .../java/io/appulse/utils/RoundRobin.java | 2 +- .../io/appulse/utils/SerializationUtils.java | 2 +- .../java/io/appulse/utils/SocketUtils.java | 2 +- .../io/appulse/utils/cache/FifoCache.java | 2 +- .../java/io/appulse/utils/cache/LruCache.java | 2 +- .../exception/SerializationException.java | 2 +- .../io/appulse/utils/test/TestAppender.java | 2 +- .../utils/threads/AppulseExecutors.java | 2 +- .../utils/threads/AppulseThreadFactory.java | 2 +- .../utils/threads/CompletablePromise.java | 64 +++++++++++++++++++ .../threads/CompletablePromiseContext.java | 52 +++++++++++++++ .../io/appulse/utils/threads/FutureUtils.java | 14 +++- .../ExecutorServiceWithClientTrace.java | 2 +- .../ExecutorServiceWithTimeMonitor.java | 2 +- .../executor/ExecutorServiceWrapper.java | 2 +- ...heduledExecutorServiceWithClientTrace.java | 2 +- .../ScheduledExecutorServiceWrapper.java | 2 +- .../builder/ExecutorServiceBuilder.java | 34 +++++----- .../executor/builder/ForkJoinPoolBuilder.java | 2 +- .../ScheduledExecutorServiceBuilder.java | 2 +- .../io/appulse/utils/AnnotationUtilsTest.java | 2 +- src/test/java/io/appulse/utils/BytesTest.java | 2 +- .../java/io/appulse/utils/BytesUtilsTest.java | 2 +- .../io/appulse/utils/ExceptionUtilsTest.java | 2 +- .../io/appulse/utils/ReflectionUtilsTest.java | 2 +- .../io/appulse/utils/ResourceUtilsTest.java | 2 +- .../java/io/appulse/utils/RoundRobinTest.java | 2 +- .../appulse/utils/SerializationUtilsTest.java | 2 +- .../io/appulse/utils/SocketUtilsTest.java | 2 +- .../threads/AppulseThreadFactoryTest.java | 2 +- .../utils/threads/FutureUtilsTests.java | 2 +- .../ExecutorServiceWithClientTraceTest.java | 2 +- .../ExecutorServiceWithTimeMonitorTest.java | 2 +- src/test/resources/logback-test.xml | 2 +- 51 files changed, 206 insertions(+), 68 deletions(-) create mode 100644 src/main/java/io/appulse/utils/threads/CompletablePromise.java create mode 100644 src/main/java/io/appulse/utils/threads/CompletablePromiseContext.java diff --git a/.codestyle/checkstyle.xml b/.codestyle/checkstyle.xml index bb32d79..1724924 100644 --- a/.codestyle/checkstyle.xml +++ b/.codestyle/checkstyle.xml @@ -4,7 +4,7 @@ "http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd"> - + @@ -183,9 +185,6 @@ limitations under the License. - - - @@ -234,7 +233,7 @@ limitations under the License. + value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LE, LITERAL_INSTANCEOF, LT, MINUS, MOD, NOT_EQUAL, QUESTION, SL, SR, STAR"/> @@ -347,7 +346,6 @@ limitations under the License. - @@ -379,11 +377,10 @@ limitations under the License. - + - diff --git a/.codestyle/pmd.xml b/.codestyle/pmd.xml index b6baa55..0e7caf8 100644 --- a/.codestyle/pmd.xml +++ b/.codestyle/pmd.xml @@ -24,11 +24,16 @@ limitations under the License. PMD Rules + + + + + @@ -36,6 +41,7 @@ limitations under the License. + @@ -46,10 +52,12 @@ limitations under the License. + + @@ -63,14 +71,18 @@ limitations under the License. - + + + - + + + diff --git a/CHANGELOG.md b/CHANGELOG.md index 8103c72..f16c3e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add more tests. - Add `JavaDoc`. +## [1.17.0](https://github.com/appulse-projects/utils-java/releases/tag/1.17.0) - 2019-12-09 + +### Added + +- `BytesInputStream` implementation of `InputStream` with `Bytes` internal; +- `BytesOutputStream` implementation of `OutputStream` with `Bytes` internal. + +### Changed + +- Updated plugins; +- Updated `pmd` and `checkstyle` rules; +- Correct *Javadoc*s. + ## [1.16.4](https://github.com/appulse-projects/utils-java/releases/tag/1.16.4) - 2019-12-05 ### Changed diff --git a/pom.xml b/pom.xml index a445fb6..6b6bfca 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ limitations under the License. io.appulse utils-java - 1.16.4 + 1.17.0 jar @@ -66,7 +66,7 @@ limitations under the License. https://github.com/appulse-projects/utils-java scm:git:https://github.com/appulse-projects/utils-java.git scm:git:https://github.com/appulse-projects/utils-java.git - 1.16.4 + 1.17.0 @@ -194,13 +194,14 @@ limitations under the License. pl.project13.maven git-commit-id-plugin - 3.0.0 + 4.0.0 - git-infos + get-the-git-infos revision + initialize @@ -224,7 +225,7 @@ limitations under the License. org.apache.maven.plugins maven-javadoc-plugin - 3.1.0 + 3.1.1 -Xdoclint:none -Xdoclint:none @@ -301,7 +302,7 @@ limitations under the License. com.github.spotbugs spotbugs-maven-plugin - 3.1.11 + 3.1.12.2 Max Low @@ -353,7 +354,7 @@ limitations under the License. com.puppycrawl.tools checkstyle - 8.21 + 8.24 diff --git a/src/main/java/io/appulse/utils/AnnotationUtils.java b/src/main/java/io/appulse/utils/AnnotationUtils.java index fc9fcc2..87ae0de 100644 --- a/src/main/java/io/appulse/utils/AnnotationUtils.java +++ b/src/main/java/io/appulse/utils/AnnotationUtils.java @@ -31,8 +31,8 @@ /** * Different annotation helpers. * - * @author Artem Labazin * @since 1.7.0 + * @author Artem Labazin */ public final class AnnotationUtils { @@ -62,6 +62,8 @@ public final class AnnotationUtils { * * @param annotationType the annotation type to look for, both locally and as a meta-annotation * + * @param the annotation type. + * * @return the first matching annotation * * @since 1.7.0 @@ -89,6 +91,8 @@ public static Optional findAnnotation (Class clazz, * * @param annotationType the annotation type to look for, both locally and as a meta-annotation * + * @param the annotation type. + * * @return the first matching annotation * * @since 1.7.0 @@ -118,6 +122,8 @@ public static Optional findAnnotation (AnnotatedElemen * * @param annotationType the annotation type to look for * + * @param the annotation type. + * * @return the first matching annotation * * @since 1.7.0 @@ -141,7 +147,8 @@ public static boolean isInJavaLangAnnotationPackage (Annotation annotation) { } /** - * Determine if the {@link Annotation} with the supplied name is defined in the core JDK {@code java.lang.annotation} package. + * Determine if the {@link Annotation} with the supplied name is defined in + * the core JDK {@code java.lang.annotation} package. * * @param annotationType the annotation type to check * @@ -154,7 +161,8 @@ public static boolean isInJavaLangAnnotationPackage (Class } /** - * Determine if the {@link Annotation} with the supplied name is defined in the core JDK {@code java.lang.annotation} package. + * Determine if the {@link Annotation} with the supplied name is defined in + * the core JDK {@code java.lang.annotation} package. * * @param annotationType the name of the annotation type to check * diff --git a/src/main/java/io/appulse/utils/Bytes.java b/src/main/java/io/appulse/utils/Bytes.java index 182ac89..f3578e2 100644 --- a/src/main/java/io/appulse/utils/Bytes.java +++ b/src/main/java/io/appulse/utils/Bytes.java @@ -24,8 +24,8 @@ * This interface provides an abstract view for a primitive byte * arrays ({@code byte[]}). * - * @author Artem Labazin * @since 1.12.0 + * @author Artem Labazin */ @SuppressWarnings({ "PMD.ExcessiveClassLength", @@ -90,7 +90,9 @@ static Bytes copy (ByteBuffer buffer) { } /** - * Create a new {@link Bytes} instance with a fixed size content + * Create a new {@link Bytes} instance with a fixed size content. + * + * @param size the size of a new buffer. * * @return the new {@link Bytes} instance */ @@ -1638,6 +1640,8 @@ static Bytes resizableArray (int initialSize) { /** * Returns the number of bytes (octets) this buffer can contain. + * + * @return the number of bytes. */ int capacity (); @@ -1766,7 +1770,7 @@ static Bytes resizableArray (int initialSize) { /** * Returns the copy of range the buffer's back byte array from - * 0 till writeIndex. + * 0 till writeIndex. *

* Modifications to this buffer's content may NOT cause the * returned array's content to be modified, and vice versa. diff --git a/src/main/java/io/appulse/utils/BytesInputStream.java b/src/main/java/io/appulse/utils/BytesInputStream.java new file mode 100644 index 0000000..73b5b24 --- /dev/null +++ b/src/main/java/io/appulse/utils/BytesInputStream.java @@ -0,0 +1,143 @@ +/* + * Copyright 2019 the original author or authors. + * + * 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.appulse.utils; + +import static lombok.AccessLevel.PRIVATE; + +import java.io.IOException; +import java.io.InputStream; + +import lombok.NonNull; +import lombok.experimental.FieldDefaults; +import lombok.val; + +/** + * A {@code BytesInputStream} contains + * an internal buffer that contains bytes that + * may be read from the stream. An internal + * counter keeps track of the next byte to + * be supplied by the {@code read} method. + *

+ * Closing a {@code BytesInputStream} has no effect. The methods in + * this class can be called after the stream has been closed without + * generating an {@code IOException}. + * + * @since 1.17.0 + * @author Artem Labazin + */ +@FieldDefaults(level = PRIVATE) +public class BytesInputStream extends InputStream { + + Bytes buffer; + + int mark; + + /** + * Creates a BytesInputStream + * so that it uses bytes as its + * buffer array. + * The buffer array is not copied. + * + * @param bytes the input buffer. + */ + public BytesInputStream (byte[] bytes) { + super(); + buffer = Bytes.wrap(bytes); + } + + /** + * Creates a BytesInputStream + * so that it uses bytes as its + * buffer array. + * The buffer array is not copied. + * + * @param bytes the input buffer. + */ + public BytesInputStream (Bytes bytes) { + super(); + buffer = bytes; + } + + /** + * Creates ByteArrayInputStream + * that uses buf as its + * buffer array. The initial value of pos + * is offset and the initial value + * of count is the minimum of offset+length + * and buf.length. + * The buffer array is not copied. The buffer's mark is + * set to the specified offset. + * + * @param bytes the input buffer. + * @param offset the offset in the buffer of the first byte to read. + * @param length the maximum number of bytes to read from the buffer. + */ + public BytesInputStream (byte[] bytes, int offset, int length) { + super(); + buffer = Bytes.wrap(bytes); + buffer.readerIndex(offset); + buffer.writerIndex(length); + } + + @Override + public synchronized int read () throws IOException { + return buffer.isReadable() + ? buffer.readUnsignedByte() + : -1; + } + + @Override + public synchronized int read (@NonNull byte[] bytes, int offset, int length) { + val readerIndex = buffer.readerIndex(); + buffer.readBytes(bytes, offset, length); + return buffer.readerIndex() - readerIndex; + } + + @Override + public synchronized long skip (long skipBytes) { + val readerIndex = buffer.readerIndex(); + val readableBytes = buffer.readableBytes(); + val skip = (int) Math.min(readableBytes, skipBytes); + buffer.readerIndex(readerIndex + skip); + return skip; + } + + @Override + public synchronized int available () { + return buffer.readableBytes(); + } + + @Override + public boolean markSupported () { + return true; + } + + @Override + public synchronized void mark (int readAheadLimit) { + mark = buffer.readerIndex(); + } + + @Override + public synchronized void reset () { + buffer.readerIndex(mark); + } + + @Override + public void close () { + // no op + } +} diff --git a/src/main/java/io/appulse/utils/BytesOutputStream.java b/src/main/java/io/appulse/utils/BytesOutputStream.java new file mode 100644 index 0000000..eb24a73 --- /dev/null +++ b/src/main/java/io/appulse/utils/BytesOutputStream.java @@ -0,0 +1,124 @@ +/* + * Copyright 2019 the original author or authors. + * + * 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.appulse.utils; + +import static lombok.AccessLevel.PRIVATE; + +import java.io.IOException; +import java.io.OutputStream; + +import lombok.experimental.FieldDefaults; + +/** + * This class implements an output stream in which the data is + * written into a Bytes. The buffer automatically grows as data + * is written to it. + * The data can be retrieved using toByteArray() and + * array(). + *

+ * Closing a BytesOutputStream has no effect. The methods in + * this class can be called after the stream has been closed without + * generating an IOException. + * + * @since 1.17.0 + * @author Artem Labazin + */ +@FieldDefaults(level = PRIVATE, makeFinal = true) +public class BytesOutputStream extends OutputStream { + + Bytes buffer; + + /** + * Creates a new byte array output stream. The buffer capacity is + * initially 32 bytes, though its size increases if necessary. + */ + public BytesOutputStream () { + this(32); + } + + /** + * Creates a new byte array output stream, with a buffer capacity of + * the specified size, in bytes. + * + * @param size the initial size. + * @exception IllegalArgumentException if size is negative. + */ + public BytesOutputStream (int size) { + super(); + if (size < 0) { + throw new IllegalArgumentException("Negative initial size: " + size); + } + buffer = Bytes.resizableArray(size); + } + + @Override + public synchronized void write (int value) throws IOException { + buffer.write1B(value); + } + + @Override + public synchronized void write (byte[] bytes, int offset, int length) { + buffer.writeNB(bytes, offset, length); + } + + /** + * Resets the byte array output stream to zero, so that all currently + * accumulated output in the output stream is discarded. The output + * stream can be used again, reusing the already allocated buffer space. + */ + public synchronized void reset () { + buffer.reset(); + } + + /** + * Returns the current size of the buffer. + * + * @return the number of valid bytes in this output stream. + */ + public synchronized int size () { + return buffer.writerIndex(); + } + + /** + * Creates a newly allocated byte array. Its size is the current + * size of this output stream and the valid contents of the buffer + * have been copied into it. + * + * @return the current contents of this output stream, as a byte array. + * @see java.io.ByteArrayOutputStream#size() + */ + public synchronized byte[] toByteArray () { + return buffer.arrayCopy(); + } + + /** + * Returns the byte array that backs this buffer. + *

+ * Modifications to this buffer's content may cause the + * returned array's content to be modified, and vice versa. + * + * @return the array that backs this buffer + */ + public byte[] array () { + return buffer.array(); + } + + @Override + public void close () { + // no op + } +} diff --git a/src/main/java/io/appulse/utils/BytesPool.java b/src/main/java/io/appulse/utils/BytesPool.java index 6eb3d81..27e9bfa 100644 --- a/src/main/java/io/appulse/utils/BytesPool.java +++ b/src/main/java/io/appulse/utils/BytesPool.java @@ -40,8 +40,8 @@ /** * The customisable {@link Bytes} pool. * - * @author Artem Labazin * @since 1.15.0 + * @author Artem Labazin */ @FieldDefaults(level = PRIVATE, makeFinal = true) public class BytesPool implements AutoCloseable { diff --git a/src/main/java/io/appulse/utils/BytesUtils.java b/src/main/java/io/appulse/utils/BytesUtils.java index c8d3df0..2d9fd4b 100644 --- a/src/main/java/io/appulse/utils/BytesUtils.java +++ b/src/main/java/io/appulse/utils/BytesUtils.java @@ -27,9 +27,10 @@ import lombok.val; /** + * Different methods for working with bytes. * - * @author Artem Labazin * @since 1.3.0 + * @author Artem Labazin */ @SuppressWarnings({ "PMD.ExcessiveClassLength", diff --git a/src/main/java/io/appulse/utils/ExceptionUtils.java b/src/main/java/io/appulse/utils/ExceptionUtils.java index 704bbaa..45cab51 100644 --- a/src/main/java/io/appulse/utils/ExceptionUtils.java +++ b/src/main/java/io/appulse/utils/ExceptionUtils.java @@ -19,8 +19,8 @@ /** * Different exception helpers. * - * @author Artem Labazin * @since 1.6.0 + * @author Artem Labazin */ public final class ExceptionUtils { diff --git a/src/main/java/io/appulse/utils/HexUtil.java b/src/main/java/io/appulse/utils/HexUtil.java index a6bc0cd..08b1424 100644 --- a/src/main/java/io/appulse/utils/HexUtil.java +++ b/src/main/java/io/appulse/utils/HexUtil.java @@ -28,8 +28,8 @@ /** * The set of different HEX helper funtions. * - * @author Artem Labazin * @since 1.16.0 + * @author Artem Labazin */ public final class HexUtil { @@ -197,7 +197,10 @@ public static String prettyHexDump (@NonNull Bytes buffer, int offset, int lengt } result.append(NEW_LINE) - .append('|').append(String.format(ENGLISH, "%07x0", row)).append('|').append(hexDump).append('|').append(asciiDump).append('|'); + .append('|').append(String.format(ENGLISH, "%07x0", row)) + .append('|').append(hexDump) + .append('|').append(asciiDump) + .append('|'); } return result.append(NEW_LINE) diff --git a/src/main/java/io/appulse/utils/LimitedQueue.java b/src/main/java/io/appulse/utils/LimitedQueue.java index a0d0cab..0bef7fc 100644 --- a/src/main/java/io/appulse/utils/LimitedQueue.java +++ b/src/main/java/io/appulse/utils/LimitedQueue.java @@ -24,8 +24,10 @@ /** * Just a regular {@link LinkedList}, but with limited capacity. * - * @author Artem Labazin + * @param the list's element type. + * * @since 1.15.0 + * @author Artem Labazin */ @Value @EqualsAndHashCode(callSuper = true) diff --git a/src/main/java/io/appulse/utils/ReadBytesUtils.java b/src/main/java/io/appulse/utils/ReadBytesUtils.java index f25ba78..642e35c 100644 --- a/src/main/java/io/appulse/utils/ReadBytesUtils.java +++ b/src/main/java/io/appulse/utils/ReadBytesUtils.java @@ -33,8 +33,8 @@ /** * The helper methods for reading different streams/channels/files to buffers. * - * @author Artem Labazin * @since 1.14.0 + * @author Artem Labazin */ public final class ReadBytesUtils { diff --git a/src/main/java/io/appulse/utils/ReflectionUtils.java b/src/main/java/io/appulse/utils/ReflectionUtils.java index b2cb0f6..9c022d5 100644 --- a/src/main/java/io/appulse/utils/ReflectionUtils.java +++ b/src/main/java/io/appulse/utils/ReflectionUtils.java @@ -33,8 +33,8 @@ /** * Different reflection helpers. * - * @author Artem Labazin * @since 1.0.1 + * @author Artem Labazin */ public final class ReflectionUtils { diff --git a/src/main/java/io/appulse/utils/ResourceUtils.java b/src/main/java/io/appulse/utils/ResourceUtils.java index 1be921e..2ee8705 100644 --- a/src/main/java/io/appulse/utils/ResourceUtils.java +++ b/src/main/java/io/appulse/utils/ResourceUtils.java @@ -42,9 +42,10 @@ import lombok.val; /** + * The set of helper methods for working with classpath resources. * - * @author Artem Labazin * @since 1.3.0 + * @author Artem Labazin */ public final class ResourceUtils { diff --git a/src/main/java/io/appulse/utils/RoundRobin.java b/src/main/java/io/appulse/utils/RoundRobin.java index 7ed2ccb..ab7b469 100644 --- a/src/main/java/io/appulse/utils/RoundRobin.java +++ b/src/main/java/io/appulse/utils/RoundRobin.java @@ -30,8 +30,10 @@ /** * Round robin collection wrapper. * - * @author Artem Labazin + * @param the type of the selecting objects. + * * @since 1.8.0 + * @author Artem Labazin */ @FieldDefaults(level = PRIVATE) public final class RoundRobin { @@ -40,6 +42,7 @@ public final class RoundRobin { final T[] elements; + @SuppressWarnings("PMD.AvoidUsingVolatile") volatile int size; @SuppressWarnings("unchecked") diff --git a/src/main/java/io/appulse/utils/SerializationUtils.java b/src/main/java/io/appulse/utils/SerializationUtils.java index 360433a..dd9b394 100644 --- a/src/main/java/io/appulse/utils/SerializationUtils.java +++ b/src/main/java/io/appulse/utils/SerializationUtils.java @@ -33,8 +33,8 @@ /** * Different serialization helpers. * - * @author Artem Labazin * @since 1.8.0 + * @author Artem Labazin */ public final class SerializationUtils { diff --git a/src/main/java/io/appulse/utils/SizeUnit.java b/src/main/java/io/appulse/utils/SizeUnit.java index fbef23f..efa886d 100644 --- a/src/main/java/io/appulse/utils/SizeUnit.java +++ b/src/main/java/io/appulse/utils/SizeUnit.java @@ -21,11 +21,14 @@ * unit of granularity and provides utility methods to convert across * the units. * - * @author Artem Labazin * @since 1.13.0 + * @author Artem Labazin */ public enum SizeUnit { + /** + * Byte (B), 1 Byte. + */ BYTES { public long toBytes (long value) { @@ -57,6 +60,9 @@ public long convert (long value, SizeUnit unit) { } }, + /** + * Kilobyte (kB), 2^10 Byte = 1.024 Byte. + */ KILOBYTES { public long toBytes (long value) { @@ -88,6 +94,9 @@ public long convert (long value, SizeUnit unit) { } }, + /** + * Megabyte (MB), 2^20 Byte = 1.024 * 1.024 Byte = 1.048.576 Byte. + */ MEGABYTES { public long toBytes (long value) { @@ -119,6 +128,10 @@ public long convert (long value, SizeUnit unit) { } }, + /** + * Gigabyte (GB), + * 2^30 Byte = 1.024 * 1.024 * 1.024 Byte = 1.073.741.824 Byte. + */ GIGABYTES { public long toBytes (long value) { @@ -150,6 +163,10 @@ public long convert (long value, SizeUnit unit) { } }, + /** + * Terabyte (TB), + * 2^40 Byte = 1.024 * 1.024 * 1.024 * 1.024 Byte = 1.099.511.627.776 Byte. + */ TERABYTES { public long toBytes (long value) { @@ -181,6 +198,10 @@ public long convert (long value, SizeUnit unit) { } }, + /** + * Petabyte (PB), + * 2^50 Byte = 1.024 * 1.024 * 1.024 * 1.024 * 1.024 Byte = 1.125.899.906.842.624 Byte. + */ PETABYTES { public long toBytes (long value) { @@ -235,30 +256,80 @@ static long scale (long d, long m, long over) { return d * m; } + /** + * Converts a {@code source} value with a specified {@link SizeUnit} to that instance. + * + * @param source the value to convert. + * @param sourceUnit the value's size unit. + * + * @return converted value. + */ public long convert (long source, SizeUnit sourceUnit) { throw new AbstractMethodError(); } + /** + * Translates a value to bytes. + * + * @param value the value to convert. + * + * @return converted value, in bytes. + */ public long toBytes (long value) { throw new AbstractMethodError(); } + /** + * Translates a value to kilobytes. + * + * @param value the value to convert. + * + * @return converted value, in kilobytes. + */ public long toKilobytes (long value) { throw new AbstractMethodError(); } + /** + * Translates a value to megabytes. + * + * @param value the value to convert. + * + * @return converted value, in megabytes. + */ public long toMegabytes (long value) { throw new AbstractMethodError(); } + /** + * Translates a value to gigabytes. + * + * @param value the value to convert. + * + * @return converted value, in gigabytes. + */ public long toGigabytes (long value) { throw new AbstractMethodError(); } + /** + * Translates a value to terabytes. + * + * @param value the value to convert. + * + * @return converted value, in terabytes. + */ public long toTerabytes (long value) { throw new AbstractMethodError(); } + /** + * Translates a value to petabytes. + * + * @param value the value to convert. + * + * @return converted value, in petabytes. + */ public long toPetabytes (long value) { throw new AbstractMethodError(); } diff --git a/src/main/java/io/appulse/utils/SocketUtils.java b/src/main/java/io/appulse/utils/SocketUtils.java index 70f42a9..f61c797 100644 --- a/src/main/java/io/appulse/utils/SocketUtils.java +++ b/src/main/java/io/appulse/utils/SocketUtils.java @@ -29,9 +29,10 @@ import lombok.SneakyThrows; /** + * The utility class for working with TCP connections. * - * @author Artem Labazin * @since 1.2.0 + * @author Artem Labazin */ public final class SocketUtils { diff --git a/src/main/java/io/appulse/utils/WriteBytesUtils.java b/src/main/java/io/appulse/utils/WriteBytesUtils.java index da8c783..9dec61e 100644 --- a/src/main/java/io/appulse/utils/WriteBytesUtils.java +++ b/src/main/java/io/appulse/utils/WriteBytesUtils.java @@ -34,8 +34,8 @@ /** * The helper methods for writing the data to different streams/channels/files. * - * @author Artem Labazin * @since 1.14.0 + * @author Artem Labazin */ public final class WriteBytesUtils { diff --git a/src/main/java/io/appulse/utils/cache/FifoCache.java b/src/main/java/io/appulse/utils/cache/FifoCache.java index 614d4ac..d66fa0f 100644 --- a/src/main/java/io/appulse/utils/cache/FifoCache.java +++ b/src/main/java/io/appulse/utils/cache/FifoCache.java @@ -27,8 +27,11 @@ /** * FIFO cache implementation based on {@code LinkedHashMap}. * - * @author Artem Labazin + * @param the cache's key + * @param the value type of the cache + * * @since 1.10.0 + * @author Artem Labazin */ @FieldDefaults(level = PRIVATE, makeFinal = true) public class FifoCache extends LinkedHashMap { diff --git a/src/main/java/io/appulse/utils/cache/LruCache.java b/src/main/java/io/appulse/utils/cache/LruCache.java index 1d3e85f..a019681 100644 --- a/src/main/java/io/appulse/utils/cache/LruCache.java +++ b/src/main/java/io/appulse/utils/cache/LruCache.java @@ -27,8 +27,11 @@ /** * LRU cache implementation based on {@code LinkedHashMap}. * - * @author Artem Labazin + * @param the cache's key + * @param the value type of the cache + * * @since 1.9.0 + * @author Artem Labazin */ @FieldDefaults(level = PRIVATE, makeFinal = true) public class LruCache extends LinkedHashMap { diff --git a/src/main/java/io/appulse/utils/exception/SerializationException.java b/src/main/java/io/appulse/utils/exception/SerializationException.java index 5a7fe93..f1bafba 100644 --- a/src/main/java/io/appulse/utils/exception/SerializationException.java +++ b/src/main/java/io/appulse/utils/exception/SerializationException.java @@ -23,30 +23,34 @@ *

* #NotThreadSafe# because Throwable is not thread-safe. * - * @author Artem Labazin * @since 1.8.0 + * @author Artem Labazin */ public class SerializationException extends RuntimeException { private static final long serialVersionUID = 8179675064137603549L; - public SerializationException() { + public SerializationException () { super(); } - public SerializationException(String message) { + public SerializationException (String message) { super(message); } - public SerializationException(String message, Throwable cause) { + public SerializationException (String message, Throwable cause) { super(message, cause); } - public SerializationException(Throwable cause) { + public SerializationException (Throwable cause) { super(cause); } - public SerializationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + public SerializationException (String message, + Throwable cause, + boolean enableSuppression, + boolean writableStackTrace + ) { super(message, cause, enableSuppression, writableStackTrace); } } diff --git a/src/main/java/io/appulse/utils/test/TestAppender.java b/src/main/java/io/appulse/utils/test/TestAppender.java index b3db3b8..91c8497 100644 --- a/src/main/java/io/appulse/utils/test/TestAppender.java +++ b/src/main/java/io/appulse/utils/test/TestAppender.java @@ -24,13 +24,17 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; /** + * Logging catcher helper class. * - * @author Artem Labazin * @since 1.5.0 + * @author Artem Labazin */ @SuppressFBWarnings("MS_MUTABLE_COLLECTION_PKGPROTECT") public class TestAppender extends AppenderBase { + /** + * The collected logging events. + */ public static final List EVENTS = new LinkedList<>(); @Override diff --git a/src/main/java/io/appulse/utils/threads/AppulseExecutors.java b/src/main/java/io/appulse/utils/threads/AppulseExecutors.java index 7b4fcf4..7c05334 100644 --- a/src/main/java/io/appulse/utils/threads/AppulseExecutors.java +++ b/src/main/java/io/appulse/utils/threads/AppulseExecutors.java @@ -28,9 +28,10 @@ import io.appulse.utils.threads.executor.builder.ScheduledExecutorServiceBuilder; /** + * The {@link ExecutorService} implementation with fancy builder. * - * @author Artem Labazin * @since 1.5.0 + * @author Artem Labazin */ @SuppressWarnings("PMD.ClassNamingConventions") public final class AppulseExecutors { diff --git a/src/main/java/io/appulse/utils/threads/AppulseThreadFactory.java b/src/main/java/io/appulse/utils/threads/AppulseThreadFactory.java index 8c69e90..1152c26 100644 --- a/src/main/java/io/appulse/utils/threads/AppulseThreadFactory.java +++ b/src/main/java/io/appulse/utils/threads/AppulseThreadFactory.java @@ -33,9 +33,10 @@ import lombok.val; /** + * The {@link ThreadFactory} custom implementation, which adds fancy builder. * - * @author Artem Labazin * @since 1.5.0 + * @author Artem Labazin */ @SuppressWarnings("PMD.DoNotUseThreads") @FieldDefaults(level = PRIVATE, makeFinal = true) diff --git a/src/main/java/io/appulse/utils/threads/CompletablePromise.java b/src/main/java/io/appulse/utils/threads/CompletablePromise.java index 78d9013..b217e4f 100644 --- a/src/main/java/io/appulse/utils/threads/CompletablePromise.java +++ b/src/main/java/io/appulse/utils/threads/CompletablePromise.java @@ -28,8 +28,10 @@ /** * {@link Future} object wrapper to {@link CompletableFuture}. * - * @author Artem Labazin + * @param the promis's generic type. + * * @since 1.11.1 + * @author Artem Labazin */ @FieldDefaults(level = PRIVATE) public class CompletablePromise extends CompletableFuture { diff --git a/src/main/java/io/appulse/utils/threads/FutureUtils.java b/src/main/java/io/appulse/utils/threads/FutureUtils.java index fc3b3be..327f40a 100644 --- a/src/main/java/io/appulse/utils/threads/FutureUtils.java +++ b/src/main/java/io/appulse/utils/threads/FutureUtils.java @@ -29,8 +29,8 @@ /** * Different future helpers. * - * @author Artem Labazin * @since 1.11.0 + * @author Artem Labazin */ public final class FutureUtils { @@ -39,6 +39,8 @@ public final class FutureUtils { * * @param throwable the exception * + * @param the future's generic type. + * * @return completed exceptionally {@link CompletableFuture} instance. */ public static CompletableFuture completedExceptionally (Throwable throwable) { @@ -52,9 +54,13 @@ public static CompletableFuture completedExceptionally (Throwable throwab * * @param futures array of futures. * + * @param the future's generic type. + * * @return first non-exceptional completed future. */ - public static CompletableFuture firstCompletedWithoutException (@NonNull CompletionStage... futures) { + public static CompletableFuture firstCompletedWithoutException ( + @NonNull CompletionStage... futures + ) { val stream = Stream.of(futures); return firstCompletedWithoutException(stream); } @@ -64,9 +70,13 @@ public static CompletableFuture firstCompletedWithoutException (@NonNull * * @param futures list of futures. * + * @param the future's generic type. + * * @return first non-exceptional completed future. */ - public static CompletableFuture firstCompletedWithoutException (@NonNull List> futures) { + public static CompletableFuture firstCompletedWithoutException ( + @NonNull List> futures + ) { val stream = futures.stream(); return firstCompletedWithoutException(stream); } @@ -76,6 +86,8 @@ public static CompletableFuture firstCompletedWithoutException (@NonNull * * @param future for transform. * + * @param the future's generic type. + * * @return {@link CompletableFuture} instance. */ public static CompletableFuture toCompletableFuture (@NonNull Future future) { @@ -83,7 +95,9 @@ public static CompletableFuture toCompletableFuture (@NonNull Future f } // https://stackoverflow.com/a/34163913 - private static CompletableFuture firstCompletedWithoutException (Stream> stream) { + private static CompletableFuture firstCompletedWithoutException ( + Stream> stream + ) { CompletableFuture result = new CompletableFuture<>(); val complete = (Consumer) result::complete; diff --git a/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java index 307d096..e57d0ef 100644 --- a/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java +++ b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTrace.java @@ -23,9 +23,10 @@ import lombok.val; /** + * The {@link ExecutorService}'s wrapper for client's stack trace. * - * @author Artem Labazin * @since 1.5.0 + * @author Artem Labazin */ @Slf4j @SuppressWarnings("PMD.DoNotUseThreads") diff --git a/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitor.java b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitor.java index 9ef0127..f95b0db 100644 --- a/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitor.java +++ b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitor.java @@ -23,9 +23,10 @@ import lombok.val; /** + * The {@link ExecutorService}'s wrapper for tasks execution monitoring. * - * @author Artem Labazin * @since 1.5.0 + * @author Artem Labazin */ @Slf4j @SuppressWarnings("PMD.DoNotUseThreads") diff --git a/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWrapper.java b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWrapper.java index 6af4982..3dcd377 100644 --- a/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWrapper.java +++ b/src/main/java/io/appulse/utils/threads/executor/ExecutorServiceWrapper.java @@ -30,9 +30,10 @@ import lombok.experimental.FieldDefaults; /** + * The {@link ExecutorService} wrapper, which delegates all methods execution. * - * @author Artem Labazin * @since 1.5.0 + * @author Artem Labazin */ @SuppressWarnings("PMD.DoNotUseThreads") @RequiredArgsConstructor(access = PROTECTED) diff --git a/src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWithClientTrace.java b/src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWithClientTrace.java index a27fe52..7f7b2aa 100644 --- a/src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWithClientTrace.java +++ b/src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWithClientTrace.java @@ -23,9 +23,10 @@ import lombok.val; /** + * The {@link ScheduledExecutorService}'s wrapper for client's stack trace. * - * @author Artem Labazin * @since 1.5.0 + * @author Artem Labazin */ @Slf4j @SuppressWarnings("PMD.DoNotUseThreads") diff --git a/src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWrapper.java b/src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWrapper.java index af2583f..936e040 100644 --- a/src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWrapper.java +++ b/src/main/java/io/appulse/utils/threads/executor/ScheduledExecutorServiceWrapper.java @@ -28,9 +28,10 @@ import lombok.experimental.FieldDefaults; /** + * The {@link ScheduledExecutorService} wrapper, which delegates all methods execution. * - * @author Artem Labazin * @since 1.5.0 + * @author Artem Labazin */ @SuppressWarnings("PMD.DoNotUseThreads") @FieldDefaults(level = PRIVATE, makeFinal = true) diff --git a/src/main/java/io/appulse/utils/threads/executor/builder/ExecutorServiceBuilder.java b/src/main/java/io/appulse/utils/threads/executor/builder/ExecutorServiceBuilder.java index 13d3523..dc210f5 100644 --- a/src/main/java/io/appulse/utils/threads/executor/builder/ExecutorServiceBuilder.java +++ b/src/main/java/io/appulse/utils/threads/executor/builder/ExecutorServiceBuilder.java @@ -35,9 +35,10 @@ import lombok.experimental.FieldDefaults; /** + * The {@link ExecutorService}'s builder object. * - * @author Artem Labazin * @since 1.5.0 + * @author Artem Labazin */ @SuppressWarnings({ "PMD.AvoidLiteralsInIfCondition", diff --git a/src/main/java/io/appulse/utils/threads/executor/builder/ForkJoinPoolBuilder.java b/src/main/java/io/appulse/utils/threads/executor/builder/ForkJoinPoolBuilder.java index 983d76a..bbc8970 100644 --- a/src/main/java/io/appulse/utils/threads/executor/builder/ForkJoinPoolBuilder.java +++ b/src/main/java/io/appulse/utils/threads/executor/builder/ForkJoinPoolBuilder.java @@ -28,9 +28,10 @@ import lombok.experimental.FieldDefaults; /** + * The {@link ForkJoinPool}'s builder object. * - * @author Artem Labazin * @since 1.5.0 + * @author Artem Labazin */ @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") @FieldDefaults(level = PRIVATE) diff --git a/src/main/java/io/appulse/utils/threads/executor/builder/ScheduledExecutorServiceBuilder.java b/src/main/java/io/appulse/utils/threads/executor/builder/ScheduledExecutorServiceBuilder.java index 0de8635..b50718c 100644 --- a/src/main/java/io/appulse/utils/threads/executor/builder/ScheduledExecutorServiceBuilder.java +++ b/src/main/java/io/appulse/utils/threads/executor/builder/ScheduledExecutorServiceBuilder.java @@ -32,9 +32,10 @@ import lombok.experimental.FieldDefaults; /** + * The {@link ScheduledExecutorService}'s builder object. * - * @author Artem Labazin * @since 1.5.0 + * @author Artem Labazin */ @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") @FieldDefaults(level = PRIVATE) diff --git a/src/test/java/io/appulse/utils/AnnotationUtilsTest.java b/src/test/java/io/appulse/utils/AnnotationUtilsTest.java index b401ccc..951fa4e 100644 --- a/src/test/java/io/appulse/utils/AnnotationUtilsTest.java +++ b/src/test/java/io/appulse/utils/AnnotationUtilsTest.java @@ -30,10 +30,6 @@ import org.junit.jupiter.api.Test; -/** - * - * @author alabazin - */ class AnnotationUtilsTest { @Test diff --git a/src/test/java/io/appulse/utils/BytesTest.java b/src/test/java/io/appulse/utils/BytesTest.java index 74b0e62..98469a9 100644 --- a/src/test/java/io/appulse/utils/BytesTest.java +++ b/src/test/java/io/appulse/utils/BytesTest.java @@ -25,11 +25,6 @@ import lombok.val; import org.junit.jupiter.api.Test; -/** - * - * @author Artem Labazin - * @since 1.0.0 - */ class BytesTest { @Test diff --git a/src/test/java/io/appulse/utils/ExceptionUtilsTest.java b/src/test/java/io/appulse/utils/ExceptionUtilsTest.java index 7c90bb0..cf30c1f 100644 --- a/src/test/java/io/appulse/utils/ExceptionUtilsTest.java +++ b/src/test/java/io/appulse/utils/ExceptionUtilsTest.java @@ -24,11 +24,6 @@ import org.junit.jupiter.api.Test; -/** - * - * @author Artem Labazin - * @since 1.6.0 - */ class ExceptionUtilsTest { @Test diff --git a/src/test/java/io/appulse/utils/ReflectionUtilsTest.java b/src/test/java/io/appulse/utils/ReflectionUtilsTest.java index 9f875bb..dac98d2 100644 --- a/src/test/java/io/appulse/utils/ReflectionUtilsTest.java +++ b/src/test/java/io/appulse/utils/ReflectionUtilsTest.java @@ -23,10 +23,6 @@ import lombok.Setter; import org.junit.jupiter.api.Test; -/** - * - * @author Artem Labazin - */ class ReflectionUtilsTest { @Test diff --git a/src/test/java/io/appulse/utils/ResourceUtilsTest.java b/src/test/java/io/appulse/utils/ResourceUtilsTest.java index 9d1d634..3f1027c 100644 --- a/src/test/java/io/appulse/utils/ResourceUtilsTest.java +++ b/src/test/java/io/appulse/utils/ResourceUtilsTest.java @@ -24,11 +24,6 @@ import org.junit.jupiter.api.Test; -/** - * - * @author Artem Labazin - * @since 1.3.0 - */ class ResourceUtilsTest { @Test diff --git a/src/test/java/io/appulse/utils/RoundRobinTest.java b/src/test/java/io/appulse/utils/RoundRobinTest.java index df2c316..38614fd 100644 --- a/src/test/java/io/appulse/utils/RoundRobinTest.java +++ b/src/test/java/io/appulse/utils/RoundRobinTest.java @@ -20,10 +20,6 @@ import org.junit.jupiter.api.Test; -/** - * @author Artem Labazin - * @since 1.8.0 - */ class RoundRobinTest { @Test diff --git a/src/test/java/io/appulse/utils/SerializationUtilsTest.java b/src/test/java/io/appulse/utils/SerializationUtilsTest.java index 4e183c1..6b430dd 100644 --- a/src/test/java/io/appulse/utils/SerializationUtilsTest.java +++ b/src/test/java/io/appulse/utils/SerializationUtilsTest.java @@ -30,10 +30,6 @@ import lombok.val; import org.junit.jupiter.api.Test; -/** - * - * @author alabazin - */ class SerializationUtilsTest { @Test diff --git a/src/test/java/io/appulse/utils/SocketUtilsTest.java b/src/test/java/io/appulse/utils/SocketUtilsTest.java index 4024588..b454fd1 100644 --- a/src/test/java/io/appulse/utils/SocketUtilsTest.java +++ b/src/test/java/io/appulse/utils/SocketUtilsTest.java @@ -22,11 +22,6 @@ import org.junit.jupiter.api.Test; -/** - * - * @author Artem Labazin - * @since 1.2.0 - */ class SocketUtilsTest { @Test diff --git a/src/test/java/io/appulse/utils/threads/AppulseThreadFactoryTest.java b/src/test/java/io/appulse/utils/threads/AppulseThreadFactoryTest.java index d8dd9b8..7943f69 100644 --- a/src/test/java/io/appulse/utils/threads/AppulseThreadFactoryTest.java +++ b/src/test/java/io/appulse/utils/threads/AppulseThreadFactoryTest.java @@ -24,11 +24,6 @@ import org.junit.jupiter.api.Test; -/** - * - * @author Artem Labazin - * @since 1.5.0 - */ class AppulseThreadFactoryTest { @Test diff --git a/src/test/java/io/appulse/utils/threads/FutureUtilsTests.java b/src/test/java/io/appulse/utils/threads/FutureUtilsTests.java index 94e0653..d54ff7a 100644 --- a/src/test/java/io/appulse/utils/threads/FutureUtilsTests.java +++ b/src/test/java/io/appulse/utils/threads/FutureUtilsTests.java @@ -30,11 +30,6 @@ import lombok.val; import org.junit.jupiter.api.Test; -/** - * - * @author Artem Labazin - * @since 1.11.0 - */ class FutureUtilsTests { @Test diff --git a/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java b/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java index a92434b..1196129 100644 --- a/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java +++ b/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithClientTraceTest.java @@ -30,11 +30,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -/** - * - * @author Artem Labazin - * @since 1.5.0 - */ class ExecutorServiceWithClientTraceTest { @BeforeEach diff --git a/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitorTest.java b/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitorTest.java index a41d46d..b609759 100644 --- a/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitorTest.java +++ b/src/test/java/io/appulse/utils/threads/executor/ExecutorServiceWithTimeMonitorTest.java @@ -28,15 +28,9 @@ import ch.qos.logback.classic.spi.ILoggingEvent; import lombok.val; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -/** - * - * @author Artem Labazin - * @since 1.5.0 - */ class ExecutorServiceWithTimeMonitorTest { @BeforeEach From b05fb5f39e0d5deb54ae699d61aa95f257e032dd Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Mon, 9 Dec 2019 19:09:27 +0300 Subject: [PATCH 45/58] Add wrapper constructor for BytesOpenStream --- CHANGELOG.md | 6 ++++++ pom.xml | 4 ++-- src/main/java/io/appulse/utils/BytesOutputStream.java | 10 ++++++++++ .../io/appulse/utils/threads/AppulseExecutors.java | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f16c3e4..5d5a3c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add more tests. - Add `JavaDoc`. +## [1.17.1](https://github.com/appulse-projects/utils-java/releases/tag/1.17.1) - 2019-12-09 + +### Changed + +- Added a new wrapper constructor for `BytesOutputStream`. + ## [1.17.0](https://github.com/appulse-projects/utils-java/releases/tag/1.17.0) - 2019-12-09 ### Added diff --git a/pom.xml b/pom.xml index 6b6bfca..fc68741 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ limitations under the License. io.appulse utils-java - 1.17.0 + 1.17.1 jar @@ -66,7 +66,7 @@ limitations under the License. https://github.com/appulse-projects/utils-java scm:git:https://github.com/appulse-projects/utils-java.git scm:git:https://github.com/appulse-projects/utils-java.git - 1.17.0 + 1.17.1 diff --git a/src/main/java/io/appulse/utils/BytesOutputStream.java b/src/main/java/io/appulse/utils/BytesOutputStream.java index eb24a73..723b951 100644 --- a/src/main/java/io/appulse/utils/BytesOutputStream.java +++ b/src/main/java/io/appulse/utils/BytesOutputStream.java @@ -65,6 +65,16 @@ public BytesOutputStream (int size) { buffer = Bytes.resizableArray(size); } + /** + * The constructor wraps already existent {@link Bytes}. + * + * @param bytes the bytes buffer to wraps. + */ + public BytesOutputStream (Bytes bytes) { + super(); + buffer = bytes; + } + @Override public synchronized void write (int value) throws IOException { buffer.write1B(value); diff --git a/src/main/java/io/appulse/utils/threads/AppulseExecutors.java b/src/main/java/io/appulse/utils/threads/AppulseExecutors.java index 7c05334..1900ac7 100644 --- a/src/main/java/io/appulse/utils/threads/AppulseExecutors.java +++ b/src/main/java/io/appulse/utils/threads/AppulseExecutors.java @@ -28,7 +28,7 @@ import io.appulse.utils.threads.executor.builder.ScheduledExecutorServiceBuilder; /** - * The {@link ExecutorService} implementation with fancy builder. + * The {@link java.util.concurrent.ExecutorService} implementation with fancy builder. * * @since 1.5.0 * @author Artem Labazin From 713e72efc5455709a1961b8409b5351482fdc1e1 Mon Sep 17 00:00:00 2001 From: Artem Labazin Date: Thu, 12 Dec 2019 16:30:04 +0300 Subject: [PATCH 46/58] Add AutoCloseable interface for PooledBytes class --- CHANGELOG.md | 6 ++++++ pom.xml | 4 ++-- src/main/java/io/appulse/utils/BytesPool.java | 7 ++++++- src/test/java/io/appulse/utils/BytesPoolTest.java | 4 ++-- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d5a3c7..db6f617 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add more tests. - Add `JavaDoc`. +## [1.17.2](https://github.com/appulse-projects/utils-java/releases/tag/1.17.2) - 2019-12-12 + +### Changed + +- Add `AutoCloseable` interface for `PooledBytes` class. + ## [1.17.1](https://github.com/appulse-projects/utils-java/releases/tag/1.17.1) - 2019-12-09 ### Changed diff --git a/pom.xml b/pom.xml index fc68741..6daeb57 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ limitations under the License. io.appulse utils-java - 1.17.1 + 1.17.2 jar @@ -66,7 +66,7 @@ limitations under the License. https://github.com/appulse-projects/utils-java scm:git:https://github.com/appulse-projects/utils-java.git scm:git:https://github.com/appulse-projects/utils-java.git - 1.17.1 + 1.17.2 diff --git a/src/main/java/io/appulse/utils/BytesPool.java b/src/main/java/io/appulse/utils/BytesPool.java index 27e9bfa..f71c19a 100644 --- a/src/main/java/io/appulse/utils/BytesPool.java +++ b/src/main/java/io/appulse/utils/BytesPool.java @@ -208,7 +208,7 @@ private Bytes getOrCreateBuffer () throws InterruptedException { */ @FieldDefaults(level = PRIVATE) @SuppressWarnings("PMD.LinguisticNaming") - public class PooledBytes extends BytesAbstract { + public final class PooledBytes extends BytesAbstract implements AutoCloseable { Bytes delegate; @@ -226,6 +226,11 @@ public void release () { BytesPool.this.release(this); } + @Override + public void close () { + release(); + } + @Override public boolean isAutoResizable () { validate(); diff --git a/src/test/java/io/appulse/utils/BytesPoolTest.java b/src/test/java/io/appulse/utils/BytesPoolTest.java index 9ee00dd..e980052 100644 --- a/src/test/java/io/appulse/utils/BytesPoolTest.java +++ b/src/test/java/io/appulse/utils/BytesPoolTest.java @@ -105,8 +105,8 @@ void twoPools () { @Test void instantiation () { - try (val pool = new BytesPool()) { - val buffer = pool.acquire(16); + try (val pool = new BytesPool(); + val buffer = pool.acquire(16)) { assertThat(buffer.capacity()).isGreaterThanOrEqualTo(16); } } From 362ebe346d7a92451cd1ca2a52d3eab94d6f7946 Mon Sep 17 00:00:00 2001 From: xxlabaza Date: Tue, 25 Feb 2020 20:34:55 +0300 Subject: [PATCH 47/58] Update dependencies --- .codestyle/checkstyle.xml | 8 ++--- .codestyle/findbugs.xml | 2 +- .codestyle/license_for_check.txt | 2 +- .codestyle/pmd.xml | 2 +- .mvn/wrapper/maven-wrapper.properties | 2 +- .settings.xml | 2 +- .travis.yml | 5 ++- CHANGELOG.md | 9 +++++ CONTRIBUTING.md | 2 +- pom.xml | 34 +++++++++---------- .../io/appulse/utils/AnnotationUtils.java | 2 +- src/main/java/io/appulse/utils/Bytes.java | 2 +- .../java/io/appulse/utils/BytesAbstract.java | 2 +- .../java/io/appulse/utils/BytesByteBuf.java | 2 +- .../io/appulse/utils/BytesByteBuffer.java | 2 +- .../appulse/utils/BytesExtendableArray.java | 2 +- .../io/appulse/utils/BytesFixedArray.java | 2 +- .../io/appulse/utils/BytesInputStream.java | 2 +- .../io/appulse/utils/BytesOutputStream.java | 2 +- src/main/java/io/appulse/utils/BytesPool.java | 2 +- .../java/io/appulse/utils/BytesUtils.java | 2 +- .../java/io/appulse/utils/ExceptionUtils.java | 2 +- src/main/java/io/appulse/utils/HexUtil.java | 2 +- .../java/io/appulse/utils/LimitedQueue.java | 2 +- .../java/io/appulse/utils/ReadBytesUtils.java | 2 +- .../io/appulse/utils/ReflectionUtils.java | 2 +- .../java/io/appulse/utils/ResourceUtils.java | 2 +- .../java/io/appulse/utils/RoundRobin.java | 2 +- .../io/appulse/utils/SerializationUtils.java | 2 +- src/main/java/io/appulse/utils/SizeUnit.java | 2 +- .../java/io/appulse/utils/SocketUtils.java | 2 +- .../io/appulse/utils/WriteBytesUtils.java | 2 +- .../io/appulse/utils/cache/FifoCache.java | 2 +- .../java/io/appulse/utils/cache/LruCache.java | 2 +- .../exception/CantReadFromArrayException.java | 2 +- .../exception/CantWriteToArrayException.java | 2 +- .../exception/SerializationException.java | 2 +- .../io/appulse/utils/test/TestAppender.java | 2 +- .../utils/threads/AppulseExecutors.java | 2 +- .../utils/threads/AppulseThreadFactory.java | 2 +- .../utils/threads/CompletablePromise.java | 2 +- .../threads/CompletablePromiseContext.java | 2 +- .../io/appulse/utils/threads/FutureUtils.java | 2 +- .../ExecutorServiceWithClientTrace.java | 2 +- .../ExecutorServiceWithTimeMonitor.java | 2 +- .../executor/ExecutorServiceWrapper.java | 2 +- ...heduledExecutorServiceWithClientTrace.java | 2 +- .../ScheduledExecutorServiceWrapper.java | 2 +- .../builder/ExecutorServiceBuilder.java | 2 +- .../executor/builder/ForkJoinPoolBuilder.java | 2 +- .../ScheduledExecutorServiceBuilder.java | 2 +- .../io/appulse/utils/AnnotationUtilsTest.java | 2 +- .../java/io/appulse/utils/BytesPoolTest.java | 2 +- src/test/java/io/appulse/utils/BytesTest.java | 2 +- .../java/io/appulse/utils/BytesUtilsTest.java | 2 +- .../io/appulse/utils/ExceptionUtilsTest.java | 2 +- .../java/io/appulse/utils/HexUtilTests.java | 2 +- .../io/appulse/utils/ReadBytesUtilsTests.java | 2 +- .../io/appulse/utils/ReflectionUtilsTest.java | 2 +- .../io/appulse/utils/ResourceUtilsTest.java | 2 +- .../java/io/appulse/utils/RoundRobinTest.java | 2 +- .../appulse/utils/SerializationUtilsTest.java | 2 +- .../io/appulse/utils/SocketUtilsTest.java | 2 +- .../appulse/utils/WriteBytesUtilsTests.java | 2 +- .../utils/threads/AppulseExecutorsTests.java | 2 +- .../threads/AppulseThreadFactoryTest.java | 2 +- .../utils/threads/FutureUtilsTests.java | 2 +- .../ExecutorServiceWithClientTraceTest.java | 2 +- .../ExecutorServiceWithTimeMonitorTest.java | 2 +- src/test/resources/logback-test.xml | 2 +- 70 files changed, 100 insertions(+), 88 deletions(-) diff --git a/.codestyle/checkstyle.xml b/.codestyle/checkstyle.xml index 39583e3..2c25cae 100644 --- a/.codestyle/checkstyle.xml +++ b/.codestyle/checkstyle.xml @@ -4,7 +4,7 @@ "http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd">