diff --git a/README.md b/README.md
index b916ff05..ec5b610c 100644
--- a/README.md
+++ b/README.md
@@ -93,7 +93,7 @@ mvn clean
Have a fantastic feature idea? Spot a bug? We would absolutely love for you to contribute to this project! Please feel free to:
* Fork this project
-* Create a feature branch from the dev branch
+* Create a feature branch from the master branch
* Write awesome code that does awesome things
* Write awesome test to test your awesome code
* Verify that everything is working as it should by running mvn test. If everything passes, you may want to make sure that your tests are covering everything you think they are! Run mvn org.pitest:pitest-maven:mutationCoverage to find out!
diff --git a/src/main/java/org/piwik/java/tracking/PiwikTracker.java b/src/main/java/org/piwik/java/tracking/PiwikTracker.java
index 57857562..a0ec1201 100644
--- a/src/main/java/org/piwik/java/tracking/PiwikTracker.java
+++ b/src/main/java/org/piwik/java/tracking/PiwikTracker.java
@@ -18,6 +18,7 @@
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.concurrent.FutureCallback;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
@@ -112,6 +113,17 @@ public HttpResponse sendRequest(final PiwikRequest request) throws IOException {
* @throws IOException thrown if there was a problem with this connection
*/
public Future sendRequestAsync(final PiwikRequest request) throws IOException {
+ return sendRequestAsync(request, null);
+ }
+ /**
+ * Send a request.
+ *
+ * @param request request to send
+ * @param callback callback that gets executed when response arrives
+ * @return future with response from this request
+ * @throws IOException thrown if there was a problem with this connection
+ */
+ public Future sendRequestAsync(final PiwikRequest request, FutureCallback callback) throws IOException {
final CloseableHttpAsyncClient client = getHttpAsyncClient();
client.start();
uriBuilder.setCustomQuery(request.getQueryString());
@@ -119,7 +131,7 @@ public Future sendRequestAsync(final PiwikRequest request) throws
try {
get = new HttpGet(uriBuilder.build());
- return client.execute(get, null);
+ return client.execute(get, callback);
} catch (final URISyntaxException e) {
throw new IOException(e);
}
@@ -148,7 +160,20 @@ public HttpResponse sendBulkRequest(final Iterable requests) throw
* @throws IOException thrown if there was a problem with this connection
*/
public Future sendBulkRequestAsync(final Iterable requests) throws IOException {
- return sendBulkRequestAsync(requests, null);
+ return sendBulkRequestAsync(requests, null, null);
+ }
+
+ /**
+ * Send multiple requests in a single HTTP call. More efficient than sending
+ * several individual requests.
+ *
+ * @param requests the requests to send
+ * @param callback callback that gets executed when response arrives
+ * @return future with response from these requests
+ * @throws IOException thrown if there was a problem with this connection
+ */
+ public Future sendBulkRequestAsync(final Iterable requests, FutureCallback callback) throws IOException {
+ return sendBulkRequestAsync(requests, null, callback);
}
/**
@@ -205,6 +230,22 @@ public HttpResponse sendBulkRequest(final Iterable requests, final
* @throws IOException thrown if there was a problem with this connection
*/
public Future sendBulkRequestAsync(final Iterable requests, final String authToken) throws IOException {
+ return sendBulkRequestAsync(requests, authToken, null);
+ }
+
+ /**
+ * Send multiple requests in a single HTTP call. More efficient than sending
+ * several individual requests. Specify the AuthToken if parameters that require
+ * an auth token is used.
+ *
+ * @param requests the requests to send
+ * @param authToken specify if any of the parameters use require AuthToken
+ * @param callback callback that gets executed when response arrives
+ * @return the response from these requests
+ * @throws IOException thrown if there was a problem with this connection
+ */
+ public Future sendBulkRequestAsync(final Iterable requests, final String authToken,
+ FutureCallback callback) throws IOException {
if (authToken != null && authToken.length() != PiwikRequest.AUTH_TOKEN_LENGTH) {
throw new IllegalArgumentException(authToken + " is not " + PiwikRequest.AUTH_TOKEN_LENGTH + " characters long.");
}
@@ -230,7 +271,7 @@ public Future sendBulkRequestAsync(final Iterable re
post = new HttpPost(uriBuilder.build());
post.setEntity(new StringEntity(ob.build().toString(),
ContentType.APPLICATION_JSON));
- return client.execute(post, null);
+ return client.execute(post, callback);
} catch (final URISyntaxException e) {
throw new IOException(e);
}
diff --git a/src/test/java/org/piwik/java/tracking/PiwikTrackerTest.java b/src/test/java/org/piwik/java/tracking/PiwikTrackerTest.java
index e812fe20..0cdaa39b 100644
--- a/src/test/java/org/piwik/java/tracking/PiwikTrackerTest.java
+++ b/src/test/java/org/piwik/java/tracking/PiwikTrackerTest.java
@@ -13,6 +13,7 @@
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
+import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.util.EntityUtils;
import org.junit.After;
@@ -30,11 +31,10 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.Future;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.doReturn;
@@ -173,6 +173,57 @@ public void testWithLocalServerAsync() throws Exception {
assertEquals("OK", msgBulk);
}
+ /**
+ * Test async API with local server
+ */
+ @Test
+ public void testWithLocalServerAsyncCallback() throws Exception {
+ CountDownLatch latch = new CountDownLatch(2);
+ BlockingQueue responses = new LinkedBlockingQueue<>();
+ BlockingQueue exceptions = new LinkedBlockingQueue<>();
+ AtomicInteger cancelled = new AtomicInteger();
+
+ FutureCallback cb = new FutureCallback() {
+
+ @Override
+ public void completed(HttpResponse httpResponse) {
+ responses.add(httpResponse);
+ latch.countDown();
+ }
+
+ @Override
+ public void failed(Exception e) {
+ exceptions.add(e);
+ latch.countDown();
+ }
+
+ @Override
+ public void cancelled() {
+ cancelled.incrementAndGet();
+ latch.countDown();
+
+ }
+ };
+
+ // one
+ PiwikRequest request = new PiwikRequest(3, new URL("http://test.com"));
+ Future respFuture = localTracker.sendRequestAsync(request, cb);
+ // bulk
+ List requests = Collections.singletonList(request);
+ Future bulkFuture = localTracker.sendBulkRequestAsync(requests, cb);
+
+ assertTrue("Responses not received", latch.await(100, TimeUnit.MILLISECONDS));
+ assertEquals("Not expecting cancelled responses", 0, cancelled.get());
+ assertEquals("Not expecting exceptions", exceptions.size(), 0);
+ assertTrue("Single response future not done", respFuture.isDone());
+ assertTrue("Bulk response future not done", bulkFuture.isDone());
+ HttpResponse response = responses.poll(1, TimeUnit.MILLISECONDS);
+ assertEquals("OK", EntityUtils.toString(response.getEntity()));
+
+ HttpResponse bulkResponse = responses.poll(1, TimeUnit.MILLISECONDS);
+ assertEquals("OK", EntityUtils.toString(bulkResponse.getEntity()));
+ }
+
static class CorrectGetRequest implements ArgumentMatcher {
String url;
@@ -262,7 +313,7 @@ public void testSendBulkRequestAsync_Iterable() throws Exception {
doReturn(response).when(future).get();
doReturn(true).when(future).isDone();
- doReturn(future).when(piwikTracker).sendBulkRequestAsync(requests, null);
+ doReturn(future).when(piwikTracker).sendBulkRequestAsync(requests);
assertEquals(response, piwikTracker.sendBulkRequestAsync(requests).get());
}
@@ -304,7 +355,7 @@ public void testSendBulkRequestAsync_Iterable_StringFF() throws Exception {
doReturn(future).when(client)
.execute(argThat(new CorrectPostRequest("{\"requests\":[\"?query\"]}")), any());
- assertEquals(response, piwikTracker.sendBulkRequestAsync(requests, null).get());
+ assertEquals(response, piwikTracker.sendBulkRequestAsync(requests).get());
}
@Test