16
16
17
17
package org .springframework .integration .mqtt .core ;
18
18
19
- import java .time .Instant ;
20
- import java .util .concurrent .ScheduledFuture ;
21
-
22
19
import org .eclipse .paho .client .mqttv3 .IMqttAsyncClient ;
23
20
import org .eclipse .paho .client .mqttv3 .IMqttDeliveryToken ;
24
21
import org .eclipse .paho .client .mqttv3 .MqttCallback ;
25
22
import org .eclipse .paho .client .mqttv3 .MqttConnectOptions ;
26
23
import org .eclipse .paho .client .mqttv3 .MqttException ;
27
24
import org .eclipse .paho .client .mqttv3 .MqttMessage ;
28
25
29
- import org .springframework .beans .factory .BeanFactory ;
30
- import org .springframework .beans .factory .BeanFactoryAware ;
31
- import org .springframework .beans .factory .InitializingBean ;
32
- import org .springframework .integration .context .IntegrationContextUtils ;
33
- import org .springframework .scheduling .TaskScheduler ;
34
26
import org .springframework .util .Assert ;
35
27
36
- public class Mqttv3ClientManager extends AbstractMqttClientManager <IMqttAsyncClient >
37
- implements MqttCallback , InitializingBean , BeanFactoryAware {
38
-
39
- /**
40
- * The default reconnect timeout in millis.
41
- */
42
- private static final long DEFAULT_RECOVERY_INTERVAL = 10_000 ;
28
+ /**
29
+ * @author Artem Vozhdayenko
30
+ * @since 6.0
31
+ */
32
+ public class Mqttv3ClientManager extends AbstractMqttClientManager <IMqttAsyncClient > implements MqttCallback {
43
33
44
34
private final MqttPahoClientFactory clientFactory ;
45
35
46
- private BeanFactory beanFactory ;
47
-
48
- private TaskScheduler taskScheduler ;
49
-
50
- private volatile ScheduledFuture <?> scheduledReconnect ;
51
-
52
36
private volatile IMqttAsyncClient client ;
53
37
54
- private long recoveryInterval = DEFAULT_RECOVERY_INTERVAL ;
55
-
56
38
public Mqttv3ClientManager (MqttPahoClientFactory clientFactory , String clientId ) {
57
39
super (clientId );
58
40
Assert .notNull (clientFactory , "'clientFactory' is required" );
59
41
this .clientFactory = clientFactory ;
60
- String [] serverURIs = clientFactory .getConnectionOptions ().getServerURIs ();
42
+ MqttConnectOptions connectionOptions = clientFactory .getConnectionOptions ();
43
+ String [] serverURIs = connectionOptions .getServerURIs ();
61
44
Assert .notEmpty (serverURIs , "'serverURIs' must be provided in the 'MqttConnectionOptions'" );
62
45
setUrl (serverURIs [0 ]);
46
+ if (!connectionOptions .isAutomaticReconnect ()) {
47
+ logger .info ("If this `ClientManager` is used from message-driven channel adapters, " +
48
+ "it is recommended to set 'automaticReconnect' MQTT connection option. " +
49
+ "Otherwise connection check and reconnect should be done manually." );
50
+ }
63
51
}
64
52
65
53
public Mqttv3ClientManager (String url , String clientId ) {
66
- super (clientId );
54
+ this (buildDefaultClientFactory (url ), clientId );
55
+ }
56
+
57
+ private static MqttPahoClientFactory buildDefaultClientFactory (String url ) {
67
58
Assert .notNull (url , "'url' is required" );
68
- setUrl (url );
69
59
MqttConnectOptions connectOptions = new MqttConnectOptions ();
70
60
connectOptions .setServerURIs (new String []{ url });
61
+ connectOptions .setAutomaticReconnect (true );
71
62
DefaultMqttPahoClientFactory defaultFactory = new DefaultMqttPahoClientFactory ();
72
63
defaultFactory .setConnectionOptions (connectOptions );
73
- this . clientFactory = defaultFactory ;
64
+ return defaultFactory ;
74
65
}
75
66
76
67
@ Override
77
68
public IMqttAsyncClient getClient () {
78
69
return this .client ;
79
70
}
80
71
81
- @ Override
82
- public void afterPropertiesSet () {
83
- this .taskScheduler = IntegrationContextUtils .getTaskScheduler (this .beanFactory );
84
- }
85
-
86
- @ Override
87
- public void setBeanFactory (BeanFactory beanFactory ) {
88
- Assert .notNull (beanFactory , "'beanFactory' must not be null" );
89
- this .beanFactory = beanFactory ;
90
- }
91
-
92
72
@ Override
93
73
public synchronized void start () {
94
74
if (this .client == null ) {
@@ -102,12 +82,20 @@ public synchronized void start() {
102
82
}
103
83
}
104
84
try {
105
- connect ();
85
+ MqttConnectOptions options = this .clientFactory .getConnectionOptions ();
86
+ this .client .connect (options ).waitForCompletion (options .getConnectionTimeout ());
106
87
}
107
88
catch (MqttException e ) {
108
- logger .error ("could not start client manager, scheduling reconnect, client_id=" +
109
- this .client .getClientId (), e );
110
- scheduleReconnect ();
89
+ logger .error ("could not start client manager, client_id=" + this .client .getClientId (), e );
90
+
91
+ if (this .clientFactory .getConnectionOptions ().isAutomaticReconnect ()) {
92
+ try {
93
+ this .client .reconnect ();
94
+ }
95
+ catch (MqttException ex ) {
96
+ logger .error ("MQTT client failed to re-connect." , ex );
97
+ }
98
+ }
111
99
}
112
100
}
113
101
@@ -140,9 +128,7 @@ public synchronized boolean isRunning() {
140
128
141
129
@ Override
142
130
public synchronized void connectionLost (Throwable cause ) {
143
- logger .error ("connection lost, scheduling reconnect, client_id=" + this .client .getClientId (),
144
- cause );
145
- scheduleReconnect ();
131
+ logger .error ("connection lost, client_id=" + this .client .getClientId (), cause );
146
132
}
147
133
148
134
@ Override
@@ -155,37 +141,4 @@ public void deliveryComplete(IMqttDeliveryToken token) {
155
141
// nor this manager concern
156
142
}
157
143
158
- public long getRecoveryInterval () {
159
- return this .recoveryInterval ;
160
- }
161
-
162
- public void setRecoveryInterval (long recoveryInterval ) {
163
- this .recoveryInterval = recoveryInterval ;
164
- }
165
-
166
- private synchronized void connect () throws MqttException {
167
- MqttConnectOptions options = this .clientFactory .getConnectionOptions ();
168
- this .client .connect (options ).waitForCompletion (options .getConnectionTimeout ());
169
- }
170
-
171
- private synchronized void scheduleReconnect () {
172
- if (this .scheduledReconnect != null ) {
173
- this .scheduledReconnect .cancel (false );
174
- }
175
- this .scheduledReconnect = this .taskScheduler .schedule (() -> {
176
- try {
177
- if (this .client .isConnected ()) {
178
- return ;
179
- }
180
-
181
- connect ();
182
- this .scheduledReconnect = null ;
183
- }
184
- catch (MqttException e ) {
185
- logger .error ("could not reconnect" , e );
186
- scheduleReconnect ();
187
- }
188
- }, Instant .now ().plusMillis (getRecoveryInterval ()));
189
- }
190
-
191
144
}
0 commit comments