Skip to content

Commit ccb9b01

Browse files
authoredApr 8, 2021
Merge pull request #480 from hivemq/develop
Release 1.2.2
2 parents 3f1c055 + 6428df1 commit ccb9b01

24 files changed

+293
-223
lines changed
 

‎.gitignore

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
# Gradle
12
.gradle
2-
out/
33
build/
44

5+
# IntelliJ
6+
out/
57
*.iml
68
.idea/*
79
!.idea/codeStyles
810
!.idea/inspectionProfiles
11+
!.idea/runConfigurations
912

10-
.DS_Store
1113
.java-version
12-
credentials.gradle
13-
bintray.gradle
14+
.DS_Store

‎.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
include:
1919
- stage: release
2020
install: skip
21-
script: ./gradlew bintrayUpload githubRelease
21+
script: ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository githubRelease
2222
jdk: oraclejdk8
2323

2424
addons:

‎README.md

+30-23
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
[![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)
88
[![JitPack](https://jitpack.io/v/hivemq/hivemq-mqtt-client.svg)](https://jitpack.io/#hivemq/hivemq-mqtt-client)
9+
[![javadoc](https://javadoc.io/badge2/com.hivemq/hivemq-mqtt-client/javadoc.svg)](https://javadoc.io/doc/com.hivemq/hivemq-mqtt-client)
910
[![Build Status](https://travis-ci.com/hivemq/hivemq-mqtt-client.svg?branch=develop)](https://travis-ci.com/hivemq/hivemq-mqtt-client)
1011
[![Language grade: Java](https://img.shields.io/lgtm/grade/java/g/hivemq/hivemq-mqtt-client.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/hivemq/hivemq-mqtt-client/context:java)
1112
[![Total alerts](https://img.shields.io/lgtm/alerts/g/hivemq/hivemq-mqtt-client.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/hivemq/hivemq-mqtt-client/alerts/)
@@ -79,7 +80,13 @@ backpressure support.
7980
<img src="https://avatars3.githubusercontent.com/u/11352045?s=200&v=4" alt="Open Smart Grid Platform" height="60px"/>
8081
](https://github.com/OSGP/open-smart-grid-platform) &nbsp;&nbsp; [
8182
<img src="https://raw.githubusercontent.com/EXXETA/correomqtt/develop/icon/ico/Icon_128x128.png" alt="CorreoMQTT" height="60px"/>
82-
](https://github.com/EXXETA/correomqtt)
83+
](https://github.com/EXXETA/correomqtt) &nbsp;&nbsp; [
84+
<img src="https://avatars.githubusercontent.com/u/32634858?s=200&v=4" alt="HiveMQ Spring Boot Starter" height="60px"/>
85+
](https://github.com/SmartsquareGmbH/mqtt-starter) &nbsp;&nbsp; [
86+
<img src="https://avatars.githubusercontent.com/u/16953511?s=200&v=4" alt="HiveMQ Spring Boot Starter" height="60px"/>
87+
](https://www.openmuc.org/) &nbsp;&nbsp; [
88+
<img src="https://avatars.githubusercontent.com/u/20456341?s=200&v=4" alt="HiveMQ Spring Boot Starter" height="60px"/>
89+
](https://github.com/leftshiftone/gaia-sdk)
8390

8491
If you use the HiveMQ MQTT Client in a project that is not listed here, feel free to open an issue or pull request.
8592

@@ -91,22 +98,22 @@ Java 8 or higher is required.
9198

9299
#### Gradle
93100

94-
If you use Gradle, just include the following inside your `build.gradle` file.
101+
If you use Gradle, just include the following inside your `build.gradle(.kts)` file.
95102

96103
```groovy
97104
dependencies {
98-
implementation group: 'com.hivemq', name: 'hivemq-mqtt-client', version: '1.2.0'
105+
implementation("com.hivemq:hivemq-mqtt-client:1.2.2")
99106
}
100107
```
101108

102109
For optional features you can choose to include additional modules:
103110

104111
```groovy
105112
dependencies {
106-
implementation group: 'com.hivemq', name: 'hivemq-mqtt-client-websocket', version: '1.2.0'
107-
implementation group: 'com.hivemq', name: 'hivemq-mqtt-client-proxy', version: '1.2.0'
108-
implementation group: 'com.hivemq', name: 'hivemq-mqtt-client-epoll', version: '1.2.0'
109-
implementation group: 'com.hivemq', name: 'hivemq-mqtt-client-reactor', version: '1.2.0'
113+
implementation(platform("com.hivemq:hivemq-mqtt-client-websocket:1.2.2"))
114+
implementation(platform("com.hivemq:hivemq-mqtt-client-proxy:1.2.2"))
115+
implementation(platform("com.hivemq:hivemq-mqtt-client-epoll:1.2.2"))
116+
implementation("com.hivemq:hivemq-mqtt-client-reactor:1.2.2")
110117
}
111118
```
112119

@@ -121,7 +128,7 @@ If you use Maven, just include the following inside your `pom.xml` file.
121128
<dependency>
122129
<groupId>com.hivemq</groupId>
123130
<artifactId>hivemq-mqtt-client</artifactId>
124-
<version>1.2.0</version>
131+
<version>1.2.2</version>
125132
</dependency>
126133
</dependencies>
127134
...
@@ -150,31 +157,31 @@ For optional features you can choose to include additional modules:
150157
<dependency>
151158
<groupId>com.hivemq</groupId>
152159
<artifactId>hivemq-mqtt-client-websocket</artifactId>
153-
<version>1.2.0</version>
160+
<version>1.2.2</version>
154161
<type>pom</type>
155162
</dependency>
156163
</dependencies>
157164
<dependencies>
158165
<dependency>
159166
<groupId>com.hivemq</groupId>
160167
<artifactId>hivemq-mqtt-client-proxy</artifactId>
161-
<version>1.2.0</version>
168+
<version>1.2.2</version>
162169
<type>pom</type>
163170
</dependency>
164171
</dependencies>
165172
<dependencies>
166173
<dependency>
167174
<groupId>com.hivemq</groupId>
168175
<artifactId>hivemq-mqtt-client-epoll</artifactId>
169-
<version>1.2.0</version>
176+
<version>1.2.2</version>
170177
<type>pom</type>
171178
</dependency>
172179
</dependencies>
173180
<dependencies>
174181
<dependency>
175182
<groupId>com.hivemq</groupId>
176183
<artifactId>hivemq-mqtt-client-reactor</artifactId>
177-
<version>1.2.0</version>
184+
<version>1.2.2</version>
178185
</dependency>
179186
</dependencies>
180187
...
@@ -192,7 +199,7 @@ To use the shaded version just append `-shaded` to the artifact name.
192199

193200
```groovy
194201
dependencies {
195-
implementation group: 'com.hivemq', name: 'hivemq-mqtt-client-shaded', version: '1.2.0'
202+
implementation("com.hivemq:hivemq-mqtt-client-shaded:1.2.2")
196203
}
197204
```
198205

@@ -205,7 +212,7 @@ dependencies {
205212
<dependency>
206213
<groupId>com.hivemq</groupId>
207214
<artifactId>hivemq-mqtt-client-shaded</artifactId>
208-
<version>1.2.0</version>
215+
<version>1.2.2</version>
209216
</dependency>
210217
</dependencies>
211218
...
@@ -220,18 +227,18 @@ Snapshots can be obtained using [JitPack](https://jitpack.io/#hivemq/hivemq-mqtt
220227

221228
```groovy
222229
repositories {
223-
...
224-
maven { url 'https://jitpack.io' }
230+
...
231+
maven { url 'https://jitpack.io' }
225232
}
226233
227234
dependencies {
228-
implementation 'com.github.hivemq.hivemq-mqtt-client:hivemq-mqtt-client:develop-SNAPSHOT'
229-
230-
// snapshots for optional modules
231-
implementation 'com.github.hivemq.hivemq-mqtt-client:hivemq-mqtt-client-websocket:develop-SNAPSHOT'
232-
implementation 'com.github.hivemq.hivemq-mqtt-client:hivemq-mqtt-client-proxy:develop-SNAPSHOT'
233-
implementation 'com.github.hivemq.hivemq-mqtt-client:hivemq-mqtt-client-epoll:develop-SNAPSHOT'
234-
implementation 'com.github.hivemq.hivemq-mqtt-client:hivemq-mqtt-client-reactor:develop-SNAPSHOT'
235+
implementation("com.github.hivemq.hivemq-mqtt-client:hivemq-mqtt-client:develop-SNAPSHOT")
236+
237+
// snapshots for optional modules
238+
implementation(platform("com.github.hivemq.hivemq-mqtt-client:hivemq-mqtt-client-websocket:develop-SNAPSHOT"))
239+
implementation(platform("com.github.hivemq.hivemq-mqtt-client:hivemq-mqtt-client-proxy:develop-SNAPSHOT"))
240+
implementation(platform("com.github.hivemq.hivemq-mqtt-client:hivemq-mqtt-client-epoll:develop-SNAPSHOT"))
241+
implementation("com.github.hivemq.hivemq-mqtt-client:hivemq-mqtt-client-reactor:develop-SNAPSHOT")
235242
}
236243
```
237244

‎build.gradle.kts

+49-86
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import java.util.*
2-
31
plugins {
42
id("java-library")
53
id("com.github.johnrengelman.shadow")
64
id("biz.aQute.bnd.builder")
75
id("maven-publish")
8-
id("com.jfrog.bintray")
6+
id("io.github.gradle-nexus.publish-plugin")
7+
id("signing")
98
id("com.github.breadmoirai.github-release")
109
id("com.github.hierynomus.license")
1110
id("pmd")
@@ -25,25 +24,25 @@ allprojects {
2524
plugins.apply("com.github.sgtsilvio.gradle.metadata")
2625

2726
metadata {
28-
moduleName = "com.hivemq.client.mqtt"
29-
readableName = "HiveMQ MQTT Client"
27+
moduleName.set("com.hivemq.client.mqtt")
28+
readableName.set("HiveMQ MQTT Client")
3029
organization {
31-
name = "HiveMQ and the HiveMQ Community"
32-
url = "https://www.hivemq.com/"
30+
name.set("HiveMQ and the HiveMQ Community")
31+
url.set("https://www.hivemq.com/")
3332
}
3433
license {
3534
apache2()
3635
}
3736
developers {
3837
developer {
39-
id = "SgtSilvio"
40-
name = "Silvio Giebl"
41-
email = "silvio.giebl@hivemq.com"
38+
id.set("SgtSilvio")
39+
name.set("Silvio Giebl")
40+
email.set("silvio.giebl@hivemq.com")
4241
}
4342
}
4443
github {
45-
org = "hivemq"
46-
repo = "hivemq-mqtt-client"
44+
org.set("hivemq")
45+
repo.set("hivemq-mqtt-client")
4746
pages()
4847
issues()
4948
}
@@ -67,12 +66,6 @@ allprojects {
6766

6867
/* ******************** dependencies ******************** */
6968

70-
allprojects {
71-
repositories {
72-
mavenCentral()
73-
}
74-
}
75-
7669
dependencies {
7770
api("io.reactivex.rxjava2:rxjava:${property("rxjava.version")}")
7871
api("org.reactivestreams:reactive-streams:${property("reactive-streams.version")}")
@@ -94,8 +87,8 @@ dependencies {
9487

9588
/* ******************** optional dependencies ******************** */
9689

97-
listOf("websocket", "proxy", "epoll").forEach {
98-
java.registerFeature(it) {
90+
for (feature in listOf("websocket", "proxy", "epoll")) {
91+
java.registerFeature(feature) {
9992
usingSourceSet(sourceSets["main"])
10093
}
10194
}
@@ -120,7 +113,7 @@ allprojects {
120113
tasks.test {
121114
useJUnitPlatform()
122115
maxHeapSize = "1g"
123-
maxParallelForks = Runtime.getRuntime().availableProcessors()
116+
maxParallelForks = 1.coerceAtLeast(Runtime.getRuntime().availableProcessors() / 2)
124117
jvmArgs("-XX:+UseParallelGC")
125118
}
126119
}
@@ -177,12 +170,10 @@ tasks.shadowJar {
177170
archiveAppendix.set("shaded")
178171
archiveClassifier.set("")
179172

180-
configurations = listOf(project.run {
181-
configurations.create("shaded") {
182-
extendsFrom(configurations["runtimeClasspath"])
183-
configurations["apiElements"].allDependencies.forEach {
184-
exclude(it.group, it.name)
185-
}
173+
configurations = listOf(project.configurations.create("shaded") {
174+
extendsFrom(project.configurations["runtimeClasspath"])
175+
for (apiDependency in project.configurations["apiElements"].allDependencies) {
176+
exclude(apiDependency.group, apiDependency.name)
186177
}
187178
})
188179

@@ -202,8 +193,6 @@ tasks.shadowJar {
202193

203194
/* ******************** publishing ******************** */
204195

205-
apply("${rootDir}/gradle/publishing.gradle.kts")
206-
207196
allprojects {
208197
plugins.withId("java-library") {
209198

@@ -233,11 +222,11 @@ publishing.publications.register<MavenPublication>("shaded") {
233222
artifact(tasks["sourcesJar"])
234223
pom.withXml {
235224
asNode().appendNode("dependencies").apply {
236-
configurations["apiElements"].allDependencies.forEach {
225+
for (apiDependency in configurations["apiElements"].allDependencies) {
237226
appendNode("dependency").apply {
238-
appendNode("groupId", it.group)
239-
appendNode("artifactId", it.name)
240-
appendNode("version", it.version)
227+
appendNode("groupId", apiDependency.group)
228+
appendNode("artifactId", apiDependency.name)
229+
appendNode("version", apiDependency.version)
241230
appendNode("scope", "compile")
242231
}
243232
}
@@ -247,18 +236,14 @@ publishing.publications.register<MavenPublication>("shaded") {
247236

248237
allprojects {
249238
plugins.withId("maven-publish") {
250-
afterEvaluate {
251-
publishing.publications.withType<MavenPublication>().configureEach {
252-
pom.withXml {
253-
(asNode()["dependencies"] as groovy.util.NodeList).forEach { dependencies ->
254-
(dependencies as groovy.util.Node).children().forEach { dependency ->
255-
val dep = dependency as groovy.util.Node
256-
val optional = dep["optional"] as groovy.util.NodeList
257-
val scope = dep["scope"] as groovy.util.NodeList
258-
if (!optional.isEmpty() && (optional[0] as groovy.util.Node).text() == "true") {
259-
(scope[0] as groovy.util.Node).setValue("runtime")
260-
}
261-
}
239+
publishing.publications.withType<MavenPublication>().configureEach {
240+
pom.withXml {
241+
val dependencies = (asNode()["dependencies"] as groovy.util.NodeList)[0] as groovy.util.Node
242+
for (dependency in dependencies.children()) {
243+
dependency as groovy.util.Node
244+
val optional = dependency["optional"] as groovy.util.NodeList
245+
if (!optional.isEmpty() && (optional[0] as groovy.util.Node).text() == "true") {
246+
((dependency["scope"] as groovy.util.NodeList)[0] as groovy.util.Node).setValue("runtime")
262247
}
263248
}
264249
}
@@ -269,56 +254,33 @@ allprojects {
269254
allprojects {
270255
plugins.withId("maven-publish") {
271256

272-
plugins.apply("com.jfrog.bintray")
273-
274-
bintray {
275-
user = "${rootProject.extra["bintray_username"]}"
276-
key = "${rootProject.extra["bintray_apiKey"]}"
277-
publish = true
278-
pkg.apply {
279-
userOrg = "hivemq"
280-
repo = "HiveMQ"
281-
name = "hivemq-mqtt-client"
282-
desc = project.description
283-
websiteUrl = metadata.url
284-
issueTrackerUrl = metadata.issueManagement.url
285-
vcsUrl = metadata.scm.url
286-
setLicenses(metadata.license.shortName)
287-
setLabels("mqtt", "mqtt-client", "iot", "internet-of-things", "rxjava2", "reactive-streams", "backpressure")
288-
version.apply {
289-
released = Date().toString()
290-
vcsTag = "v${project.version}"
291-
gpg.apply {
292-
sign = true
293-
}
294-
}
295-
}
296-
}
297-
afterEvaluate {
298-
bintray.setPublications(*publishing.publications.withType<MavenPublication>().names.toTypedArray())
299-
}
257+
plugins.apply("signing")
300258

301-
// workaround for publishing gradle module metadata https://github.com/bintray/gradle-bintray-plugin/issues/229
302-
tasks.withType<com.jfrog.bintray.gradle.tasks.BintrayUploadTask> {
303-
doFirst {
304-
publishing.publications.withType<MavenPublication> {
305-
val moduleFile = buildDir.resolve("publications/$name/module.json")
306-
if (moduleFile.exists()) {
307-
artifact(moduleFile).extension = "module"
308-
}
309-
}
259+
signing {
260+
val signingKey: String? by project
261+
val signingPassword: String? by project
262+
useInMemoryPgpKeys(signingKey, signingPassword)
263+
publishing.publications.configureEach {
264+
sign(this)
310265
}
311266
}
312267
}
313268
}
314269

270+
nexusPublishing {
271+
repositories {
272+
sonatype()
273+
}
274+
}
275+
315276
githubRelease {
316-
token("${rootProject.extra["github_token"]}")
317-
owner.set(metadata.github.org)
318-
repo.set(metadata.github.repo)
277+
owner.set(metadata.github!!.org.get())
278+
repo.set(metadata.github!!.repo.get())
319279
targetCommitish.set("master")
320280
tagName.set("v${project.version}")
321281
releaseName.set("${project.version}")
282+
val githubToken: String? by project
283+
token(githubToken)
322284
}
323285

324286

@@ -340,11 +302,12 @@ allprojects {
340302

341303
pmd {
342304
toolVersion = "5.7.0"
305+
incrementalAnalysis.set(false)
343306
}
344307
}
345308
}
346309

347-
apply("${rootDir}/gradle/japicc.gradle.kts")
310+
apply("$rootDir/gradle/japicc.gradle.kts")
348311

349312

350313
/* ******************** build cache ******************** */

‎epoll/build.gradle.kts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ plugins {
88
description = "Adds dependencies for the HiveMQ MQTT Client epoll module"
99

1010
metadata {
11-
moduleName = "com.hivemq.client.mqtt.epoll"
12-
readableName = "HiveMQ MQTT Client epoll module"
11+
moduleName.set("com.hivemq.client.mqtt.epoll")
12+
readableName.set("HiveMQ MQTT Client epoll module")
1313
}
1414

1515

‎examples/build.gradle.kts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ plugins {
88
description = "Examples using the HiveMQ MQTT Client"
99

1010
metadata {
11-
moduleName = "com.hivemq.client.mqtt.examples"
12-
readableName = "HiveMQ MQTT Client examples"
11+
moduleName.set("com.hivemq.client.mqtt.examples")
12+
readableName.set("HiveMQ MQTT Client examples")
1313
}
1414

1515

‎gradle.properties

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
version=1.2.1
2-
prevVersion=1.2.0
1+
version=1.2.2
2+
prevVersion=1.2.1
33
#
44
# main dependencies
55
#
@@ -25,13 +25,13 @@ paho.version=1.2.0
2525
# plugins
2626
#
2727
plugin.shadow.version=5.2.0
28-
plugin.bnd.version=5.0.1
29-
plugin.license.version=0.15.0
30-
plugin.bintray.version=1.8.5
28+
plugin.bnd.version=5.3.0
29+
plugin.nexus-publish.version=1.0.0
3130
plugin.github-release.version=2.2.12
31+
plugin.license.version=0.15.0
3232
plugin.utf8.version=0.1.0
33-
plugin.metadata.version=0.1.2
34-
plugin.javadoc-links.version=0.1.0
33+
plugin.metadata.version=0.2.0
34+
plugin.javadoc-links.version=0.3.0
3535
#
3636
# options
3737
#

‎gradle/publishing.gradle.kts

-33
This file was deleted.

‎gradle/wrapper/gradle-wrapper.jar

509 Bytes
Binary file not shown.
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

‎gradlew

+2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ esac
8282

8383
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
8484

85+
8586
# Determine the Java command to use to start the JVM.
8687
if [ -n "$JAVA_HOME" ] ; then
8788
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -129,6 +130,7 @@ fi
129130
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
130131
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
131132
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133+
132134
JAVACMD=`cygpath --unix "$JAVACMD"`
133135

134136
# We build the pattern for arguments to be converted via cygpath

‎gradlew.bat

+4-18
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
4040

4141
set JAVA_EXE=java.exe
4242
%JAVA_EXE% -version >NUL 2>&1
43-
if "%ERRORLEVEL%" == "0" goto init
43+
if "%ERRORLEVEL%" == "0" goto execute
4444

4545
echo.
4646
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -54,7 +54,7 @@ goto fail
5454
set JAVA_HOME=%JAVA_HOME:"=%
5555
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
5656

57-
if exist "%JAVA_EXE%" goto init
57+
if exist "%JAVA_EXE%" goto execute
5858

5959
echo.
6060
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -64,28 +64,14 @@ echo location of your Java installation.
6464

6565
goto fail
6666

67-
:init
68-
@rem Get command-line arguments, handling Windows variants
69-
70-
if not "%OS%" == "Windows_NT" goto win9xME_args
71-
72-
:win9xME_args
73-
@rem Slurp the command line arguments.
74-
set CMD_LINE_ARGS=
75-
set _SKIP=2
76-
77-
:win9xME_args_slurp
78-
if "x%~1" == "x" goto execute
79-
80-
set CMD_LINE_ARGS=%*
81-
8267
:execute
8368
@rem Setup the command line
8469

8570
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
8671

72+
8773
@rem Execute Gradle
88-
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
74+
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
8975

9076
:end
9177
@rem End local scope for the variables with windows NT shell

‎proxy/build.gradle.kts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ plugins {
88
description = "Adds dependencies for the HiveMQ MQTT Client proxy module"
99

1010
metadata {
11-
moduleName = "com.hivemq.client.mqtt.proxy"
12-
readableName = "HiveMQ MQTT Client proxy module"
11+
moduleName.set("com.hivemq.client.mqtt.proxy")
12+
readableName.set("HiveMQ MQTT Client proxy module")
1313
}
1414

1515

‎reactor/build.gradle.kts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ plugins {
88
description = "Reactor API for the HiveMQ MQTT Client"
99

1010
metadata {
11-
moduleName = "com.hivemq.client.mqtt.reactor"
12-
readableName = "HiveMQ MQTT Client reactor module"
11+
moduleName.set("com.hivemq.client.mqtt.reactor")
12+
readableName.set("HiveMQ MQTT Client reactor module")
1313
}
1414

1515

‎settings.gradle.kts

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
rootProject.name = "hivemq-mqtt-client"
2+
13
pluginManagement {
24
repositories {
35
gradlePluginPortal()
@@ -6,18 +8,22 @@ pluginManagement {
68
plugins {
79
id("com.github.johnrengelman.shadow") version "${extra["plugin.shadow.version"]}"
810
id("biz.aQute.bnd.builder") version "${extra["plugin.bnd.version"]}"
9-
id("com.github.hierynomus.license") version "${extra["plugin.license.version"]}"
10-
id("com.jfrog.bintray") version "${extra["plugin.bintray.version"]}"
11+
id("io.github.gradle-nexus.publish-plugin") version "${extra["plugin.nexus-publish.version"]}"
1112
id("com.github.breadmoirai.github-release") version "${extra["plugin.github-release.version"]}"
13+
id("com.github.hierynomus.license") version "${extra["plugin.license.version"]}"
1214
id("com.github.sgtsilvio.gradle.utf8") version "${extra["plugin.utf8.version"]}"
1315
id("com.github.sgtsilvio.gradle.metadata") version "${extra["plugin.metadata.version"]}"
1416
id("com.github.sgtsilvio.gradle.javadoc-links") version "${extra["plugin.javadoc-links.version"]}"
1517
}
1618
}
1719

18-
rootProject.name = "hivemq-mqtt-client"
20+
dependencyResolutionManagement {
21+
repositories {
22+
mavenCentral()
23+
}
24+
}
1925

20-
listOf("websocket", "proxy", "epoll", "reactor", "examples").forEach { module ->
26+
for (module in listOf("websocket", "proxy", "epoll", "reactor", "examples")) {
2127
include("${rootProject.name}-$module")
2228
project(":${rootProject.name}-$module").projectDir = file(module)
2329
}

‎src/main/java/com/hivemq/client/internal/mqtt/MqttClientConfig.java

+1
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ public void releaseEventLoop() {
197197
synchronized (state) {
198198
if (eventLoopAcquireCount == this.eventLoopAcquireCount) { // eventLoop has not been reacquired
199199
this.eventLoop = null;
200+
// releaseEventLoop must be the last statement so everything is cleaned up even if it throws
200201
NettyEventLoopProvider.INSTANCE.releaseEventLoop(executorConfig.getRawNettyExecutor());
201202
}
202203
}

‎src/main/java/com/hivemq/client/internal/mqtt/handler/MqttChannelInitializer.java

+3
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ public void handlerAdded(final @NotNull ChannelHandlerContext ctx) {
9494
ctx.pipeline().remove(this);
9595

9696
((SocketChannel) ctx.channel()).config()
97+
// close not on write error (concurrent write while remote closes the connection), only on read
98+
// this ensures that always all bytes are read, e.g. of the DISCONNECT sent before the close
99+
.setAutoClose(false)
97100
.setKeepAlive(true)
98101
.setTcpNoDelay(true)
99102
.setConnectTimeoutMillis(clientConfig.getCurrentTransportConfig().getSocketConnectTimeoutMs());

‎src/main/java/com/hivemq/client/internal/mqtt/handler/proxy/MqttProxyAdapterHandler.java

+45-17
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,26 @@
1717
package com.hivemq.client.internal.mqtt.handler.proxy;
1818

1919
import com.hivemq.client.internal.mqtt.MqttProxyConfigImpl;
20-
import io.netty.channel.Channel;
21-
import io.netty.channel.ChannelHandlerContext;
22-
import io.netty.channel.ChannelOutboundHandlerAdapter;
23-
import io.netty.channel.ChannelPromise;
20+
import io.netty.channel.*;
2421
import io.netty.handler.proxy.HttpProxyHandler;
2522
import io.netty.handler.proxy.ProxyHandler;
2623
import io.netty.handler.proxy.Socks4ProxyHandler;
2724
import io.netty.handler.proxy.Socks5ProxyHandler;
25+
import io.netty.util.concurrent.Future;
26+
import io.netty.util.concurrent.FutureListener;
2827
import org.jetbrains.annotations.NotNull;
2928
import org.jetbrains.annotations.Nullable;
3029

3130
import java.net.InetSocketAddress;
3231
import java.net.SocketAddress;
32+
import java.util.NoSuchElementException;
3333
import java.util.function.BiConsumer;
3434
import java.util.function.Consumer;
3535

3636
/**
3737
* @author Silvio Giebl
3838
*/
39-
class MqttProxyAdapterHandler extends ChannelOutboundHandlerAdapter {
39+
class MqttProxyAdapterHandler extends ChannelDuplexHandler implements FutureListener<Channel> {
4040

4141
public static final @NotNull String NAME = "proxy.adapter";
4242
private static final @NotNull String PROXY_HANDLER_NAME = "proxy";
@@ -45,6 +45,7 @@ class MqttProxyAdapterHandler extends ChannelOutboundHandlerAdapter {
4545
private final @NotNull InetSocketAddress serverAddress;
4646
private final @NotNull Consumer<Channel> onSuccess;
4747
private final @NotNull BiConsumer<Channel, Throwable> onError;
48+
private boolean handshakeDone = false;
4849

4950
public MqttProxyAdapterHandler(
5051
final @NotNull MqttProxyConfigImpl proxyConfig,
@@ -68,8 +69,6 @@ public void connect(
6869
final Channel channel = ctx.channel();
6970
final String username = proxyConfig.getRawUsername();
7071
final String password = proxyConfig.getRawPassword();
71-
final Consumer<Channel> onSuccess = this.onSuccess;
72-
final BiConsumer<Channel, Throwable> onError = this.onError;
7372

7473
final ProxyHandler proxyHandler;
7574
switch (proxyConfig.getProtocol()) {
@@ -88,25 +87,54 @@ public void connect(
8887
}
8988
break;
9089
default:
91-
onError.accept(
92-
channel, new IllegalStateException("Unknown proxy protocol " + proxyConfig.getProtocol()));
90+
if (setHandshakeDone(channel.pipeline())) {
91+
onError.accept(
92+
channel, new IllegalStateException("Unknown proxy protocol " + proxyConfig.getProtocol()));
93+
}
9394
return;
9495
}
9596

9697
proxyHandler.setConnectTimeoutMillis(proxyConfig.getHandshakeTimeoutMs());
9798

98-
proxyHandler.connectFuture().addListener(future -> {
99-
channel.pipeline().remove(PROXY_HANDLER_NAME);
100-
if (future.isSuccess()) {
99+
proxyHandler.connectFuture().addListener(this);
100+
101+
channel.pipeline().addFirst(PROXY_HANDLER_NAME, proxyHandler);
102+
103+
ctx.connect(serverAddress, localAddress, promise);
104+
}
105+
106+
@Override
107+
public void operationComplete(final @NotNull Future<Channel> future) {
108+
if (future.isSuccess()) {
109+
final Channel channel = future.getNow();
110+
if (setHandshakeDone(channel.pipeline())) {
101111
onSuccess.accept(channel);
102-
} else {
103-
onError.accept(channel, future.cause());
104112
}
105-
});
113+
}
114+
// onError is handled in exceptionCaught because the exception is fired after the connect future is set and
115+
// otherwise "An exceptionCaught() event was fired, and it reached at the tail of the pipeline" would be logged
116+
}
106117

107-
channel.pipeline().addFirst(PROXY_HANDLER_NAME, proxyHandler).remove(this);
118+
@Override
119+
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final @NotNull Throwable cause) {
120+
if (setHandshakeDone(ctx.pipeline())) {
121+
onError.accept(ctx.channel(), cause);
122+
} else {
123+
ctx.fireExceptionCaught(cause);
124+
}
125+
}
108126

109-
ctx.connect(serverAddress, localAddress, promise);
127+
private boolean setHandshakeDone(final @NotNull ChannelPipeline pipeline) {
128+
if (!handshakeDone) {
129+
handshakeDone = true;
130+
pipeline.remove(this);
131+
try {
132+
pipeline.remove(PROXY_HANDLER_NAME);
133+
} catch (final NoSuchElementException ignored) {
134+
}
135+
return true;
136+
}
137+
return false;
110138
}
111139

112140
@Override

‎src/main/java/com/hivemq/client/internal/mqtt/handler/publish/incoming/MqttStatefulPublishWithFlows.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.hivemq.client.internal.annotations.NotThreadSafe;
2020
import com.hivemq.client.internal.mqtt.message.publish.MqttStatefulPublish;
2121
import com.hivemq.client.internal.util.collections.HandleList;
22+
import com.hivemq.client.mqtt.datatypes.MqttQos;
2223
import org.jetbrains.annotations.NotNull;
2324

2425
/**
@@ -39,7 +40,7 @@ class MqttStatefulPublishWithFlows extends HandleList<MqttIncomingPublishFlow> {
3940

4041
@Override
4142
public @NotNull Handle<MqttIncomingPublishFlow> add(final @NotNull MqttIncomingPublishFlow flow) {
42-
if (flow.manualAcknowledgement) {
43+
if ((publish.stateless().getQos() != MqttQos.AT_MOST_ONCE) && flow.manualAcknowledgement) {
4344
missingAcknowledgements++;
4445
flow.increaseMissingAcknowledgements();
4546
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright 2018-present HiveMQ and the HiveMQ Community
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.hivemq.client.internal.mqtt.handler.ssl;
18+
19+
import io.netty.channel.Channel;
20+
import io.netty.channel.ChannelHandlerContext;
21+
import io.netty.channel.ChannelInboundHandlerAdapter;
22+
import io.netty.handler.ssl.SslHandler;
23+
import io.netty.handler.ssl.SslHandshakeCompletionEvent;
24+
import org.jetbrains.annotations.NotNull;
25+
import org.jetbrains.annotations.Nullable;
26+
27+
import javax.net.ssl.HostnameVerifier;
28+
import javax.net.ssl.SSLHandshakeException;
29+
import java.util.function.BiConsumer;
30+
import java.util.function.Consumer;
31+
32+
/**
33+
* @author Silvio Giebl
34+
*/
35+
class MqttSslAdapterHandler extends ChannelInboundHandlerAdapter {
36+
37+
public static final @NotNull String NAME = "ssl.adapter";
38+
39+
private final @NotNull SslHandler sslHandler;
40+
private final @NotNull String host;
41+
private final @Nullable HostnameVerifier hostnameVerifier;
42+
private final @NotNull Consumer<Channel> onSuccess;
43+
private final @NotNull BiConsumer<Channel, Throwable> onError;
44+
private boolean handshakeDone = false;
45+
46+
public MqttSslAdapterHandler(
47+
final @NotNull SslHandler sslHandler,
48+
final @NotNull String host,
49+
final @Nullable HostnameVerifier hostnameVerifier,
50+
final @NotNull Consumer<Channel> onSuccess,
51+
final @NotNull BiConsumer<Channel, Throwable> onError) {
52+
53+
this.sslHandler = sslHandler;
54+
this.host = host;
55+
this.hostnameVerifier = hostnameVerifier;
56+
this.onSuccess = onSuccess;
57+
this.onError = onError;
58+
}
59+
60+
@Override
61+
public void userEventTriggered(final @NotNull ChannelHandlerContext ctx, final @NotNull Object evt) {
62+
if (evt instanceof SslHandshakeCompletionEvent) {
63+
handshakeComplete(ctx, (SslHandshakeCompletionEvent) evt);
64+
} else {
65+
ctx.fireUserEventTriggered(evt);
66+
}
67+
}
68+
69+
private void handshakeComplete(
70+
final @NotNull ChannelHandlerContext ctx, final @NotNull SslHandshakeCompletionEvent evt) {
71+
72+
if (setHandshakeDone()) {
73+
if (evt.isSuccess()) {
74+
ctx.pipeline().remove(this);
75+
if ((hostnameVerifier == null) || hostnameVerifier.verify(host, sslHandler.engine().getSession())) {
76+
onSuccess.accept(ctx.channel());
77+
} else {
78+
onError.accept(ctx.channel(), new SSLHandshakeException("Hostname verification failed"));
79+
}
80+
} else {
81+
// this handler is not removed here as the exception might also be fired so exceptionCaught is called
82+
// otherwise "An exceptionCaught() event was fired, and it reached at the tail of the pipeline" would be
83+
// logged
84+
onError.accept(ctx.channel(), evt.cause());
85+
}
86+
}
87+
}
88+
89+
@Override
90+
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final @NotNull Throwable cause) {
91+
// to ensure that additional exceptions are not swallowed, the handler is removed on the first exception
92+
ctx.pipeline().remove(this);
93+
if (setHandshakeDone()) {
94+
onError.accept(ctx.channel(), cause);
95+
}
96+
// the exception is not fired in the else branch to avoid that
97+
// "An exceptionCaught() event was fired, and it reached at the tail of the pipeline" is logged although it was
98+
// already handled via the SslHandshakeCompletionEvent
99+
}
100+
101+
private boolean setHandshakeDone() {
102+
if (!handshakeDone) {
103+
handshakeDone = true;
104+
return true;
105+
}
106+
return false;
107+
}
108+
109+
@Override
110+
public boolean isSharable() {
111+
return false;
112+
}
113+
}

‎src/main/java/com/hivemq/client/internal/mqtt/handler/ssl/MqttSslInitializer.java

+4-14
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828

2929
import javax.net.ssl.HostnameVerifier;
3030
import javax.net.ssl.SSLException;
31-
import javax.net.ssl.SSLHandshakeException;
3231
import javax.net.ssl.SSLParameters;
3332
import java.net.InetSocketAddress;
3433
import java.util.function.BiConsumer;
@@ -73,20 +72,11 @@ public static void initChannel(
7372
sslHandler.engine().setSSLParameters(sslParameters);
7473
}
7574

76-
sslHandler.handshakeFuture().addListener(future -> {
77-
if (future.isSuccess()) {
78-
if ((hostnameVerifier != null) &&
79-
!hostnameVerifier.verify(serverAddress.getHostString(), sslHandler.engine().getSession())) {
80-
onError.accept(channel, new SSLHandshakeException("Hostname verification failed"));
81-
} else {
82-
onSuccess.accept(channel);
83-
}
84-
} else {
85-
onError.accept(channel, future.cause());
86-
}
87-
});
75+
final MqttSslAdapterHandler sslAdapterHandler =
76+
new MqttSslAdapterHandler(sslHandler, serverAddress.getHostString(), hostnameVerifier, onSuccess,
77+
onError);
8878

89-
channel.pipeline().addLast(SSL_HANDLER_NAME, sslHandler);
79+
channel.pipeline().addLast(SSL_HANDLER_NAME, sslHandler).addLast(MqttSslAdapterHandler.NAME, sslAdapterHandler);
9080
}
9181

9282
static @NotNull SslContext createSslContext(final @NotNull MqttClientSslConfigImpl sslConfig) throws SSLException {

‎src/main/java/com/hivemq/client/internal/netty/NettyEventLoopProvider.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,9 @@ private NettyEventLoopProvider(
9090
if (entry == null) {
9191
final MultithreadEventLoopGroup eventLoopGroup;
9292
if (executor == null) {
93-
eventLoopGroup = eventLoopGroupFactory.apply(threadCount,
94-
new ThreadPerTaskExecutor(new DefaultThreadFactory("com.hivemq.client.mqtt")));
93+
eventLoopGroup = eventLoopGroupFactory.apply(
94+
threadCount, new ThreadPerTaskExecutor(
95+
new DefaultThreadFactory("com.hivemq.client.mqtt", Thread.MAX_PRIORITY)));
9596

9697
} else if (executor instanceof MultithreadEventLoopGroup) {
9798
eventLoopGroup = (MultithreadEventLoopGroup) executor;
@@ -119,10 +120,11 @@ private NettyEventLoopProvider(
119120
public synchronized void releaseEventLoop(final @Nullable Executor executor) {
120121
final Entry entry = entries.get(executor);
121122
if (--entry.referenceCount == 0) {
123+
entries.remove(executor);
122124
if (!(executor instanceof MultithreadEventLoopGroup)) {
125+
// shutdownGracefully must be the last statement so everything is cleaned up even if it throws
123126
entry.eventLoopGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS);
124127
}
125-
entries.remove(executor);
126128
}
127129
}
128130

‎src/main/java/com/hivemq/client/mqtt/MqttClientSslConfigBuilderBase.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public interface MqttClientSslConfigBuilderBase<B extends MqttClientSslConfigBui
4848
@NotNull B keyManagerFactory(@Nullable KeyManagerFactory keyManagerFactory);
4949

5050
/**
51-
* Sets the optional user defined {@link MqttClientSslConfig#getTrustManagerFactory() trunst manager factory}.
51+
* Sets the optional user defined {@link MqttClientSslConfig#getTrustManagerFactory() trust manager factory}.
5252
*
5353
* @param trustManagerFactory the trust manager factory or <code>null</code> to remove any previously set trust
5454
* manager factory

‎websocket/build.gradle.kts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ plugins {
88
description = "Adds dependencies for the HiveMQ MQTT Client websocket module"
99

1010
metadata {
11-
moduleName = "com.hivemq.client.mqtt.websocket"
12-
readableName = "HiveMQ MQTT Client websocket module"
11+
moduleName.set("com.hivemq.client.mqtt.websocket")
12+
readableName.set("HiveMQ MQTT Client websocket module")
1313
}
1414

1515

0 commit comments

Comments
 (0)
Please sign in to comment.