Skip to content

Commit e0c677f

Browse files
authored
Merge pull request #322 from hivemq/develop
Release 1.1.2
2 parents f678684 + 70c56fd commit e0c677f

30 files changed

+412
-118
lines changed

README.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
[![Build Status](https://travis-ci.org/hivemq/hivemq-mqtt-client.svg?branch=develop)](https://travis-ci.org/hivemq/hivemq-mqtt-client)
66
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.hivemq/hivemq-mqtt-client/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.hivemq/hivemq-mqtt-client)
7+
[![JitPack](https://jitpack.io/v/hivemq/hivemq-mqtt-client.svg)](https://jitpack.io/#hivemq/hivemq-mqtt-client)
78

89
MQTT 5.0 and 3.1.1 compatible and feature-rich high-performance Java client library with different API flavours and
910
backpressure support.
@@ -46,7 +47,7 @@ If you use Gradle, just include the following inside your `build.gradle` file.
4647

4748
```groovy
4849
dependencies {
49-
compile group: 'com.hivemq', name: 'hivemq-mqtt-client', version: '1.1.1'
50+
compile group: 'com.hivemq', name: 'hivemq-mqtt-client', version: '1.1.2'
5051
}
5152
```
5253

@@ -68,7 +69,7 @@ NOTE: You have to set the compiler version to `1.8` or higher.
6869
<dependency>
6970
<groupId>com.hivemq</groupId>
7071
<artifactId>hivemq-mqtt-client</artifactId>
71-
<version>1.1.1</version>
72+
<version>1.1.2</version>
7273
</dependency>
7374
</dependencies>
7475
...
@@ -85,7 +86,7 @@ To use the shaded version just append `-shaded` to the artifact name.
8586

8687
```groovy
8788
dependencies {
88-
compile group: 'com.hivemq', name: 'hivemq-mqtt-client-shaded', version: '1.1.1'
89+
compile group: 'com.hivemq', name: 'hivemq-mqtt-client-shaded', version: '1.1.2'
8990
}
9091
```
9192

@@ -98,7 +99,7 @@ dependencies {
9899
<dependency>
99100
<groupId>com.hivemq</groupId>
100101
<artifactId>hivemq-mqtt-client-shaded</artifactId>
101-
<version>1.1.1</version>
102+
<version>1.1.2</version>
102103
</dependency>
103104
</dependencies>
104105
...

build.gradle

+29-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
buildscript {
2+
repositories {
3+
mavenCentral()
4+
}
5+
dependencies {
6+
classpath 'biz.aQute.bnd:biz.aQute.bnd.gradle:4.2.0'
7+
}
8+
}
9+
110
plugins {
211
id 'java-library'
312
id 'maven-publish'
@@ -10,25 +19,29 @@ plugins {
1019
id 'com.github.johnrengelman.shadow' version '4.0.4'
1120
id 'com.github.hierynomus.license' version '0.14.0'
1221
id 'pmd'
22+
id 'biz.aQute.bnd.builder' version '4.2.0'
1323
}
1424

1525
group 'com.hivemq'
16-
version '1.1.1' + (Boolean.valueOf(System.getProperty("snapshot")) ? "-SNAPSHOT" : "")
26+
version '1.1.2' + (Boolean.valueOf(System.getProperty("snapshot")) ? "-SNAPSHOT" : "")
1727
description 'HiveMQ MQTT Client is a MQTT 5.0 and MQTT 3.1.1 compatible and feature-rich high-performance Java client ' +
1828
'library with different API flavours and backpressure support'
1929

2030
ext {
31+
moduleName = 'com.hivemq.client.mqtt'
2132
readableName = 'HiveMQ MQTT Client'
2233
githubOrg = 'hivemq'
2334
githubRepo = 'hivemq-mqtt-client'
2435
githubUrl = 'https://github.com/' + githubOrg + '/' + githubRepo
2536
scmConnection = 'scm:git:git://github.com/' + githubOrg + '/' + githubRepo + '.git'
2637
scmDeveloperConnection = 'scm:git:ssh://[email protected]/' + githubOrg + '/' + githubRepo + '.git'
38+
issuesUrl = githubUrl + '/issues'
39+
docUrl = 'https://' + githubOrg + '.github.io/' + githubRepo + '/'
2740
licenseShortName = 'Apache-2.0'
2841
licenseReadableName = 'The Apache License, Version 2.0'
2942
licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
3043
shadedAppendix = 'shaded'
31-
prevVersion = '1.0.1'
44+
prevVersion = '1.1.1'
3245
}
3346

3447
sourceCompatibility = 1.8
@@ -90,6 +103,20 @@ apply from: 'japicc.gradle'
90103

91104
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
92105

106+
jar {
107+
bnd('Automatic-Module-Name': project.moduleName,
108+
'Bundle-Name': project.name,
109+
'Bundle-SymbolicName': project.moduleName,
110+
'Bundle-Description': project.description,
111+
'Bundle-Vendor': 'HiveMQ and the HiveMQ Community',
112+
'Bundle-License': project.licenseShortName + ';description="' + project.licenseReadableName + '";link="' + project.licenseUrl + '"',
113+
'Bundle-DocURL': project.docUrl,
114+
'Bundle-SCM': 'url="' + project.githubUrl + '";connection="' + project.scmConnection + '";developerConnection="' + project.scmDeveloperConnection + '"',
115+
'Export-Package': 'com.hivemq.client.annotations.*, com.hivemq.client.mqtt.*, com.hivemq.client.rx.*, com.hivemq.client.util.*',
116+
'-consumer-policy': '${range;[==,=+)}',
117+
'-removeheaders': 'Private-Package')
118+
}
119+
93120
shadowJar { ShadowJar shadowJar ->
94121
appendix shadedAppendix
95122
classifier null

publishing.gradle

+8-4
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ void addPom(MavenPublication publication) {
8282
developerConnection = project.scmDeveloperConnection
8383
url = project.githubUrl
8484
}
85+
issueManagement {
86+
system = 'github'
87+
url = project.issuesUrl
88+
}
8589
}
8690
}
8791

@@ -124,10 +128,10 @@ bintray {
124128
repo = 'HiveMQ'
125129
name = 'hivemq-mqtt-client'
126130
desc = project.description
127-
websiteUrl = githubUrl
128-
issueTrackerUrl = githubUrl + '/issues'
129-
vcsUrl = githubUrl + '.git'
130-
licenses = [licenseShortName]
131+
websiteUrl = project.githubUrl
132+
issueTrackerUrl = project.issuesUrl
133+
vcsUrl = project.githubUrl + '.git'
134+
licenses = [project.licenseShortName]
131135
labels = ['mqtt', 'mqtt-client', 'iot', 'internet-of-things', 'rxjava2', 'reactive-streams', 'backpressure']
132136
version {
133137
released = new Date()

src/main/java/com/hivemq/client/internal/mqtt/MqttAsyncClient.java

+51-13
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,54 @@
4646
import java.util.concurrent.CompletableFuture;
4747
import java.util.concurrent.Executor;
4848
import java.util.function.Consumer;
49-
import java.util.function.Function;
5049

5150
/**
5251
* @author Silvio Giebl
5352
*/
5453
public class MqttAsyncClient implements Mqtt5AsyncClient {
5554

56-
private static final @NotNull Function<Mqtt5SubAck, Mqtt5SubAck> SUBACK_HANDLER = MqttBlockingClient::handleSubAck;
57-
private static final @NotNull Function<Mqtt5UnsubAck, Mqtt5UnsubAck> UNSUBACK_HANDLER =
58-
MqttBlockingClient::handleUnsubAck;
55+
private static @NotNull CompletableFuture<@NotNull Mqtt5SubAck> handleSubAck(
56+
final @NotNull CompletableFuture<@NotNull Mqtt5SubAck> future, final @NotNull MqttSubscribe subscribe) {
57+
58+
if (subscribe.getSubscriptions().size() == 1) {
59+
return future;
60+
}
61+
final CompletableFuture<Mqtt5SubAck> mappedFuture = new CompletableFuture<>();
62+
future.whenComplete((subAck, throwable) -> {
63+
if (throwable != null) {
64+
mappedFuture.completeExceptionally(throwable);
65+
} else {
66+
try {
67+
mappedFuture.complete(MqttBlockingClient.handleSubAck(subAck));
68+
} catch (final Throwable t) {
69+
mappedFuture.completeExceptionally(t);
70+
}
71+
}
72+
});
73+
return mappedFuture;
74+
}
75+
76+
private static @NotNull CompletableFuture<@NotNull Mqtt5UnsubAck> handleUnsubAck(
77+
final @NotNull CompletableFuture<@NotNull Mqtt5UnsubAck> future,
78+
final @NotNull MqttUnsubscribe unsubscribe) {
79+
80+
if (unsubscribe.getTopicFilters().size() == 1) {
81+
return future;
82+
}
83+
final CompletableFuture<Mqtt5UnsubAck> mappedFuture = new CompletableFuture<>();
84+
future.whenComplete((unsubAck, throwable) -> {
85+
if (throwable != null) {
86+
mappedFuture.completeExceptionally(throwable);
87+
} else {
88+
try {
89+
mappedFuture.complete(MqttBlockingClient.handleUnsubAck(unsubAck));
90+
} catch (final Throwable t) {
91+
mappedFuture.completeExceptionally(t);
92+
}
93+
}
94+
});
95+
return mappedFuture;
96+
}
5997

6098
private final @NotNull MqttRxClient delegate;
6199

@@ -74,7 +112,7 @@ public class MqttAsyncClient implements Mqtt5AsyncClient {
74112
public @NotNull CompletableFuture<@NotNull Mqtt5SubAck> subscribe(final @Nullable Mqtt5Subscribe subscribe) {
75113
final MqttSubscribe mqttSubscribe = MqttChecks.subscribe(subscribe);
76114

77-
return RxFutureConverter.toFuture(delegate.subscribe(mqttSubscribe)).thenApply(SUBACK_HANDLER);
115+
return handleSubAck(RxFutureConverter.toFuture(delegate.subscribe(mqttSubscribe)), mqttSubscribe);
78116
}
79117

80118
@Override
@@ -84,9 +122,9 @@ public class MqttAsyncClient implements Mqtt5AsyncClient {
84122
final MqttSubscribe mqttSubscribe = MqttChecks.subscribe(subscribe);
85123
Checks.notNull(callback, "Callback");
86124

87-
return delegate.subscribeStream(mqttSubscribe)
88-
.subscribeSingleFuture(new CallbackSubscriber(callback))
89-
.thenApply(SUBACK_HANDLER);
125+
return handleSubAck(
126+
delegate.subscribeStream(mqttSubscribe).subscribeSingleFuture(new CallbackSubscriber(callback)),
127+
mqttSubscribe);
90128
}
91129

92130
@Override
@@ -98,10 +136,10 @@ public class MqttAsyncClient implements Mqtt5AsyncClient {
98136
Checks.notNull(callback, "Callback");
99137
Checks.notNull(executor, "Executor");
100138

101-
return delegate.subscribeStreamUnsafe(mqttSubscribe)
102-
.observeOnBoth(Schedulers.from(executor), true)
103-
.subscribeSingleFuture(new CallbackSubscriber(callback))
104-
.thenApply(SUBACK_HANDLER);
139+
return handleSubAck(
140+
delegate.subscribeStreamUnsafe(mqttSubscribe)
141+
.observeOnBoth(Schedulers.from(executor), true).subscribeSingleFuture(new CallbackSubscriber(callback)),
142+
mqttSubscribe);
105143
}
106144

107145
@Override
@@ -134,7 +172,7 @@ public void publishes(
134172

135173
final MqttUnsubscribe mqttUnsubscribe = MqttChecks.unsubscribe(unsubscribe);
136174

137-
return RxFutureConverter.toFuture(delegate.unsubscribe(mqttUnsubscribe)).thenApply(UNSUBACK_HANDLER);
175+
return handleUnsubAck(RxFutureConverter.toFuture(delegate.unsubscribe(mqttUnsubscribe)), mqttUnsubscribe);
138176
}
139177

140178
@Override

src/main/java/com/hivemq/client/internal/mqtt/MqttBlockingClient.java

+22-20
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ private static class MqttPublishes implements Mqtt5Publishes, FlowableSubscriber
168168
private final @NotNull AtomicReference<@Nullable Subscription> subscription = new AtomicReference<>();
169169
private final @NotNull LinkedList<Entry> entries = new LinkedList<>();
170170
private @Nullable Mqtt5Publish queuedPublish;
171-
private boolean cancelled;
171+
private @Nullable Throwable error;
172172

173173
MqttPublishes(final @NotNull Flowable<Mqtt5Publish> publishes) {
174174
publishes.subscribe(this);
@@ -192,7 +192,7 @@ private void request() {
192192
@Override
193193
public void onNext(final @NotNull Mqtt5Publish publish) {
194194
synchronized (entries) {
195-
if (cancelled) {
195+
if (error != null) {
196196
return;
197197
}
198198
Entry entry;
@@ -216,9 +216,10 @@ public void onComplete() {
216216
@Override
217217
public void onError(final @NotNull Throwable t) {
218218
synchronized (entries) {
219-
if (cancelled) {
219+
if (error != null) {
220220
return;
221221
}
222+
error = t;
222223
Entry entry;
223224
while ((entry = entries.poll()) != null) {
224225
entry.result.set(t);
@@ -231,8 +232,8 @@ public void onError(final @NotNull Throwable t) {
231232
public @NotNull Mqtt5Publish receive() throws InterruptedException {
232233
final Entry entry;
233234
synchronized (entries) {
234-
if (cancelled) {
235-
throw new CancellationException();
235+
if (error != null) {
236+
throw handleError(error);
236237
}
237238
final Mqtt5Publish publish = receiveNowUnsafe();
238239
if (publish != null) {
@@ -253,10 +254,7 @@ public void onError(final @NotNull Throwable t) {
253254
return (Mqtt5Publish) result;
254255
}
255256
if (result instanceof Throwable) {
256-
if (result instanceof RuntimeException) {
257-
throw AsyncRuntimeException.fillInStackTrace((RuntimeException) result);
258-
}
259-
throw new RuntimeException((Throwable) result);
257+
throw handleError((Throwable) result);
260258
}
261259
if (interruptedException != null) {
262260
throw interruptedException;
@@ -275,8 +273,8 @@ public void onError(final @NotNull Throwable t) {
275273

276274
final Entry entry;
277275
synchronized (entries) {
278-
if (cancelled) {
279-
throw new CancellationException();
276+
if (error != null) {
277+
throw handleError(error);
280278
}
281279
final Mqtt5Publish publish = receiveNowUnsafe();
282280
if (publish != null) {
@@ -297,10 +295,7 @@ public void onError(final @NotNull Throwable t) {
297295
return Optional.of((Mqtt5Publish) result);
298296
}
299297
if (result instanceof Throwable) {
300-
if (result instanceof RuntimeException) {
301-
throw AsyncRuntimeException.fillInStackTrace((RuntimeException) result);
302-
}
303-
throw new RuntimeException((Throwable) result);
298+
throw handleError((Throwable) result);
304299
}
305300
if (interruptedException != null) {
306301
throw interruptedException;
@@ -312,8 +307,8 @@ public void onError(final @NotNull Throwable t) {
312307
public @NotNull Optional<Mqtt5Publish> receiveNow() {
313308
final Mqtt5Publish publish;
314309
synchronized (entries) {
315-
if (cancelled) {
316-
throw new CancellationException();
310+
if (error != null) {
311+
throw handleError(error);
317312
}
318313
publish = receiveNowUnsafe();
319314
}
@@ -337,18 +332,25 @@ public void close() {
337332
subscription.cancel();
338333
}
339334
synchronized (entries) {
340-
if (cancelled) {
335+
if (error != null) {
341336
return;
342337
}
343-
cancelled = true;
338+
error = new CancellationException();
344339
Entry entry;
345340
while ((entry = entries.poll()) != null) {
346-
entry.result.set(new CancellationException());
341+
entry.result.set(error);
347342
entry.latch.countDown();
348343
}
349344
}
350345
}
351346

347+
private @NotNull RuntimeException handleError(final @NotNull Throwable t) {
348+
if (t instanceof RuntimeException) {
349+
return AsyncRuntimeException.fillInStackTrace((RuntimeException) t);
350+
}
351+
throw new RuntimeException(t);
352+
}
353+
352354
private static class Entry {
353355

354356
static final @NotNull Object CANCELLED = new Object();

0 commit comments

Comments
 (0)