Skip to content

Commit d64d85f

Browse files
committed
Merge branch 'release/1.0.0'
2 parents b166a47 + 59610ae commit d64d85f

15 files changed

+885
-24
lines changed

.classpath

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@
2222
<attribute name="maven.pomderived" value="true"/>
2323
</attributes>
2424
</classpathentry>
25-
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
25+
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
2626
<attributes>
2727
<attribute name="maven.pomderived" value="true"/>
2828
</attributes>
2929
</classpathentry>
30-
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
30+
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
3131
<attributes>
3232
<attribute name="maven.pomderived" value="true"/>
3333
</attributes>

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/target/
2+
/pom.xml.versionsBackup
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
eclipse.preferences.version=1
22
encoding//src/main/java=UTF-8
3+
encoding//src/main/resources=UTF-8
34
encoding//src/test/java=UTF-8
5+
encoding//src/test/resources=UTF-8
6+
encoding/<project>=UTF-8

.settings/org.eclipse.jdt.core.prefs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
eclipse.preferences.version=1
2-
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3-
org.eclipse.jdt.core.compiler.compliance=1.6
2+
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
3+
org.eclipse.jdt.core.compiler.compliance=1.7
44
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
5-
org.eclipse.jdt.core.compiler.source=1.6
5+
org.eclipse.jdt.core.compiler.source=1.7

README.md

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,81 @@
11
# MQTT over WebSocket library for Java
22

3-
This library offers MQTT client over WebSocket transport.
3+
This library offers MQTT client functionality over WebSocket transport with [Paho](http://www.eclipse.org/paho/) library and [Jetty](http://www.eclipse.org/jetty/) library.
44

5+
# Supported MQTT Version
6+
7+
1. MQTT v3.1 (with Sub-Protocol: `mqttv3.1`)
8+
1. MQTT v3.1.1 (with Sub-Protocol: `mqtt`) ... DEFAULT
9+
10+
# Supported Paho MQTT library version and Jetty WebSocket Client version
11+
12+
1. [Paho org.eclipse.paho.mqtt.java 1.0.0](http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.java.git/tag/?id=v1.0.0)
13+
1. [Jetty websocket-client 9.2.1.v20140609](http://www.eclipse.org/jetty/documentation/9.2.1.v20140609/jetty-websocket-client-api.html)
14+
15+
# Supported JDK/JRE Version
16+
17+
JDK/JRE 1.7+ is required as Jetty no longer supports JDK/JRE 1.6.
18+
19+
# How to build
20+
21+
Install maven then run the following command on the project root directory.
22+
23+
Note that Paho Java library is included in this project as the binary isn't uploaded to any maven repository yet.
24+
25+
$ mvn clean package
26+
27+
Then you'll get `mqtt-websocket-java-1.0.0.jar` under the `target` directory.
28+
29+
30+
# How to use
31+
Here is a sample code to use `MqttWebSocketAsyncClient`.
32+
33+
Do NOT use `MqttClient` as it always uses Paho's default async client `MqttAsyncClient`.
34+
35+
// Plain MQTT
36+
// final String uriString = "tcp://your-mqtt-broker:1883";
37+
38+
// MQTT over WebSocket
39+
final String uriString = "wss://your-ws-broker/mqtt";
40+
41+
// Credentials
42+
final String clientId = "your-client-id";
43+
final String userName = "your-user-name";
44+
final String password = "your-password";
45+
46+
final IMqttAsyncClient client = new MqttWebSocketAsyncClient(
47+
uriString, clientId, new MemoryPersistence());
48+
final MqttConnectOptions options = new MqttConnectOptions();
49+
options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
50+
options.setCleanSession(true);
51+
options.setUserName(userName);
52+
options.setPassword(password.toCharArray());
53+
client.connect(options);
54+
client.setCallback(new MqttCallback() {
55+
56+
@Override
57+
public void messageArrived(String topic, MqttMessage message)
58+
throws Exception {
59+
}
60+
61+
@Override
62+
public void deliveryComplete(IMqttDeliveryToken token) {
63+
}
64+
65+
@Override
66+
public void connectionLost(Throwable cause) {
67+
}
68+
});
69+
70+
71+
# Source Code License
72+
73+
All program source codes are available under the MIT style License.
74+
75+
Copyright (c) 2014 Inventit Inc.
76+
77+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
78+
79+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
80+
81+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

pom.xml

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>io.inventit.dev</groupId>
88
<artifactId>mqtt-websocket-java</artifactId>
9-
<version>0.0.1</version>
9+
<version>1.0.0</version>
1010
<name>MQTT over WebScoket for Java with Paho and Jetty</name>
1111
<distributionManagement>
1212
<repository>
@@ -20,9 +20,10 @@
2020

2121
<repositories>
2222
<repository>
23-
<id>LocalRepository</id>
24-
<name>Local Repository</name>
25-
<url>file://${basedir}/target</url>
23+
<id>ProjectLocalLibrariesRepository</id>
24+
<name>Project Local Libraries Repository</name>
25+
<url>file://${basedir}/src/main/libs</url>
26+
<layout>default</layout>
2627
</repository>
2728
</repositories>
2829

@@ -33,8 +34,8 @@
3334
<version>3.1</version>
3435
<configuration>
3536
<encoding>UTF-8</encoding>
36-
<source>1.6</source>
37-
<target>1.6</target>
37+
<source>1.7</source>
38+
<target>1.7</target>
3839
</configuration>
3940
</plugin>
4041
<plugin>
@@ -120,19 +121,20 @@
120121
</build>
121122

122123
<properties>
124+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
123125
</properties>
124126

125127
<dependencies>
126128
<dependency>
127-
<groupId>org.eclipse.jetty</groupId>
128-
<artifactId>jetty-websocket</artifactId>
129-
<version>8.1.15.v20140411</version>
129+
<groupId>org.eclipse.jetty.websocket</groupId>
130+
<artifactId>websocket-client</artifactId>
131+
<version>9.2.1.v20140609</version>
130132
<scope>compile</scope>
131133
</dependency>
132134
<dependency>
133-
<groupId>org.fusesource.mqtt-client</groupId>
134-
<artifactId>mqtt-client</artifactId>
135-
<version>1.10</version>
135+
<groupId>org.eclipse.paho</groupId>
136+
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
137+
<version>1.0.0</version>
136138
<scope>compile</scope>
137139
</dependency>
138140
<dependency>
@@ -141,18 +143,18 @@
141143
<version>17.0</version>
142144
<scope>compile</scope>
143145
</dependency>
146+
<dependency>
147+
<groupId>commons-codec</groupId>
148+
<artifactId>commons-codec</artifactId>
149+
<version>1.9</version>
150+
<scope>compile</scope>
151+
</dependency>
144152
<dependency>
145153
<groupId>junit</groupId>
146154
<artifactId>junit</artifactId>
147155
<version>4.11</version>
148156
<scope>test</scope>
149157
</dependency>
150-
<dependency>
151-
<groupId>org.testng</groupId>
152-
<artifactId>testng</artifactId>
153-
<version>6.8.5</version>
154-
<scope>test</scope>
155-
</dependency>
156158
<dependency>
157159
<groupId>org.mockito</groupId>
158160
<artifactId>mockito-all</artifactId>
@@ -172,4 +174,5 @@
172174
<scope>test</scope>
173175
</dependency>
174176
</dependencies>
177+
<url>https://github.com/inventit/mqtt-websocket-java</url>
175178
</project>
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/*
2+
* Copyright (c) 2014 Inventit Inc.
3+
*/
4+
package io.inventit.dev.mqtt.paho;
5+
6+
import java.net.URI;
7+
8+
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
9+
import org.eclipse.paho.client.mqttv3.MqttClientPersistence;
10+
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
11+
import org.eclipse.paho.client.mqttv3.MqttException;
12+
import org.eclipse.paho.client.mqttv3.MqttPingSender;
13+
import org.eclipse.paho.client.mqttv3.MqttSecurityException;
14+
import org.eclipse.paho.client.mqttv3.TimerPingSender;
15+
import org.eclipse.paho.client.mqttv3.internal.NetworkModule;
16+
import org.eclipse.paho.client.mqttv3.logging.Logger;
17+
import org.eclipse.paho.client.mqttv3.logging.LoggerFactory;
18+
import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
19+
20+
public class MqttWebSocketAsyncClient extends MqttAsyncClient {
21+
22+
private static final String CLASS_NAME = MqttWebSocketAsyncClient.class
23+
.getName();
24+
private static final Logger log = LoggerFactory.getLogger(
25+
LoggerFactory.MQTT_CLIENT_MSG_CAT, CLASS_NAME);
26+
27+
private final String serverURI;
28+
29+
/**
30+
* Create a dummy URI in order to by-pass MqttConnectOptions.validateURI()
31+
* validation.
32+
*
33+
* @param original
34+
* @return
35+
*/
36+
static String createDummyURI(String original) {
37+
if (!original.startsWith("ws:") && !original.startsWith("wss:")) {
38+
return original;
39+
}
40+
final URI uri = URI.create(original);
41+
return "tcp://DUMMY-" + uri.getHost() + ":"
42+
+ (uri.getPort() > 0 ? uri.getPort() : 80);
43+
}
44+
45+
static boolean isDummyURI(String uri) {
46+
return uri.startsWith("tcp://DUMMY-");
47+
}
48+
49+
public MqttWebSocketAsyncClient(String serverURI, String clientId,
50+
MqttClientPersistence persistence, MqttPingSender pingSender)
51+
throws MqttException {
52+
53+
super(createDummyURI(serverURI), clientId, persistence, pingSender);
54+
this.serverURI = serverURI;
55+
56+
final String methodName = "MqttWebSocketAsyncClient";
57+
58+
// @TRACE 101=<init> ClientID={0} ServerURI={1} PersistenceType={2}
59+
if (log.isLoggable(Logger.FINE)) {
60+
log.fine(CLASS_NAME, methodName, "101", new Object[] { clientId,
61+
serverURI, persistence });
62+
}
63+
}
64+
65+
public MqttWebSocketAsyncClient(String serverURI, String clientId,
66+
MqttClientPersistence persistence) throws MqttException {
67+
this(serverURI, clientId, persistence, new TimerPingSender());
68+
}
69+
70+
public MqttWebSocketAsyncClient(String serverURI, String clientId)
71+
throws MqttException {
72+
this(serverURI, clientId, new MqttDefaultFilePersistence());
73+
}
74+
75+
/**
76+
* Same as super{@link #createNetworkModules(String, MqttConnectOptions)}
77+
*/
78+
@Override
79+
protected NetworkModule[] createNetworkModules(String address,
80+
MqttConnectOptions options) throws MqttException,
81+
MqttSecurityException {
82+
final String methodName = "createNetworkModules";
83+
// @TRACE 116=URI={0}
84+
if (log.isLoggable(Logger.FINE)) {
85+
log.fine(CLASS_NAME, methodName, "116", new Object[] { address });
86+
}
87+
NetworkModule[] networkModules = null;
88+
String[] serverURIs = options.getServerURIs();
89+
String[] array = null;
90+
if (serverURIs == null) {
91+
array = new String[] { address };
92+
} else if (serverURIs.length == 0) {
93+
array = new String[] { address };
94+
} else {
95+
array = serverURIs;
96+
}
97+
98+
networkModules = new NetworkModule[array.length];
99+
for (int i = 0; i < array.length; i++) {
100+
networkModules[i] = createNetworkModule(array[i], options);
101+
}
102+
103+
log.fine(CLASS_NAME, methodName, "108");
104+
return networkModules;
105+
}
106+
107+
/**
108+
* Factory method to create the correct network module, based on the
109+
* supplied address URI.
110+
*
111+
* @param address
112+
* the URI for the server.
113+
* @param options
114+
* MQTT connect options
115+
* @return a network module appropriate to the specified address.
116+
*/
117+
protected NetworkModule createNetworkModule(String input,
118+
MqttConnectOptions options) throws MqttException,
119+
MqttSecurityException {
120+
final String address = isDummyURI(input) ? this.serverURI : input;
121+
if (!address.startsWith("ws:") && !address.startsWith("wss:")) {
122+
return super.createNetworkModules(address, options)[0];
123+
}
124+
125+
final String methodName = "createNetworkModule";
126+
// @TRACE 115=URI={0}
127+
if (log.isLoggable(Logger.FINE)) {
128+
log.fine(CLASS_NAME, methodName, "115", new Object[] { address });
129+
}
130+
131+
final String subProtocol;
132+
if (options.getMqttVersion() == MqttConnectOptions.MQTT_VERSION_3_1) {
133+
// http://wiki.eclipse.org/Paho/Paho_Websockets#Ensuring_implementations_can_inter-operate
134+
subProtocol = "mqttv3.1";
135+
} else {
136+
// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/cs01/mqtt-v3.1.1-cs01.html#_Toc388534418
137+
subProtocol = "mqtt";
138+
}
139+
140+
final WebSocketNetworkModule netModule = new WebSocketNetworkModule(
141+
URI.create(address), subProtocol, getClientId());
142+
netModule.setConnectTimeout(options.getConnectionTimeout());
143+
return netModule;
144+
}
145+
146+
}

0 commit comments

Comments
 (0)