diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 5fde8dd7..1711ae4b 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -14,17 +14,17 @@ jobs:
checks: write
contents: read
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-java@v4
+ - uses: actions/checkout@v6
+ - uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- run: mvn -B verify
- - uses: madrapps/jacoco-report@v1.6.1
+ - uses: madrapps/jacoco-report@v1.7.2
with:
paths: ${{ github.workspace }}/target/site/jacoco/jacoco.xml
token: ${{ secrets.GITHUB_TOKEN }}
min-coverage-overall: 80
min-coverage-changed-files: 80
- - uses: scacap/action-surefire-report@v1.7.3
\ No newline at end of file
+ - uses: scacap/action-surefire-report@v1.9.1
\ No newline at end of file
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index f6ad8c52..c00ed329 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -23,14 +23,14 @@ jobs:
language: [ 'java' ]
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-java@v4
+ - uses: actions/checkout@v6
+ - uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- - uses: github/codeql-action/init@v3
+ - uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
- - uses: github/codeql-action/autobuild@v3
- - uses: github/codeql-action/analyze@v3
+ - uses: github/codeql-action/autobuild@v4
+ - uses: github/codeql-action/analyze@v4
diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml
index 44316aef..ace69696 100644
--- a/.github/workflows/gh-pages.yml
+++ b/.github/workflows/gh-pages.yml
@@ -14,13 +14,13 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
- - uses: actions/configure-pages@v4
+ - uses: actions/checkout@v6
+ - uses: actions/configure-pages@v5
- uses: actions/jekyll-build-pages@v1
with:
source: ./
destination: ./_site
- - uses: actions/upload-pages-artifact@v3
+ - uses: actions/upload-pages-artifact@v4
deploy:
environment:
name: github-pages
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 69ce43c6..3ab20fb0 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -5,8 +5,8 @@ jobs:
publish:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-java@v4
+ - uses: actions/checkout@v6
+ - uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'temurin'
@@ -28,7 +28,7 @@ jobs:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
- - uses: release-drafter/release-drafter@v6
+ - uses: release-drafter/release-drafter@v7
with:
version: ${{ steps.version.outputs.version }}
publish: true
diff --git a/README.md b/README.md
index bcd72ba4..db941103 100644
--- a/README.md
+++ b/README.md
@@ -69,13 +69,22 @@ Projects that use Matomo Java Tracker:
## What Is New?
+### Version 3.4.x
+
+We fixed a synchronization issue in the Java 8 sender (https://github.com/matomo-org/matomo-java-tracker/issues/168).
+To consume the exact amount of space needed for the queries to send to Matomo, we need the collection size of the incoming
+requests. So we changed `Iterable` to `Collection` in some `MatomoTracker`. This could affect users, that use parameters
+of type `Iterable` in the tracker. Please use `Collection` instead.
+
+### Version 3.3.x
+
Do you still use Matomo Java Tracker 2.x? We created version 3, that is compatible with Matomo 4 and 5 and contains
fewer
dependencies. Release notes can be found here: https://github.com/matomo-org/matomo-java-tracker/releases
Here are the most important changes:
-* Matomo Java Tracker 3.2.0 is compatible with Matomo 4 and 5
+* Matomo Java Tracker 3.4.0 is compatible with Matomo 4 and 5
* less dependencies
* new dimension parameter
* special types allow to provide valid parameters now
@@ -140,7 +149,7 @@ Add a dependency on Matomo Java Tracker using Maven. For Java 8:
org.piwik.java.tracking
matomo-java-tracker
- 3.2.0
+ 3.4.0
```
@@ -151,7 +160,7 @@ For Java 11:
org.piwik.java.tracking
matomo-java-tracker-java11
- 3.2.0
+ 3.4.0
```
@@ -159,7 +168,7 @@ or Gradle (Java 8):
```groovy
dependencies {
- implementation("org.piwik.java.tracking:matomo-java-tracker:3.2.0")
+ implementation("org.piwik.java.tracking:matomo-java-tracker:3.4.0")
}
```
@@ -167,20 +176,20 @@ or Gradle (Java 11):
```groovy
dependencies {
- implementation("org.piwik.java.tracking:matomo-java-tracker-java11:3.2.0")
+ implementation("org.piwik.java.tracking:matomo-java-tracker-java11:3.4.0")
}
```
or Gradle with Kotlin DSL (Java 8)
```kotlin
-implementation("org.piwik.java.tracking:matomo-java-tracker:3.2.0")
+implementation("org.piwik.java.tracking:matomo-java-tracker:3.4.0")
```
or Gradle with Kotlin DSL (Java 11)
```kotlin
-implementation("org.piwik.java.tracking:matomo-java-tracker-java11:3.2.0")
+implementation("org.piwik.java.tracking:matomo-java-tracker-java11:3.4.0")
```
### Spring Boot Module
@@ -193,7 +202,7 @@ and allows you to configure the tracker via application properties. Add the foll
org.piwik.java.tracking
matomo-java-tracker-spring-boot-starter
- 3.2.0
+ 3.4.0
```
@@ -201,14 +210,14 @@ or Gradle:
```groovy
dependencies {
- implementation("org.piwik.java.tracking:matomo-java-tracker-spring-boot-starter:3.2.0")
+ implementation("org.piwik.java.tracking:matomo-java-tracker-spring-boot-starter:3.4.0")
}
```
or Gradle with Kotlin DSL
```kotlin
-implementation("org.piwik.java.tracking:matomo-java-tracker-spring-boot-starter:3.2.0")
+implementation("org.piwik.java.tracking:matomo-java-tracker-spring-boot-starter:3.4.0")
```
The following properties are supported:
@@ -270,14 +279,21 @@ To let the Matomo Java Tracker send a request to the Matomo instance, you need t
```java
import java.net.URI;
-import org.matomo.java.tracking.MatomoRequest;
import org.matomo.java.tracking.MatomoRequests;
import org.matomo.java.tracking.MatomoTracker;
import org.matomo.java.tracking.TrackerConfiguration;
import org.matomo.java.tracking.parameters.VisitorId;
+/**
+ * Example for sending a request.
+ */
public class SendExample {
+ /**
+ * Example for sending a request.
+ *
+ * @param args ignored
+ */
public static void main(String[] args) {
TrackerConfiguration configuration = TrackerConfiguration
@@ -288,17 +304,19 @@ public class SendExample {
.logFailedTracking(true)
.build();
- MatomoTracker tracker = new MatomoTracker(configuration);
-
- tracker.sendRequestAsync(MatomoRequests
- .event("Training", "Workout completed", "Bench press", 60.0)
- .visitorId(VisitorId.fromString("customer@mail.com"))
- .build()
- );
-
+ try (MatomoTracker tracker = new MatomoTracker(configuration)) {
+ tracker.sendRequestAsync(MatomoRequests
+ .event("Training", "Workout completed", "Bench press", 60.0)
+ .visitorId(VisitorId.fromString("customer@mail.com"))
+ .build()
+ );
+ } catch (Exception e) {
+ throw new RuntimeException("Could not close tracker", e);
+ }
}
}
+
```
This will send a request to the Matomo instance at https://www.yourdomain.com/matomo.php and track a page view for the
@@ -311,15 +329,23 @@ If you want to perform an operation after a successful asynchronous call to Mato
result like this:
```java
-
import java.net.URI;
+import org.matomo.java.tracking.MatomoRequest;
import org.matomo.java.tracking.MatomoRequests;
import org.matomo.java.tracking.MatomoTracker;
import org.matomo.java.tracking.TrackerConfiguration;
import org.matomo.java.tracking.parameters.VisitorId;
+/**
+ * Example for sending a request and performing an action when the request was sent successfully.
+ */
public class ConsumerExample {
+ /**
+ * Example for sending a request and performing an action when the request was sent successfully.
+ *
+ * @param args ignored
+ */
public static void main(String[] args) {
TrackerConfiguration configuration = TrackerConfiguration
@@ -330,24 +356,27 @@ public class ConsumerExample {
.logFailedTracking(true)
.build();
- MatomoTracker tracker = new MatomoTracker(configuration);
-
- MatomoRequest request = MatomoRequests
- .event("Training", "Workout completed", "Bench press", 60.0)
- .visitorId(VisitorId.fromString("customer@mail.com"))
- .build();
-
- tracker.sendRequestAsync(request)
- .thenAccept(req -> System.out.printf("Sent request %s%n", req))
- .exceptionally(throwable -> {
- System.err.printf("Failed to send request: %s%n", throwable.getMessage());
- return null;
- });
+ try (MatomoTracker tracker = new MatomoTracker(configuration)) {
+ MatomoRequest request = MatomoRequests
+ .event("Training", "Workout completed", "Bench press", 60.0)
+ .visitorId(VisitorId.fromString("customer@mail.com"))
+ .build();
+
+ tracker.sendRequestAsync(request)
+ .thenAccept(req -> System.out.printf("Sent request %s%n", req))
+ .exceptionally(throwable -> {
+ System.err.printf("Failed to send request: %s%n", throwable.getMessage());
+ return null;
+ });
+ } catch (Exception e) {
+ throw new RuntimeException("Could not close tracker", e);
+ }
}
}
+
```
If you have multiple requests to wish to track, it may be more efficient to send them in a single HTTP call. To do this,
@@ -355,14 +384,21 @@ send a bulk request. Place your requests in an _Iterable_ data structure and cal
```java
import java.net.URI;
-import org.matomo.java.tracking.MatomoRequest;
import org.matomo.java.tracking.MatomoRequests;
import org.matomo.java.tracking.MatomoTracker;
import org.matomo.java.tracking.TrackerConfiguration;
import org.matomo.java.tracking.parameters.VisitorId;
+/**
+ * Example for sending multiple requests in one bulk request.
+ */
public class BulkExample {
+ /**
+ * Example for sending multiple requests in one bulk request.
+ *
+ * @param args ignored
+ */
public static void main(String[] args) {
TrackerConfiguration configuration = TrackerConfiguration
@@ -373,23 +409,24 @@ public class BulkExample {
.logFailedTracking(true)
.build();
- MatomoTracker tracker = new MatomoTracker(configuration);
-
- VisitorId visitorId = VisitorId.fromString("customer@mail.com");
- tracker.sendBulkRequestAsync(
- MatomoRequests.siteSearch("Running shoes", "Running", 120L)
- .visitorId(visitorId).build(),
- MatomoRequests.pageView("VelocityStride ProX Running Shoes")
- .visitorId(visitorId).build(),
- MatomoRequests.ecommerceOrder("QXZ-789LMP", 100.0, 124.0, 19.0, 10.0, 5.0)
- .visitorId(visitorId)
- .build()
- );
+ try (MatomoTracker tracker = new MatomoTracker(configuration)) {
+ VisitorId visitorId = VisitorId.fromString("customer@mail.com");
+ tracker.sendBulkRequestAsync(
+ MatomoRequests.siteSearch("Running shoes", "Running", 120L)
+ .visitorId(visitorId).build(),
+ MatomoRequests.pageView("VelocityStride ProX Running Shoes")
+ .visitorId(visitorId).build(),
+ MatomoRequests.ecommerceOrder("QXZ-789LMP", 100.0, 124.0, 19.0, 10.0, 5.0)
+ .visitorId(visitorId)
+ .build()
+ );
+ } catch (Exception e) {
+ throw new RuntimeException("Could not close tracker", e);
+ }
}
}
-
```
This will send two requests in a single HTTP call. The requests will be sent asynchronously.
@@ -410,9 +447,7 @@ a unique identifier, e.g. an email address. If you do not provide a visitor id,
Ecommerce requests contain ecommerce items, that can be fluently build:
```java
-
import java.net.URI;
-import org.matomo.java.tracking.MatomoRequest;
import org.matomo.java.tracking.MatomoRequests;
import org.matomo.java.tracking.MatomoTracker;
import org.matomo.java.tracking.TrackerConfiguration;
@@ -420,8 +455,16 @@ import org.matomo.java.tracking.parameters.EcommerceItem;
import org.matomo.java.tracking.parameters.EcommerceItems;
import org.matomo.java.tracking.parameters.VisitorId;
+/**
+ * Example for sending an ecommerce request.
+ */
public class EcommerceExample {
+ /**
+ * Example for sending an ecommerce request.
+ *
+ * @param args ignored
+ */
public static void main(String[] args) {
TrackerConfiguration configuration = TrackerConfiguration
@@ -432,37 +475,38 @@ public class EcommerceExample {
.logFailedTracking(true)
.build();
- MatomoTracker tracker = new MatomoTracker(configuration);
-
- tracker.sendBulkRequestAsync(MatomoRequests
- .ecommerceCartUpdate(50.0)
- .ecommerceItems(EcommerceItems
- .builder()
- .item(EcommerceItem
- .builder()
- .sku("XYZ12345")
- .name("Matomo - The big book about web analytics")
- .category("Education & Teaching")
- .price(23.1)
- .quantity(2)
- .build())
- .item(EcommerceItem
- .builder()
- .sku("B0C2WV3MRJ")
- .name("Matomo for data visualization")
- .category("Education & Teaching")
- .price(15.0)
- .quantity(1)
- .build())
- .build())
- .visitorId(VisitorId.fromString("customer@mail.com"))
- .build()
- );
+ try (MatomoTracker tracker = new MatomoTracker(configuration)) {
+ tracker.sendBulkRequestAsync(MatomoRequests
+ .ecommerceCartUpdate(50.0)
+ .ecommerceItems(EcommerceItems
+ .builder()
+ .item(EcommerceItem
+ .builder()
+ .sku("XYZ12345")
+ .name("Matomo - The big book about web analytics")
+ .category("Education & Teaching")
+ .price(23.1)
+ .quantity(2)
+ .build())
+ .item(EcommerceItem
+ .builder()
+ .sku("B0C2WV3MRJ")
+ .name("Matomo for data visualization")
+ .category("Education & Teaching")
+ .price(15.0)
+ .quantity(1)
+ .build())
+ .build())
+ .visitorId(VisitorId.fromString("customer@mail.com"))
+ .build()
+ );
+ } catch (Exception e) {
+ throw new RuntimeException("Could not close tracker", e);
+ }
}
}
-
```
Note that if you want to be able to track campaigns using *Referrers > Campaigns*, you must add the correct
@@ -640,11 +684,10 @@ the Maven goal `install, a snapshot
version can be used in your local Maven repository for testing purposes, e.g.
```xml
-
org.piwik.java.tracking
matomo-java-tracker
- 3.2.1-SNAPSHOT
+ 3.4.1-SNAPSHOT
```
diff --git a/core/pom.xml b/core/pom.xml
index b6d57050..a716cbbb 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -4,7 +4,7 @@
org.piwik.java.tracking
matomo-java-tracker-parent
- 3.2.2-SNAPSHOT
+ 3.4.1-SNAPSHOT
../pom.xml
diff --git a/core/src/main/java/org/matomo/java/tracking/ExecutorServiceCloser.java b/core/src/main/java/org/matomo/java/tracking/ExecutorServiceCloser.java
new file mode 100644
index 00000000..1ef11c97
--- /dev/null
+++ b/core/src/main/java/org/matomo/java/tracking/ExecutorServiceCloser.java
@@ -0,0 +1,42 @@
+package org.matomo.java.tracking;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import lombok.NonNull;
+
+/**
+ * Helps to close an executor service.
+ */
+public class ExecutorServiceCloser {
+
+ /**
+ * Closes the given executor service.
+ *
+ *
This will check whether the executor service is already terminated, and if not, it
+ * initiates a shutdown and waits a minute. If the minute expires, the executor service
+ * is shutdown immediately.
+ *
+ * @param executorService The executor service to close
+ */
+ public static void close(@NonNull ExecutorService executorService) {
+ boolean terminated = executorService.isTerminated();
+ if (!terminated) {
+ executorService.shutdown();
+ boolean interrupted = false;
+ while (!terminated) {
+ try {
+ terminated = executorService.awaitTermination(1L, TimeUnit.MINUTES);
+ } catch (InterruptedException e) {
+ if (!interrupted) {
+ executorService.shutdownNow();
+ interrupted = true;
+ }
+ }
+ }
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+}
diff --git a/core/src/main/java/org/matomo/java/tracking/MatomoRequest.java b/core/src/main/java/org/matomo/java/tracking/MatomoRequest.java
index ea2ddbfc..42ef0c29 100644
--- a/core/src/main/java/org/matomo/java/tracking/MatomoRequest.java
+++ b/core/src/main/java/org/matomo/java/tracking/MatomoRequest.java
@@ -355,7 +355,7 @@ public class MatomoRequest {
/**
* The grand total for the ecommerce order (required when tracking an ecommerce order).
*/
- @TrackingParameter(name = "revenue")
+ @TrackingParameter(name = "revenue", min = 0)
private Double ecommerceRevenue;
/**
@@ -433,7 +433,7 @@ public class MatomoRequest {
/**
* Some numeric value that represents the event value.
*/
- @TrackingParameter(name = "e_n")
+ @TrackingParameter(name = "e_v", min = 0)
private Double eventValue;
/**
@@ -476,25 +476,25 @@ public class MatomoRequest {
/**
* The subtotal of the order; excludes shipping.
*/
- @TrackingParameter(name = "ec_st")
+ @TrackingParameter(name = "ec_st", min = 0)
private Double ecommerceSubtotal;
/**
* Tax amount of the order.
*/
- @TrackingParameter(name = "ec_tx")
+ @TrackingParameter(name = "ec_tx", min = 0)
private Double ecommerceTax;
/**
* Shipping cost of the order.
*/
- @TrackingParameter(name = "ec_sh")
+ @TrackingParameter(name = "ec_sh", min = 0)
private Double ecommerceShippingCost;
/**
* Discount offered.
*/
- @TrackingParameter(name = "ec_dt")
+ @TrackingParameter(name = "ec_dt", min = 0)
private Double ecommerceDiscount;
/**
diff --git a/core/src/main/java/org/matomo/java/tracking/MatomoTracker.java b/core/src/main/java/org/matomo/java/tracking/MatomoTracker.java
index 51a585d5..3c38d017 100644
--- a/core/src/main/java/org/matomo/java/tracking/MatomoTracker.java
+++ b/core/src/main/java/org/matomo/java/tracking/MatomoTracker.java
@@ -11,6 +11,7 @@
import java.net.URI;
import java.time.Duration;
import java.util.Arrays;
+import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -35,7 +36,7 @@
* @author brettcsorba
*/
@Slf4j
-public class MatomoTracker {
+public class MatomoTracker implements AutoCloseable {
private final TrackerConfiguration trackerConfiguration;
@@ -135,7 +136,7 @@ public MatomoTracker(
*
*
Use this method if you want to send a single request. If you want to send multiple requests at once, use
* {@link #sendBulkRequest(Iterable)} instead. If you want to send multiple requests asynchronously, use
- * {@link #sendRequestAsync(MatomoRequest)} or {@link #sendBulkRequestAsync(Iterable)} instead.
+ * {@link #sendRequestAsync(MatomoRequest)} or {@link #sendBulkRequestAsync(Collection)} instead.
*
* @param request request to send. must not be null
*/
@@ -160,7 +161,7 @@ private void initializeSender() {
* Send a request asynchronously via HTTP GET.
*
*
Use this method if you want to send a single request. If you want to send multiple requests at once, use
- * {@link #sendBulkRequestAsync(Iterable)} instead. If you want to send multiple requests synchronously, use
+ * {@link #sendBulkRequestAsync(Collection)} instead. If you want to send multiple requests synchronously, use
* {@link #sendRequest(MatomoRequest)} or {@link #sendBulkRequest(Iterable)} instead.
*
* @param request request to send
@@ -176,8 +177,8 @@ public CompletableFuture sendRequestAsync(
* Send a request asynchronously via HTTP GET and specify a callback that gets executed when the response arrives.
*
* Use this method if you want to send a single request. If you want to send multiple requests at once, use
- * {@link #sendBulkRequestAsync(Iterable, Consumer)} instead. If you want to send multiple requests synchronously, use
- * {@link #sendRequest(MatomoRequest)} or {@link #sendBulkRequest(Iterable)} instead.
+ * {@link #sendBulkRequestAsync(Collection, Consumer)} instead. If you want to send multiple requests synchronously,
+ * use {@link #sendRequest(MatomoRequest)} or {@link #sendBulkRequest(Iterable)} instead.
*
* @param request request to send
* @param callback callback that gets executed when response arrives, must not be null
@@ -223,7 +224,7 @@ private void applyGoalIdAndCheckSiteId(
*
*
More efficient than sending several individual requests. If you want to send a single request, use
* {@link #sendRequest(MatomoRequest)} instead. If you want to send multiple requests asynchronously, use
- * {@link #sendBulkRequestAsync(Iterable)} instead.
+ * {@link #sendBulkRequestAsync(Collection)} instead.
*
* @param requests the requests to send
*/
@@ -236,7 +237,7 @@ public void sendBulkRequest(MatomoRequest... requests) {
*
*
More efficient than sending several individual requests. If you want to send a single request, use
* {@link #sendRequest(MatomoRequest)} instead. If you want to send multiple requests asynchronously, use
- * {@link #sendBulkRequestAsync(Iterable)} instead.
+ * {@link #sendBulkRequestAsync(Collection)} instead.
*
* @param requests the requests to send
*/
@@ -250,7 +251,7 @@ public void sendBulkRequest(@NonNull Iterable extends MatomoRequest> requests)
*
*
Specify the AuthToken if parameters that require an auth token is used. If you want to send a single request,
* use {@link #sendRequest(MatomoRequest)} instead. If you want to send multiple requests asynchronously, use
- * {@link #sendBulkRequestAsync(Iterable)} instead.
+ * {@link #sendBulkRequestAsync(Collection)} instead.
*
* @param requests the requests to send
* @param authToken specify if any of the parameters use require AuthToken, if null the default auth token from the
@@ -293,7 +294,7 @@ public CompletableFuture sendBulkRequestAsync(MatomoRequest... requests) {
* @return completable future to let you know when the request is done
*/
public CompletableFuture sendBulkRequestAsync(
- @NonNull Iterable extends MatomoRequest> requests
+ @NonNull Collection extends MatomoRequest> requests
) {
return sendBulkRequestAsync(requests, null, null);
}
@@ -313,7 +314,7 @@ public CompletableFuture sendBulkRequestAsync(
*/
@Deprecated
public CompletableFuture sendBulkRequestAsync(
- @NonNull Iterable extends MatomoRequest> requests,
+ @NonNull Collection extends MatomoRequest> requests,
@Nullable String authToken,
@Nullable Consumer callback
) {
@@ -342,7 +343,7 @@ public CompletableFuture sendBulkRequestAsync(
* @return completable future to let you know when the request is done
*/
public CompletableFuture sendBulkRequestAsync(
- @NonNull Iterable extends MatomoRequest> requests,
+ @NonNull Collection extends MatomoRequest> requests,
@Nullable Consumer callback
) {
return sendBulkRequestAsync(requests, null, callback);
@@ -357,11 +358,19 @@ public CompletableFuture sendBulkRequestAsync(
* @param authToken specify if any of the parameters use require AuthToken, null allowed
* @return completable future to let you know when the request is done
* @deprecated Please set the auth token in the tracker configuration or the requests directly and use
- * {@link #sendBulkRequestAsync(Iterable)} instead.
+ * {@link #sendBulkRequestAsync(Collection)} instead.
*/
public CompletableFuture sendBulkRequestAsync(
- @NonNull Iterable extends MatomoRequest> requests, @Nullable String authToken
+ @NonNull Collection extends MatomoRequest> requests, @Nullable String authToken
) {
return sendBulkRequestAsync(requests, authToken, null);
}
+
+ @Override
+ public void close() throws Exception {
+ if (sender != null) {
+ sender.close();
+ }
+ }
+
}
diff --git a/core/src/main/java/org/matomo/java/tracking/Sender.java b/core/src/main/java/org/matomo/java/tracking/Sender.java
index acb82280..7b1df985 100644
--- a/core/src/main/java/org/matomo/java/tracking/Sender.java
+++ b/core/src/main/java/org/matomo/java/tracking/Sender.java
@@ -2,9 +2,10 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
+import java.util.Collection;
import java.util.concurrent.CompletableFuture;
-interface Sender {
+interface Sender extends AutoCloseable {
@NonNull
CompletableFuture sendSingleAsync(
@NonNull MatomoRequest request
@@ -20,6 +21,6 @@ void sendBulk(
@NonNull
CompletableFuture sendBulkAsync(
- @NonNull Iterable extends MatomoRequest> requests, @Nullable String overrideAuthToken
+ @NonNull Collection extends MatomoRequest> requests, @Nullable String overrideAuthToken
);
}
diff --git a/core/src/test/java/org/matomo/java/tracking/ExecutorServiceCloserTest.java b/core/src/test/java/org/matomo/java/tracking/ExecutorServiceCloserTest.java
new file mode 100644
index 00000000..e0d167a9
--- /dev/null
+++ b/core/src/test/java/org/matomo/java/tracking/ExecutorServiceCloserTest.java
@@ -0,0 +1,46 @@
+package org.matomo.java.tracking;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import org.junit.jupiter.api.Test;
+
+class ExecutorServiceCloserTest {
+
+ @Test
+ void shutsDownExecutorService() {
+
+ ExecutorService executorService = Executors.newFixedThreadPool(2, new DaemonThreadFactory());
+
+ ExecutorServiceCloser.close(executorService);
+
+ assertThat(executorService.isTerminated()).isTrue();
+ assertThat(executorService.isShutdown()).isTrue();
+
+ }
+
+ @Test
+ void shutsDownExecutorServiceImmediately() throws Exception {
+
+ ExecutorService executorService = Executors.newSingleThreadExecutor();
+ executorService.submit(() -> {
+ try {
+ Thread.sleep(10000L);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ Thread thread = new Thread(() -> {
+ ExecutorServiceCloser.close(executorService);
+ });
+ thread.start();
+ Thread.sleep(1000L);
+ thread.interrupt();
+
+ assertThat(executorService.isShutdown()).isTrue();
+
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/test/java/org/matomo/java/tracking/QueryCreatorTest.java b/core/src/test/java/org/matomo/java/tracking/QueryCreatorTest.java
index 1b1cecd4..a4e87e5b 100644
--- a/core/src/test/java/org/matomo/java/tracking/QueryCreatorTest.java
+++ b/core/src/test/java/org/matomo/java/tracking/QueryCreatorTest.java
@@ -538,4 +538,67 @@ void failsIfLongitudeIsGreaterThan180() {
.hasRootCauseMessage("Invalid value for long. Must be less or equal than 180");
}
-}
+ @Test
+ void tracksEvent() {
+ matomoRequestBuilder.eventName("Event Name")
+ .eventValue(23.456)
+ .eventAction("Event Action")
+ .eventCategory("Event Category");
+
+ whenCreatesQuery();
+
+ assertThat(query).isEqualTo("idsite=42&token_auth=876de1876fb2cda2816c362a61bfc712&rec=1&apiv=1&_id=112210f47de98115&e_c=Event+Category&e_a=Event+Action&e_n=Event+Name&e_v=23.456&send_image=0&rand=random-value");
+ }
+
+ @Test
+ void allowsZeroForEventValue() {
+ matomoRequestBuilder.eventName("Event Name")
+ .eventValue(0.0)
+ .eventAction("Event Action")
+ .eventCategory("Event Category");
+
+ whenCreatesQuery();
+
+ assertThat(query)
+ .isEqualTo("idsite=42&" +
+ "token_auth=876de1876fb2cda2816c362a61bfc712&" +
+ "rec=1&" +
+ "apiv=1&" +
+ "_id=112210f47de98115&" +
+ "e_c=Event+Category&" +
+ "e_a=Event+Action&" +
+ "e_n=Event+Name&" +
+ "e_v=0.0&" +
+ "send_image=0&" +
+ "rand=random-value"
+ );
+ }
+
+ @Test
+ void allowsZeroForEcommerceValues() {
+ matomoRequestBuilder
+ .ecommerceRevenue(0.0)
+ .ecommerceSubtotal(0.0)
+ .ecommerceTax(0.0)
+ .ecommerceShippingCost(0.0)
+ .ecommerceDiscount(0.0);
+
+ whenCreatesQuery();
+
+ assertThat(query)
+ .isEqualTo("idsite=42&" +
+ "token_auth=876de1876fb2cda2816c362a61bfc712&" +
+ "rec=1&" +
+ "apiv=1&" +
+ "_id=112210f47de98115&" +
+ "revenue=0.0&" +
+ "ec_st=0.0&" +
+ "ec_tx=0.0&" +
+ "ec_sh=0.0&" +
+ "ec_dt=0.0&" +
+ "send_image=0&" +
+ "rand=random-value"
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/test/java/org/matomo/java/tracking/TestSender.java b/core/src/test/java/org/matomo/java/tracking/TestSender.java
index 4d4c7465..f000bc8d 100644
--- a/core/src/test/java/org/matomo/java/tracking/TestSender.java
+++ b/core/src/test/java/org/matomo/java/tracking/TestSender.java
@@ -53,7 +53,7 @@ public void sendBulk(
@NonNull
@Override
public CompletableFuture sendBulkAsync(
- @NonNull Iterable extends MatomoRequest> requests, @Nullable String overrideAuthToken
+ @NonNull Collection extends MatomoRequest> requests, @Nullable String overrideAuthToken
) {
for (MatomoRequest request : requests) {
createQueryAndAddRequest(request, overrideAuthToken);
@@ -69,4 +69,8 @@ private void createQueryAndAddRequest(@lombok.NonNull MatomoRequest request, @Nu
requests.add(request);
}
+ @Override
+ public void close() {
+ // do nothing
+ }
}
diff --git a/java11/pom.xml b/java11/pom.xml
index f367934e..fb03eedf 100644
--- a/java11/pom.xml
+++ b/java11/pom.xml
@@ -4,12 +4,12 @@
org.piwik.java.tracking
matomo-java-tracker-parent
- 3.2.2-SNAPSHOT
+ 3.4.1-SNAPSHOT
../pom.xml
matomo-java-tracker-java11
- 3.2.2-SNAPSHOT
+ 3.4.1-SNAPSHOT
jar
Matomo Java Tracker Java 11
@@ -48,7 +48,7 @@
org.wiremock
wiremock
- 3.3.1
+ 3.13.2
test
diff --git a/java11/src/main/java/org/matomo/java/tracking/Java11Sender.java b/java11/src/main/java/org/matomo/java/tracking/Java11Sender.java
index 3daf434f..abb6181f 100644
--- a/java11/src/main/java/org/matomo/java/tracking/Java11Sender.java
+++ b/java11/src/main/java/org/matomo/java/tracking/Java11Sender.java
@@ -17,6 +17,7 @@
import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -39,9 +40,14 @@ public class Java11Sender implements Sender {
@lombok.NonNull
private final CookieStore cookieStore;
+ @lombok.NonNull
+ private final ExecutorService executorService;
+
@NonNull
@Override
- public CompletableFuture sendSingleAsync(@NonNull @lombok.NonNull MatomoRequest request) {
+ public CompletableFuture sendSingleAsync(
+ @NonNull @lombok.NonNull MatomoRequest request
+ ) {
return sendAsyncAndCheckResponse(buildHttpGetRequest(request), request);
}
@@ -51,14 +57,19 @@ public void sendSingle(@NonNull @lombok.NonNull MatomoRequest request) {
}
private void sendAndCheckResponse(@NonNull HttpRequest httpRequest) {
- checkResponse(send(httpRequest, () -> httpClient.send(httpRequest, HttpResponse.BodyHandlers.discarding())),
+ checkResponse(
+ send(
+ httpRequest,
+ () -> httpClient.send(httpRequest, HttpResponse.BodyHandlers.discarding())
+ ),
httpRequest
);
}
@Override
public void sendBulk(
- @NonNull @lombok.NonNull Iterable extends MatomoRequest> requests, @Nullable String overrideAuthToken
+ @NonNull @lombok.NonNull Iterable extends MatomoRequest> requests,
+ @Nullable String overrideAuthToken
) {
sendAndCheckResponse(buildHttpPostRequest(requests, overrideAuthToken));
}
@@ -67,7 +78,8 @@ public void sendBulk(
private HttpRequest buildHttpPostRequest(
@NonNull Iterable extends MatomoRequest> requests, @Nullable String overrideAuthToken
) {
- String authToken = AuthToken.determineAuthToken(overrideAuthToken, requests, trackerConfiguration);
+ String authToken =
+ AuthToken.determineAuthToken(overrideAuthToken, requests, trackerConfiguration);
Collection queries = new ArrayList<>();
Map headers = new LinkedHashMap<>(10);
String headerUserAgent = null;
@@ -103,7 +115,8 @@ private HttpRequest buildHttpPostRequest(
@NonNull
@Override
public CompletableFuture sendBulkAsync(
- @NonNull @lombok.NonNull Iterable extends MatomoRequest> requests, @Nullable String overrideAuthToken
+ @NonNull @lombok.NonNull Collection extends MatomoRequest> requests,
+ @Nullable String overrideAuthToken
) {
return sendAsyncAndCheckResponse(buildHttpPostRequest(requests, overrideAuthToken), null);
}
@@ -112,11 +125,13 @@ public CompletableFuture sendBulkAsync(
private CompletableFuture sendAsyncAndCheckResponse(
@NonNull HttpRequest httpRequest, @Nullable T result
) {
- return send(httpRequest,
- () -> httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.discarding()).thenApply(response -> {
- checkResponse(response, httpRequest);
- return result;
- })
+ return send(
+ httpRequest,
+ () -> httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.discarding())
+ .thenApply(response -> {
+ checkResponse(response, httpRequest);
+ return result;
+ })
);
}
@@ -129,7 +144,8 @@ private HttpRequest buildHttpGetRequest(@NonNull MatomoRequest request) {
URI apiEndpoint = trackerConfiguration.getApiEndpoint();
HttpRequest.Builder builder = HttpRequest
.newBuilder()
- .uri(apiEndpoint.resolve(String.format("%s?%s",
+ .uri(apiEndpoint.resolve(String.format(
+ "%s?%s",
apiEndpoint.getPath(),
queryCreator.createQuery(request, authToken)
)));
@@ -155,12 +171,22 @@ private T send(
}
}
- private void checkResponse(@NonNull HttpResponse response, @NonNull HttpRequest httpRequest) {
+ private void checkResponse(
+ @NonNull HttpResponse response,
+ @NonNull HttpRequest httpRequest
+ ) {
if (response.statusCode() > 399) {
if (trackerConfiguration.isLogFailedTracking()) {
- log.error("Received HTTP error code {} for URL {}", response.statusCode(), httpRequest.uri());
+ log.error(
+ "Received HTTP error code {} for URL {}",
+ response.statusCode(),
+ httpRequest.uri()
+ );
}
- throw new MatomoException(String.format("Tracking endpoint responded with code %d", response.statusCode()));
+ throw new MatomoException(String.format(
+ "Tracking endpoint responded with code %d",
+ response.statusCode()
+ ));
}
}
@@ -176,13 +202,16 @@ private void addCookies(MatomoRequest request) {
}
private void applyTrackerConfiguration(@NonNull HttpRequest.Builder builder) {
- if (trackerConfiguration.getSocketTimeout() != null && trackerConfiguration.getSocketTimeout().toMillis() > 0L) {
+ if (trackerConfiguration.getSocketTimeout() != null
+ && trackerConfiguration.getSocketTimeout().toMillis() > 0L) {
builder.timeout(trackerConfiguration.getSocketTimeout());
}
}
private void setUserAgentHeader(
- HttpRequest.Builder builder, @Nullable String headerUserAgent, @Nullable Map headers
+ HttpRequest.Builder builder,
+ @Nullable String headerUserAgent,
+ @Nullable Map headers
) {
String userAgentHeader = null;
if ((headerUserAgent == null || headerUserAgent.trim().isEmpty()) && headers != null) {
@@ -197,11 +226,19 @@ private void setUserAgentHeader(
}
}
- private void addHeaders(@NonNull HttpRequest.Builder builder, @Nullable Map headers) {
+ private void addHeaders(
+ @NonNull HttpRequest.Builder builder,
+ @Nullable Map headers
+ ) {
if (headers != null) {
for (Map.Entry header : headers.entrySet()) {
builder.header(header.getKey(), header.getValue());
}
}
}
+
+ @Override
+ public void close() {
+ ExecutorServiceCloser.close(executorService);
+ }
}
diff --git a/java11/src/main/java/org/matomo/java/tracking/Java11SenderProvider.java b/java11/src/main/java/org/matomo/java/tracking/Java11SenderProvider.java
index 273ca19f..d6145198 100644
--- a/java11/src/main/java/org/matomo/java/tracking/Java11SenderProvider.java
+++ b/java11/src/main/java/org/matomo/java/tracking/Java11SenderProvider.java
@@ -6,6 +6,7 @@
import java.net.ProxySelector;
import java.net.http.HttpClient;
import java.security.SecureRandom;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
@@ -22,19 +23,25 @@ public Sender provideSender(
TrackerConfiguration trackerConfiguration, QueryCreator queryCreator
) {
CookieManager cookieManager = new CookieManager();
+ ExecutorService executorService = Executors.newFixedThreadPool(
+ trackerConfiguration.getThreadPoolSize(),
+ new DaemonThreadFactory()
+ );
HttpClient.Builder builder = HttpClient
.newBuilder()
.cookieHandler(cookieManager)
- .executor(Executors.newFixedThreadPool(trackerConfiguration.getThreadPoolSize(), new DaemonThreadFactory()))
- ;
- if (trackerConfiguration.getConnectTimeout() != null && trackerConfiguration.getConnectTimeout().toMillis() > 0L) {
+ .executor(executorService);
+ if (trackerConfiguration.getConnectTimeout() != null
+ && trackerConfiguration.getConnectTimeout().toMillis() > 0L) {
builder.connectTimeout(trackerConfiguration.getConnectTimeout());
}
if (!isEmpty(trackerConfiguration.getProxyHost()) && trackerConfiguration.getProxyPort() > 0) {
- builder.proxy(ProxySelector.of(new InetSocketAddress(trackerConfiguration.getProxyHost(),
+ builder.proxy(ProxySelector.of(new InetSocketAddress(
+ trackerConfiguration.getProxyHost(),
trackerConfiguration.getProxyPort()
)));
- if (!isEmpty(trackerConfiguration.getProxyUsername()) && !isEmpty(trackerConfiguration.getProxyPassword())) {
+ if (!isEmpty(trackerConfiguration.getProxyUsername())
+ && !isEmpty(trackerConfiguration.getProxyPassword())) {
builder.authenticator(new ProxyAuthenticator(
trackerConfiguration.getProxyUsername(),
trackerConfiguration.getProxyPassword()
@@ -54,7 +61,13 @@ public Sender provideSender(
throw new MatomoException("Please disable SSL hostname verification manually using the system parameter -Djdk.internal.httpclient.disableHostnameVerification=true");
}
- return new Java11Sender(trackerConfiguration, queryCreator, builder.build(), cookieManager.getCookieStore());
+ return new Java11Sender(
+ trackerConfiguration,
+ queryCreator,
+ builder.build(),
+ cookieManager.getCookieStore(),
+ executorService
+ );
}
private static boolean isEmpty(
diff --git a/java11/src/test/java/org/matomo/java/tracking/Java11SenderIT.java b/java11/src/test/java/org/matomo/java/tracking/Java11SenderIT.java
index cdfef1df..6ce1a63b 100644
--- a/java11/src/test/java/org/matomo/java/tracking/Java11SenderIT.java
+++ b/java11/src/test/java/org/matomo/java/tracking/Java11SenderIT.java
@@ -21,6 +21,7 @@
import java.time.Duration;
import java.util.List;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -45,7 +46,8 @@ void failsIfTrackerConfigurationIsNotSet() {
.apiEndpoint(URI.create("http://localhost"))
.build()),
HttpClient.newBuilder().cookieHandler(cookieManager).build(),
- cookieManager.getCookieStore()
+ cookieManager.getCookieStore(),
+ Executors.newFixedThreadPool(2, new DaemonThreadFactory())
)).isInstanceOf(NullPointerException.class)
.hasMessage("trackerConfiguration is marked non-null but is null");
}
@@ -57,7 +59,8 @@ void failsIfQueryCreatorIsNotSet() {
TrackerConfiguration.builder().apiEndpoint(URI.create("http://localhost")).build(),
null,
HttpClient.newBuilder().cookieHandler(cookieManager).build(),
- cookieManager.getCookieStore()
+ cookieManager.getCookieStore(),
+ Executors.newFixedThreadPool(2, new DaemonThreadFactory())
)).isInstanceOf(NullPointerException.class)
.hasMessage("queryCreator is marked non-null but is null");
}
@@ -71,7 +74,8 @@ void failsIfHttpClientIsNotSet() {
.apiEndpoint(URI.create("http://localhost"))
.build()),
null,
- cookieManager.getCookieStore()
+ cookieManager.getCookieStore(),
+ Executors.newFixedThreadPool(2, new DaemonThreadFactory())
)).isInstanceOf(NullPointerException.class)
.hasMessage("httpClient is marked non-null but is null");
}
@@ -85,7 +89,8 @@ void failsIfCookieStoreIsNotSet() {
.apiEndpoint(URI.create("http://localhost"))
.build()),
HttpClient.newBuilder().cookieHandler(cookieManager).build(),
- null
+ null,
+ Executors.newFixedThreadPool(2, new DaemonThreadFactory())
)).isInstanceOf(NullPointerException.class)
.hasMessage("cookieStore is marked non-null but is null");
}
diff --git a/java8/pom.xml b/java8/pom.xml
index 9c47baae..4b4621ad 100644
--- a/java8/pom.xml
+++ b/java8/pom.xml
@@ -4,12 +4,12 @@
org.piwik.java.tracking
matomo-java-tracker-parent
- 3.2.2-SNAPSHOT
+ 3.4.1-SNAPSHOT
../pom.xml
matomo-java-tracker
- 3.2.2-SNAPSHOT
+ 3.4.1-SNAPSHOT
jar
Matomo Java Tracker Java 8
diff --git a/java8/src/main/java/org/matomo/java/tracking/Java8Sender.java b/java8/src/main/java/org/matomo/java/tracking/Java8Sender.java
index 9b386f89..9aca209c 100644
--- a/java8/src/main/java/org/matomo/java/tracking/Java8Sender.java
+++ b/java8/src/main/java/org/matomo/java/tracking/Java8Sender.java
@@ -27,10 +27,11 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
@@ -59,8 +60,7 @@ class Java8Sender implements Sender {
private final QueryCreator queryCreator;
- private final Executor executor;
- private final Collection queries = new ArrayList<>(16);
+ private final ExecutorService executorService;
@Override
@NonNull
@@ -70,7 +70,7 @@ public CompletableFuture sendSingleAsync(
return CompletableFuture.supplyAsync(() -> {
sendSingle(request);
return request;
- }, executor);
+ }, executorService);
}
@Override
@@ -322,39 +322,37 @@ private static void preparePostConnection(HttpURLConnection connection) {
@Override
@NonNull
public CompletableFuture sendBulkAsync(
- @NonNull Iterable extends MatomoRequest> requests, @Nullable String overrideAuthToken
+ @NonNull Collection extends MatomoRequest> requests, @Nullable String overrideAuthToken
) {
String authToken = AuthToken.determineAuthToken(overrideAuthToken, requests, trackerConfiguration);
Map headers = new LinkedHashMap<>();
String headerUserAgent = findHeaderUserAgent(requests);
String sessionId = findSessionId(requests);
Map cookies = findCookies(requests);
- synchronized (queries) {
- for (MatomoRequest request : requests) {
- RequestValidator.validate(request, authToken);
- if (request.getHeaders() != null && !request.getHeaders().isEmpty()) {
- headers.putAll(request.getHeaders());
- }
- String query = queryCreator.createQuery(request, null);
- queries.add(query);
+ List queries = new ArrayList<>(requests.size());
+ for (MatomoRequest request : requests) {
+ RequestValidator.validate(request, authToken);
+ if (request.getHeaders() != null && !request.getHeaders().isEmpty()) {
+ headers.putAll(request.getHeaders());
}
+ queries.add(queryCreator.createQuery(request, null));
}
return CompletableFuture.supplyAsync(() ->
- sendBulkAsync(authToken, headers, headerUserAgent, sessionId, cookies), executor);
+ sendBulkAsync(queries, authToken, headers, headerUserAgent, sessionId, cookies),
+ executorService);
}
@Nullable
private Void sendBulkAsync(
- @Nullable String authToken, Map headers, String headerUserAgent, String sessionId,
+ List queries,
+ @Nullable String authToken,
+ Map headers,
+ String headerUserAgent,
+ String sessionId,
Map cookies
) {
- synchronized (queries) {
- if (!queries.isEmpty()) {
- sendBulk(queries, authToken, headers, headerUserAgent, sessionId, cookies);
- queries.clear();
- }
- return null;
- }
+ sendBulk(queries, authToken, headers, headerUserAgent, sessionId, cookies);
+ return null;
}
@Nullable
@@ -385,4 +383,8 @@ private Map findCookies(Iterable extends MatomoRequest> reques
return null;
}
+ @Override
+ public void close() {
+ ExecutorServiceCloser.close(executorService);
+ }
}
diff --git a/java8/src/test/java/org/matomo/java/tracking/Java8SenderIT.java b/java8/src/test/java/org/matomo/java/tracking/Java8SenderIT.java
index 4b92535f..dcaeafa4 100644
--- a/java8/src/test/java/org/matomo/java/tracking/Java8SenderIT.java
+++ b/java8/src/test/java/org/matomo/java/tracking/Java8SenderIT.java
@@ -16,6 +16,7 @@
import java.net.MalformedURLException;
import java.net.URI;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -242,7 +243,7 @@ private void givenSender() {
sender = new Java8Sender(
trackerConfiguration,
new QueryCreator(trackerConfiguration),
- Runnable::run
+ Executors.newFixedThreadPool(2, new DaemonThreadFactory())
);
}
diff --git a/java8/src/test/java/org/matomo/java/tracking/MatomoTrackerIT.java b/java8/src/test/java/org/matomo/java/tracking/MatomoTrackerIT.java
index fe8eb7c1..04500061 100644
--- a/java8/src/test/java/org/matomo/java/tracking/MatomoTrackerIT.java
+++ b/java8/src/test/java/org/matomo/java/tracking/MatomoTrackerIT.java
@@ -23,6 +23,7 @@
import java.util.Locale.LanguageRange;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -69,6 +70,13 @@ void givenStub() {
wireMockServer.stubFor(get(urlPathEqualTo("/matomo.php")).willReturn(status(204)));
}
+ @AfterEach
+ void closeTracker() throws Exception {
+ if (matomoTracker != null) {
+ matomoTracker.close();
+ }
+ }
+
@Test
void requiresSiteId() {
diff --git a/pom.xml b/pom.xml
index 247ff62f..f4c62914 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
org.piwik.java.tracking
matomo-java-tracker-parent
- 3.2.2-SNAPSHOT
+ 3.4.1-SNAPSHOT
pom
Matomo Java Tracker Parent
@@ -62,8 +62,8 @@
1.8
1.8
${project.build.outputDirectory}/delombok
- 1.18.30
- 2.0.12
+ 1.18.36
+ 2.0.17
@@ -71,7 +71,7 @@
com.github.spotbugs
spotbugs-annotations
- 4.8.3
+ 4.9.8
provided
@@ -88,13 +88,13 @@
org.junit.jupiter
junit-jupiter
- 5.10.2
+ 5.11.4
test
org.assertj
assertj-core
- 3.25.3
+ 3.27.7
test
@@ -106,7 +106,7 @@
org.eclipse.jetty.ee10
jetty-ee10-servlet
- 12.0.6
+ 12.0.16
@@ -117,52 +117,52 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.12.1
+ 3.15.0
org.apache.maven.plugins
maven-project-info-reports-plugin
- 3.5.0
+ 3.8.0
org.apache.maven.plugins
maven-clean-plugin
- 3.3.2
+ 3.5.0
org.apache.maven.plugins
maven-deploy-plugin
- 3.1.1
+ 3.1.4
org.apache.maven.plugins
maven-install-plugin
- 3.1.1
+ 3.1.3
org.apache.maven.plugins
maven-jar-plugin
- 3.3.0
+ 3.4.2
org.apache.maven.plugins
maven-resources-plugin
- 3.3.1
+ 3.5.0
org.apache.maven.plugins
maven-site-plugin
- 3.12.1
+ 3.21.0
org.apache.maven.plugins
maven-surefire-plugin
- 3.2.5
+ 3.5.5
org.apache.maven.plugins
maven-release-plugin
- 3.0.1
+ 3.3.1
true
false
@@ -174,7 +174,7 @@
org.apache.maven.plugins
maven-gpg-plugin
- 3.1.0
+ 3.2.8
sign-artifacts
@@ -188,7 +188,7 @@
org.sonatype.plugins
nexus-staging-maven-plugin
- 1.6.13
+ 1.7.0
true
ossrh
@@ -202,7 +202,7 @@
org.apache.maven.plugins
maven-failsafe-plugin
- 3.2.5
+ 3.5.5
@@ -215,7 +215,7 @@
org.apache.maven.plugins
maven-source-plugin
- 3.3.0
+ 3.3.1
attach-sources
@@ -253,7 +253,7 @@
org.apache.maven.plugins
maven-javadoc-plugin
- 3.6.3
+ 3.11.2
${delombok.output}
none
@@ -270,7 +270,7 @@
org.apache.maven.plugins
maven-enforcer-plugin
- 3.4.1
+ 3.5.0
enforce-maven
@@ -290,7 +290,7 @@
org.jacoco
jacoco-maven-plugin
- 0.8.11
+ 0.8.14
prepare-agent
@@ -334,7 +334,7 @@
org.apache.maven.plugins
maven-checkstyle-plugin
- 3.3.1
+ 3.6.0
warning
checkstyle.xml
@@ -354,12 +354,12 @@
com.github.spotbugs
spotbugs-maven-plugin
- 4.8.3.1
+ 4.9.8.2
org.owasp
dependency-check-maven
- 9.0.9
+ 12.2.0
true
diff --git a/servlet-jakarta/pom.xml b/servlet-jakarta/pom.xml
index 59d85e5b..0c31328f 100644
--- a/servlet-jakarta/pom.xml
+++ b/servlet-jakarta/pom.xml
@@ -4,12 +4,12 @@
org.piwik.java.tracking
matomo-java-tracker-parent
- 3.2.2-SNAPSHOT
+ 3.4.1-SNAPSHOT
../pom.xml
matomo-java-tracker-servlet-jakarta
- 3.2.2-SNAPSHOT
+ 3.4.1-SNAPSHOT
jar
Matomo Java Tracker Servlet Jakarta
@@ -29,7 +29,7 @@
jakarta.servlet
jakarta.servlet-api
- 6.0.0
+ 6.1.0
provided
@@ -53,7 +53,7 @@
org.eclipse.jetty.ee10
jetty-ee10-servlet
- 12.0.6
+ 12.0.16
test
diff --git a/servlet-jakarta/src/main/java/org/matomo/java/tracking/servlet/MatomoTrackerFilter.java b/servlet-jakarta/src/main/java/org/matomo/java/tracking/servlet/MatomoTrackerFilter.java
index 664ce209..11ca4494 100644
--- a/servlet-jakarta/src/main/java/org/matomo/java/tracking/servlet/MatomoTrackerFilter.java
+++ b/servlet-jakarta/src/main/java/org/matomo/java/tracking/servlet/MatomoTrackerFilter.java
@@ -30,4 +30,15 @@ protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterC
tracker.sendRequestAsync(matomoRequest);
super.doFilter(req, res, chain);
}
+
+ @Override
+ public void destroy() {
+ if (tracker != null) {
+ try {
+ tracker.close();
+ } catch (Exception e) {
+ throw new RuntimeException("Could not close tracker", e);
+ }
+ }
+ }
}
diff --git a/servlet-jakarta/src/test/java/org/matomo/java/tracking/TestSender.java b/servlet-jakarta/src/test/java/org/matomo/java/tracking/TestSender.java
index d6c03833..14f8cde6 100644
--- a/servlet-jakarta/src/test/java/org/matomo/java/tracking/TestSender.java
+++ b/servlet-jakarta/src/test/java/org/matomo/java/tracking/TestSender.java
@@ -46,9 +46,13 @@ public void sendBulk(
@NonNull
@Override
public CompletableFuture sendBulkAsync(
- @NonNull Iterable extends MatomoRequest> requests, @Nullable String overrideAuthToken
+ @NonNull Collection extends MatomoRequest> requests, @Nullable String overrideAuthToken
) {
throw new UnsupportedOperationException();
}
+ @Override
+ public void close() {
+ // Do nothing
+ }
}
diff --git a/servlet-javax/pom.xml b/servlet-javax/pom.xml
index 4fd8bf9d..7e76f0a5 100644
--- a/servlet-javax/pom.xml
+++ b/servlet-javax/pom.xml
@@ -4,12 +4,12 @@
org.piwik.java.tracking
matomo-java-tracker-parent
- 3.2.2-SNAPSHOT
+ 3.4.1-SNAPSHOT
../pom.xml
matomo-java-tracker-servlet-javax
- 3.2.2-SNAPSHOT
+ 3.4.1-SNAPSHOT
jar
Matomo Java Tracker Servlet Javax
@@ -53,7 +53,7 @@
org.eclipse.jetty
jetty-servlet
- 10.0.20
+ 10.0.24
test
diff --git a/servlet-javax/src/test/java/org/matomo/java/tracking/MatomoTrackerFilterIT.java b/servlet-javax/src/test/java/org/matomo/java/tracking/MatomoTrackerFilterIT.java
index 62979d9b..676524c2 100644
--- a/servlet-javax/src/test/java/org/matomo/java/tracking/MatomoTrackerFilterIT.java
+++ b/servlet-javax/src/test/java/org/matomo/java/tracking/MatomoTrackerFilterIT.java
@@ -58,6 +58,8 @@ void sendsAnAsyncRequestOnFilter() throws Exception {
);
});
+ tracker.close();
+
}
}
\ No newline at end of file
diff --git a/servlet-javax/src/test/java/org/matomo/java/tracking/TestSender.java b/servlet-javax/src/test/java/org/matomo/java/tracking/TestSender.java
index d6c03833..0e1704f1 100644
--- a/servlet-javax/src/test/java/org/matomo/java/tracking/TestSender.java
+++ b/servlet-javax/src/test/java/org/matomo/java/tracking/TestSender.java
@@ -46,9 +46,13 @@ public void sendBulk(
@NonNull
@Override
public CompletableFuture sendBulkAsync(
- @NonNull Iterable extends MatomoRequest> requests, @Nullable String overrideAuthToken
+ @NonNull Collection extends MatomoRequest> requests, @Nullable String overrideAuthToken
) {
throw new UnsupportedOperationException();
}
+ @Override
+ public void close() {
+ // do nothing
+ }
}
diff --git a/spring/pom.xml b/spring/pom.xml
index 8adfadc4..c55f8c43 100644
--- a/spring/pom.xml
+++ b/spring/pom.xml
@@ -4,7 +4,7 @@
org.piwik.java.tracking
matomo-java-tracker-parent
- 3.2.2-SNAPSHOT
+ 3.4.1-SNAPSHOT
../pom.xml
@@ -17,7 +17,7 @@
17
17
- 3.2.2
+ 3.4.2
diff --git a/test/pom.xml b/test/pom.xml
index 24aeb628..7a2eb183 100644
--- a/test/pom.xml
+++ b/test/pom.xml
@@ -4,7 +4,7 @@
org.piwik.java.tracking
matomo-java-tracker-parent
- 3.2.2-SNAPSHOT
+ 3.4.1-SNAPSHOT
../pom.xml
@@ -46,7 +46,7 @@
org.eclipse.jetty.ee10
jetty-ee10-servlet
- 12.0.6
+ 12.0.16
diff --git a/test/src/main/java/org/matomo/java/tracking/test/BulkExample.java b/test/src/main/java/org/matomo/java/tracking/test/BulkExample.java
index d674acf2..54f35f92 100644
--- a/test/src/main/java/org/matomo/java/tracking/test/BulkExample.java
+++ b/test/src/main/java/org/matomo/java/tracking/test/BulkExample.java
@@ -26,18 +26,20 @@ public static void main(String[] args) {
.logFailedTracking(true)
.build();
- MatomoTracker tracker = new MatomoTracker(configuration);
-
- VisitorId visitorId = VisitorId.fromString("customer@mail.com");
- tracker.sendBulkRequestAsync(
- MatomoRequests.siteSearch("Running shoes", "Running", 120L)
- .visitorId(visitorId).build(),
- MatomoRequests.pageView("VelocityStride ProX Running Shoes")
- .visitorId(visitorId).build(),
- MatomoRequests.ecommerceOrder("QXZ-789LMP", 100.0, 124.0, 19.0, 10.0, 5.0)
- .visitorId(visitorId)
- .build()
- );
+ try (MatomoTracker tracker = new MatomoTracker(configuration)) {
+ VisitorId visitorId = VisitorId.fromString("customer@mail.com");
+ tracker.sendBulkRequestAsync(
+ MatomoRequests.siteSearch("Running shoes", "Running", 120L)
+ .visitorId(visitorId).build(),
+ MatomoRequests.pageView("VelocityStride ProX Running Shoes")
+ .visitorId(visitorId).build(),
+ MatomoRequests.ecommerceOrder("QXZ-789LMP", 100.0, 124.0, 19.0, 10.0, 5.0)
+ .visitorId(visitorId)
+ .build()
+ );
+ } catch (Exception e) {
+ throw new RuntimeException("Could not close tracker", e);
+ }
}
diff --git a/test/src/main/java/org/matomo/java/tracking/test/ConsumerExample.java b/test/src/main/java/org/matomo/java/tracking/test/ConsumerExample.java
index 3c49b87a..6c37626a 100644
--- a/test/src/main/java/org/matomo/java/tracking/test/ConsumerExample.java
+++ b/test/src/main/java/org/matomo/java/tracking/test/ConsumerExample.java
@@ -27,19 +27,21 @@ public static void main(String[] args) {
.logFailedTracking(true)
.build();
- MatomoTracker tracker = new MatomoTracker(configuration);
-
- MatomoRequest request = MatomoRequests
- .event("Training", "Workout completed", "Bench press", 60.0)
- .visitorId(VisitorId.fromString("customer@mail.com"))
- .build();
-
- tracker.sendRequestAsync(request)
- .thenAccept(req -> System.out.printf("Sent request %s%n", req))
- .exceptionally(throwable -> {
- System.err.printf("Failed to send request: %s%n", throwable.getMessage());
- return null;
- });
+ try (MatomoTracker tracker = new MatomoTracker(configuration)) {
+ MatomoRequest request = MatomoRequests
+ .event("Training", "Workout completed", "Bench press", 60.0)
+ .visitorId(VisitorId.fromString("customer@mail.com"))
+ .build();
+
+ tracker.sendRequestAsync(request)
+ .thenAccept(req -> System.out.printf("Sent request %s%n", req))
+ .exceptionally(throwable -> {
+ System.err.printf("Failed to send request: %s%n", throwable.getMessage());
+ return null;
+ });
+ } catch (Exception e) {
+ throw new RuntimeException("Could not close tracker", e);
+ }
}
diff --git a/test/src/main/java/org/matomo/java/tracking/test/EcommerceExample.java b/test/src/main/java/org/matomo/java/tracking/test/EcommerceExample.java
index 584aa32d..3f16258a 100644
--- a/test/src/main/java/org/matomo/java/tracking/test/EcommerceExample.java
+++ b/test/src/main/java/org/matomo/java/tracking/test/EcommerceExample.java
@@ -28,32 +28,34 @@ public static void main(String[] args) {
.logFailedTracking(true)
.build();
- MatomoTracker tracker = new MatomoTracker(configuration);
-
- tracker.sendBulkRequestAsync(MatomoRequests
- .ecommerceCartUpdate(50.0)
- .ecommerceItems(EcommerceItems
- .builder()
- .item(EcommerceItem
- .builder()
- .sku("XYZ12345")
- .name("Matomo - The big book about web analytics")
- .category("Education & Teaching")
- .price(23.1)
- .quantity(2)
- .build())
- .item(EcommerceItem
- .builder()
- .sku("B0C2WV3MRJ")
- .name("Matomo for data visualization")
- .category("Education & Teaching")
- .price(15.0)
- .quantity(1)
- .build())
- .build())
- .visitorId(VisitorId.fromString("customer@mail.com"))
- .build()
- );
+ try (MatomoTracker tracker = new MatomoTracker(configuration)) {
+ tracker.sendBulkRequestAsync(MatomoRequests
+ .ecommerceCartUpdate(50.0)
+ .ecommerceItems(EcommerceItems
+ .builder()
+ .item(EcommerceItem
+ .builder()
+ .sku("XYZ12345")
+ .name("Matomo - The big book about web analytics")
+ .category("Education & Teaching")
+ .price(23.1)
+ .quantity(2)
+ .build())
+ .item(EcommerceItem
+ .builder()
+ .sku("B0C2WV3MRJ")
+ .name("Matomo for data visualization")
+ .category("Education & Teaching")
+ .price(15.0)
+ .quantity(1)
+ .build())
+ .build())
+ .visitorId(VisitorId.fromString("customer@mail.com"))
+ .build()
+ );
+ } catch (Exception e) {
+ throw new RuntimeException("Could not close tracker", e);
+ }
}
diff --git a/test/src/main/java/org/matomo/java/tracking/test/MatomoTrackerTester.java b/test/src/main/java/org/matomo/java/tracking/test/MatomoTrackerTester.java
index 8255d0ed..8532c370 100644
--- a/test/src/main/java/org/matomo/java/tracking/test/MatomoTrackerTester.java
+++ b/test/src/main/java/org/matomo/java/tracking/test/MatomoTrackerTester.java
@@ -25,7 +25,7 @@
import org.matomo.java.tracking.parameters.VisitorId;
@Slf4j
-class MatomoTrackerTester {
+class MatomoTrackerTester implements AutoCloseable {
private final MatomoTracker tracker;
@@ -39,7 +39,7 @@ class MatomoTrackerTester {
}
}
- public static void main(String[] args) {
+ public static void main(String[] args) throws Exception {
TrackerConfiguration configuration = TrackerConfiguration
.builder()
@@ -49,12 +49,12 @@ public static void main(String[] args) {
.logFailedTracking(true)
.build();
- MatomoTrackerTester matomoTrackerTester = new MatomoTrackerTester(configuration);
-
- matomoTrackerTester.sendRequestAsync();
- matomoTrackerTester.sendBulkRequestsAsync();
- matomoTrackerTester.sendRequest();
- matomoTrackerTester.sendBulkRequests();
+ try (MatomoTrackerTester matomoTrackerTester = new MatomoTrackerTester(configuration)) {
+ matomoTrackerTester.sendRequestAsync();
+ matomoTrackerTester.sendBulkRequestsAsync();
+ matomoTrackerTester.sendRequest();
+ matomoTrackerTester.sendBulkRequests();
+ }
}
@@ -187,4 +187,9 @@ private MatomoRequest randomRequest() {
.debug(true)
.build();
}
+
+ @Override
+ public void close() throws Exception {
+ tracker.close();
+ }
}
diff --git a/test/src/main/java/org/matomo/java/tracking/test/SendExample.java b/test/src/main/java/org/matomo/java/tracking/test/SendExample.java
index 1fe55b3e..d43bcfc3 100644
--- a/test/src/main/java/org/matomo/java/tracking/test/SendExample.java
+++ b/test/src/main/java/org/matomo/java/tracking/test/SendExample.java
@@ -26,13 +26,15 @@ public static void main(String[] args) {
.logFailedTracking(true)
.build();
- MatomoTracker tracker = new MatomoTracker(configuration);
-
- tracker.sendRequestAsync(MatomoRequests
- .event("Training", "Workout completed", "Bench press", 60.0)
- .visitorId(VisitorId.fromString("customer@mail.com"))
- .build()
- );
+ try (MatomoTracker tracker = new MatomoTracker(configuration)) {
+ tracker.sendRequestAsync(MatomoRequests
+ .event("Training", "Workout completed", "Bench press", 60.0)
+ .visitorId(VisitorId.fromString("customer@mail.com"))
+ .build()
+ );
+ } catch (Exception e) {
+ throw new RuntimeException("Could not close tracker", e);
+ }
}
}