mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[xmpp] Improve reconnection logic (#14397)
* Add null annotations * Introduce re-connect logic Signed-off-by: lsiepel <leosiepel@gmail.com> Signed-off-by: Leo Siepel <leosiepel@gmail.com>
This commit is contained in:
parent
cd398b701e
commit
31cca5ee1f
@ -27,19 +27,20 @@ Bridge xmppclient:xmppBridge:xmpp "XMPP Client" [ host="xmpp.example.com", port=
|
|||||||
**xmppBridge** parameters:
|
**xmppBridge** parameters:
|
||||||
|
|
||||||
| Name | Label | Description | Required | Default value |
|
| Name | Label | Description | Required | Default value |
|
||||||
|----------|--------------------|-------------------------------------------|-----------|-----------------------|
|
|--------------|--------------------|--------------------------------------------------------------------|----------|-----------------------|
|
||||||
| username | Username | The XMPP username (left part of JID) | true | - |
|
| username | Username | The XMPP username (left part of JID) | true | - |
|
||||||
| domain | Domain | The XMPP domain name (right part of JID) | true | - |
|
| domain | Domain | The XMPP domain name (right part of JID) | true | - |
|
||||||
| password | Password | The XMPP user password | true | - |
|
| password | Password | The XMPP user password | true | - |
|
||||||
| host | Server Hostname/IP | The IP/Hostname of the XMPP server | false | as "domain" parameter |
|
| host | Server Hostname/IP | The IP/Hostname of the XMPP server | false | as "domain" parameter |
|
||||||
| port | XMPP server Port | The typical port is 5222 | false | 5222 |
|
| port | XMPP server Port | The typical port is 5222 | false | 5222 |
|
||||||
|
| securityMode | Security Mode | Sets the TLS security mode: `required`, `ifpossible` or `disabled` | false | `required` |
|
||||||
|
|
||||||
## Channels
|
## Channels
|
||||||
|
|
||||||
**publishTrigger** parameters:
|
**publishTrigger** parameters:
|
||||||
|
|
||||||
| Name | Label | Description | Required |
|
| Name | Label | Description | Required |
|
||||||
|-----------|---------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|
|
|-----------|---------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|
|
||||||
| payload | Payload condition | An optional condition on the value | false |
|
| payload | Payload condition | An optional condition on the value | false |
|
||||||
| separator | Separator character | The trigger channel payload usually only contains the received text. If you define a separator character, for example '#', the sender UID and received text will be in the trigger channel payload. For example: pavel@example.com#My Message Text | false |
|
| separator | Separator character | The trigger channel payload usually only contains the received text. If you define a separator character, for example '#', the sender UID and received text will be in the trigger channel payload. For example: pavel@example.com#My Message Text | false |
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.xmppclient.internal;
|
package org.openhab.binding.xmppclient.internal;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -20,6 +21,7 @@ import org.openhab.core.thing.ThingTypeUID;
|
|||||||
*
|
*
|
||||||
* @author Pavel Gololobov - Initial contribution
|
* @author Pavel Gololobov - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class XMPPClientBindingConstants {
|
public class XMPPClientBindingConstants {
|
||||||
private static final String BINDING_ID = "xmppclient";
|
private static final String BINDING_ID = "xmppclient";
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ package org.openhab.binding.xmppclient.internal;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.xmppclient.internal.handler.XMPPClientHandler;
|
import org.openhab.binding.xmppclient.internal.handler.XMPPClientHandler;
|
||||||
import org.openhab.core.thing.Bridge;
|
import org.openhab.core.thing.Bridge;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
@ -29,6 +31,7 @@ import org.osgi.service.component.annotations.Component;
|
|||||||
*
|
*
|
||||||
* @author Pavel Gololobov - Initial contribution
|
* @author Pavel Gololobov - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
@Component(configurationPid = "binding.xmppclient", service = ThingHandlerFactory.class)
|
@Component(configurationPid = "binding.xmppclient", service = ThingHandlerFactory.class)
|
||||||
public class XMPPClientHandlerFactory extends BaseThingHandlerFactory {
|
public class XMPPClientHandlerFactory extends BaseThingHandlerFactory {
|
||||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set
|
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set
|
||||||
@ -40,7 +43,7 @@ public class XMPPClientHandlerFactory extends BaseThingHandlerFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ThingHandler createHandler(Thing thing) {
|
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||||
|
|
||||||
if (thingTypeUID.equals(XMPPClientBindingConstants.BRIDGE_TYPE_XMPP)) {
|
if (thingTypeUID.equals(XMPPClientBindingConstants.BRIDGE_TYPE_XMPP)) {
|
||||||
|
@ -14,7 +14,7 @@ package org.openhab.binding.xmppclient.internal.action;
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.xmppclient.internal.XMPPClient;
|
import org.openhab.binding.xmppclient.internal.client.XMPPClient;
|
||||||
import org.openhab.binding.xmppclient.internal.handler.XMPPClientHandler;
|
import org.openhab.binding.xmppclient.internal.handler.XMPPClientHandler;
|
||||||
import org.openhab.core.automation.annotation.ActionInput;
|
import org.openhab.core.automation.annotation.ActionInput;
|
||||||
import org.openhab.core.automation.annotation.RuleAction;
|
import org.openhab.core.automation.annotation.RuleAction;
|
||||||
@ -35,7 +35,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
@ThingActionsScope(name = "xmppclient")
|
@ThingActionsScope(name = "xmppclient")
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class XMPPActions implements ThingActions {
|
public class XMPPActions implements ThingActions {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(XMPPActions.class);
|
private final Logger logger = LoggerFactory.getLogger(XMPPActions.class);
|
||||||
private @Nullable XMPPClientHandler handler;
|
private @Nullable XMPPClientHandler handler;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -58,12 +58,8 @@ public class XMPPActions implements ThingActions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
XMPPClient connection = clientHandler.getXMPPClient();
|
XMPPClient connection = clientHandler.getXMPPClient();
|
||||||
if (connection == null) {
|
if (to == null || text == null) {
|
||||||
logger.warn("XMPP ThingHandler connection is null");
|
logger.warn("Skipping XMPP messaging to {} value {}", to, text);
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((to == null) || (text == null)) {
|
|
||||||
logger.info("Skipping XMPP messaging to {} value {}", to, text);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
connection.sendMessage(to, text);
|
connection.sendMessage(to, text);
|
||||||
@ -80,11 +76,7 @@ public class XMPPActions implements ThingActions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
XMPPClient connection = clientHandler.getXMPPClient();
|
XMPPClient connection = clientHandler.getXMPPClient();
|
||||||
if (connection == null) {
|
if (to == null || filename == null) {
|
||||||
logger.warn("XMPP ThingHandler connection is null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((to == null) || (filename == null)) {
|
|
||||||
logger.warn("Skipping XMPP messaging to {} value {}", to, filename);
|
logger.warn("Skipping XMPP messaging to {} value {}", to, filename);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -10,15 +10,19 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.xmppclient.internal;
|
package org.openhab.binding.xmppclient.internal.client;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.jivesoftware.smack.AbstractXMPPConnection;
|
import org.jivesoftware.smack.AbstractXMPPConnection;
|
||||||
|
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
|
||||||
import org.jivesoftware.smack.ConnectionListener;
|
import org.jivesoftware.smack.ConnectionListener;
|
||||||
import org.jivesoftware.smack.ReconnectionManager;
|
import org.jivesoftware.smack.ReconnectionManager;
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
@ -44,13 +48,20 @@ import org.slf4j.LoggerFactory;
|
|||||||
* The {@link XMPPClient} is lib for handling XMPP connection and messaging
|
* The {@link XMPPClient} is lib for handling XMPP connection and messaging
|
||||||
*
|
*
|
||||||
* @author Pavel Gololobov - Initial contribution
|
* @author Pavel Gololobov - Initial contribution
|
||||||
|
* @author Leo Siepel - Add reconnection logic
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class XMPPClient implements IncomingChatMessageListener, ConnectionListener {
|
public class XMPPClient implements IncomingChatMessageListener, ConnectionListener {
|
||||||
private final Logger logger = LoggerFactory.getLogger(XMPPClient.class);
|
private final Logger logger = LoggerFactory.getLogger(XMPPClient.class);
|
||||||
private AbstractXMPPConnection connection;
|
private @Nullable AbstractXMPPConnection connection;
|
||||||
private ChatManager chatManager;
|
private @Nullable ChatManager chatManager;
|
||||||
private HttpFileUploadManager httpFileUploadManager;
|
private @Nullable HttpFileUploadManager httpFileUploadManager;
|
||||||
private Set<XMPPClientMessageSubscriber> subscribers = new HashSet<>();
|
private Set<XMPPClientMessageSubscriber> subscribers = new HashSet<>();
|
||||||
|
private final XMPPClientEventlistener eventListener;
|
||||||
|
|
||||||
|
public XMPPClient(XMPPClientEventlistener eventListener) {
|
||||||
|
this.eventListener = eventListener;
|
||||||
|
}
|
||||||
|
|
||||||
public void subscribe(XMPPClientMessageSubscriber channel) {
|
public void subscribe(XMPPClientMessageSubscriber channel) {
|
||||||
logger.debug("Channel {} subscribed", channel.getName());
|
logger.debug("Channel {} subscribed", channel.getName());
|
||||||
@ -62,25 +73,32 @@ public class XMPPClient implements IncomingChatMessageListener, ConnectionListen
|
|||||||
subscribers.remove(channel);
|
subscribers.remove(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect(String host, Integer port, String login, String domain, String password)
|
public void connect(String host, Integer port, String login, String domain, String password,
|
||||||
throws XMPPException, SmackException, IOException {
|
SecurityMode securityMode) throws XMPPClientConfigException, XMPPClientException {
|
||||||
disconnect();
|
disconnect();
|
||||||
String serverHost = domain;
|
String serverHost = domain;
|
||||||
if ((host != null) && !host.isEmpty()) {
|
if (!host.isBlank()) {
|
||||||
serverHost = host;
|
serverHost = host;
|
||||||
}
|
}
|
||||||
|
|
||||||
XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder() //
|
XMPPTCPConnectionConfiguration config;
|
||||||
|
try {
|
||||||
|
config = XMPPTCPConnectionConfiguration.builder() //
|
||||||
.setHost(serverHost) //
|
.setHost(serverHost) //
|
||||||
.setPort(port) //
|
.setPort(port) //
|
||||||
.setUsernameAndPassword(login, password) //
|
.setUsernameAndPassword(login, password) //
|
||||||
.setXmppDomain(domain) //
|
.setXmppDomain(domain) //
|
||||||
|
.setSecurityMode(securityMode)//
|
||||||
.build();
|
.build();
|
||||||
|
} catch (XmppStringprepException e) {
|
||||||
|
throw new XMPPClientConfigException(Objects.requireNonNullElse(e.getMessage(), "Unknown error message"));
|
||||||
|
}
|
||||||
|
|
||||||
connection = new XMPPTCPConnection(config);
|
AbstractXMPPConnection connectionLocal = new XMPPTCPConnection(config);
|
||||||
connection.addConnectionListener(this);
|
connection = connectionLocal;
|
||||||
|
connectionLocal.addConnectionListener(this);
|
||||||
|
|
||||||
ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(connection);
|
ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(connectionLocal);
|
||||||
reconnectionManager.enableAutomaticReconnection();
|
reconnectionManager.enableAutomaticReconnection();
|
||||||
|
|
||||||
Identity identity = new Identity("client", "openHAB", "bot");
|
Identity identity = new Identity("client", "openHAB", "bot");
|
||||||
@ -88,16 +106,20 @@ public class XMPPClient implements IncomingChatMessageListener, ConnectionListen
|
|||||||
sdm.setIdentity(identity);
|
sdm.setIdentity(identity);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
connection.connect().login();
|
connectionLocal.connect().login();
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException | XMPPException | SmackException | IOException e) {
|
||||||
|
throw new XMPPClientException(Objects.requireNonNullElse(e.getMessage(), "Unknown error message"),
|
||||||
|
e.getCause());
|
||||||
}
|
}
|
||||||
|
|
||||||
chatManager = ChatManager.getInstanceFor(connection);
|
ChatManager chatManager = ChatManager.getInstanceFor(connection);
|
||||||
chatManager.addIncomingListener(this);
|
chatManager.addIncomingListener(this);
|
||||||
|
this.chatManager = chatManager;
|
||||||
httpFileUploadManager = HttpFileUploadManager.getInstanceFor(connection);
|
httpFileUploadManager = HttpFileUploadManager.getInstanceFor(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
|
AbstractXMPPConnection connection = this.connection;
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
connection.disconnect();
|
connection.disconnect();
|
||||||
}
|
}
|
||||||
@ -105,11 +127,13 @@ public class XMPPClient implements IncomingChatMessageListener, ConnectionListen
|
|||||||
|
|
||||||
public void sendMessage(String to, String message) {
|
public void sendMessage(String to, String message) {
|
||||||
if (connection == null) {
|
if (connection == null) {
|
||||||
logger.warn("XMPP connection is null");
|
eventListener.onErrorEvent("XMPP connection is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChatManager chatManager = this.chatManager;
|
||||||
if (chatManager == null) {
|
if (chatManager == null) {
|
||||||
logger.warn("XMPP chatManager is null");
|
eventListener.onErrorEvent("XMPP chatManager is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -117,7 +141,7 @@ public class XMPPClient implements IncomingChatMessageListener, ConnectionListen
|
|||||||
Chat chat = chatManager.chatWith(jid);
|
Chat chat = chatManager.chatWith(jid);
|
||||||
chat.send(message);
|
chat.send(message);
|
||||||
} catch (XmppStringprepException | SmackException.NotConnectedException | InterruptedException e) {
|
} catch (XmppStringprepException | SmackException.NotConnectedException | InterruptedException e) {
|
||||||
logger.info("XMPP message sending error", e);
|
logger.warn("XMPP message sending error", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,12 +150,13 @@ public class XMPPClient implements IncomingChatMessageListener, ConnectionListen
|
|||||||
logger.warn("XMPP connection is null");
|
logger.warn("XMPP connection is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (httpFileUploadManager == null) {
|
HttpFileUploadManager httpFileUploadManagerLocal = httpFileUploadManager;
|
||||||
|
if (httpFileUploadManagerLocal == null) {
|
||||||
logger.warn("XMPP httpFileUploadManager is null");
|
logger.warn("XMPP httpFileUploadManager is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
URL u = httpFileUploadManager.uploadFile(new File(filename));
|
URL u = httpFileUploadManagerLocal.uploadFile(new File(filename));
|
||||||
// Use Stanza oob
|
// Use Stanza oob
|
||||||
this.sendMessage(to, u.toString());
|
this.sendMessage(to, u.toString());
|
||||||
} catch (XMPPException.XMPPErrorException | SmackException | InterruptedException | IOException e) {
|
} catch (XMPPException.XMPPErrorException | SmackException | InterruptedException | IOException e) {
|
||||||
@ -140,7 +165,12 @@ public class XMPPClient implements IncomingChatMessageListener, ConnectionListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
|
public void newIncomingMessage(@Nullable EntityBareJid from, @Nullable Message message, @Nullable Chat chat) {
|
||||||
|
if (from == null || message == null || chat == null) {
|
||||||
|
logger.debug("newIncomingMessage with atleast one null argument, should not happen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
logger.debug("XMPP {} says {}", from.asBareJid().toString(), message.getBody());
|
logger.debug("XMPP {} says {}", from.asBareJid().toString(), message.getBody());
|
||||||
for (XMPPClientMessageSubscriber subscriber : subscribers) {
|
for (XMPPClientMessageSubscriber subscriber : subscribers) {
|
||||||
logger.debug("Push to subscriber {}", subscriber.getName());
|
logger.debug("Push to subscriber {}", subscriber.getName());
|
||||||
@ -149,30 +179,26 @@ public class XMPPClient implements IncomingChatMessageListener, ConnectionListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connected(XMPPConnection connection) {
|
public void connected(@Nullable XMPPConnection connection) {
|
||||||
logger.debug("Connected to XMPP server.");
|
logger.debug("Connected to XMPP server.");
|
||||||
|
eventListener.onAllOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void authenticated(XMPPConnection connection, boolean resumed) {
|
public void authenticated(@Nullable XMPPConnection connection, boolean resumed) {
|
||||||
logger.debug("Authenticated to XMPP server.");
|
logger.debug("Authenticated to XMPP server.");
|
||||||
|
eventListener.onAllOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connectionClosed() {
|
public void connectionClosed() {
|
||||||
logger.debug("XMPP connection was closed.");
|
logger.debug("XMPP connection was closed.");
|
||||||
|
eventListener.onErrorEvent("XMPP connection was closed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connectionClosedOnError(Exception e) {
|
public void connectionClosedOnError(@Nullable Exception e) {
|
||||||
logger.debug("Connection to XMPP server was lost.");
|
logger.debug("Connection to XMPP server was lost.");
|
||||||
if (connection != null) {
|
eventListener.onErrorEvent("XMPP connection was closed.");
|
||||||
connection.disconnect();
|
|
||||||
try {
|
|
||||||
connection.connect().login();
|
|
||||||
} catch (SmackException | IOException | XMPPException | InterruptedException ex) {
|
|
||||||
logger.info("XMPP connection error", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||||
|
*
|
||||||
|
* See the NOTICE file(s) distributed with this work for additional
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.openhab.binding.xmppclient.internal.client;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link XMPPClientConfigException} represents a binding specific {@link Exception}.
|
||||||
|
*
|
||||||
|
* @author Leo Siepel - Initial contribution
|
||||||
|
*/
|
||||||
|
|
||||||
|
@NonNullByDefault
|
||||||
|
public class XMPPClientConfigException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public XMPPClientConfigException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public XMPPClientConfigException(String message, @Nullable Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public XMPPClientConfigException(@Nullable Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||||
|
*
|
||||||
|
* See the NOTICE file(s) distributed with this work for additional
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.openhab.binding.xmppclient.internal.client;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link XMPPClientEventlistener} is an interface for handling XMPP connection events.
|
||||||
|
*
|
||||||
|
* @author Leo Siepel - Initial Contribution
|
||||||
|
*/
|
||||||
|
|
||||||
|
@NonNullByDefault
|
||||||
|
public interface XMPPClientEventlistener {
|
||||||
|
|
||||||
|
void onErrorEvent(String errorMessage);
|
||||||
|
|
||||||
|
void onAllOk();
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||||
|
*
|
||||||
|
* See the NOTICE file(s) distributed with this work for additional
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.openhab.binding.xmppclient.internal.client;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link XMPPClientException} represents a binding specific {@link Exception}.
|
||||||
|
*
|
||||||
|
* @author Leo Siepel - Initial contribution
|
||||||
|
*/
|
||||||
|
|
||||||
|
@NonNullByDefault
|
||||||
|
public class XMPPClientException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public XMPPClientException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public XMPPClientException(String message, @Nullable Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public XMPPClientException(@Nullable Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.xmppclient.internal.handler;
|
package org.openhab.binding.xmppclient.internal.handler;
|
||||||
|
|
||||||
import org.openhab.binding.xmppclient.internal.XMPPClient;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.binding.xmppclient.internal.client.XMPPClient;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,6 +23,7 @@ import org.openhab.core.thing.ChannelUID;
|
|||||||
*
|
*
|
||||||
* @author Pavel Gololobov - Initial contribution
|
* @author Pavel Gololobov - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class PublishTriggerChannel implements XMPPClientMessageSubscriber {
|
public class PublishTriggerChannel implements XMPPClientMessageSubscriber {
|
||||||
private final XMPPClient connection;
|
private final XMPPClient connection;
|
||||||
private final PublishTriggerChannelConfig config;
|
private final PublishTriggerChannelConfig config;
|
||||||
|
@ -14,6 +14,7 @@ package org.openhab.binding.xmppclient.internal.handler;
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link XMPPClientConfiguration} class contains fields mapping thing configuration parameters.
|
* The {@link XMPPClientConfiguration} class contains fields mapping thing configuration parameters.
|
||||||
@ -27,4 +28,10 @@ public class XMPPClientConfiguration {
|
|||||||
public String username = "";
|
public String username = "";
|
||||||
public String password = "";
|
public String password = "";
|
||||||
public String domain = "";
|
public String domain = "";
|
||||||
|
public String securityMode = SecurityMode.required.toString();
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
String host = this.host;
|
||||||
|
return !(host == null || host.isBlank());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,17 +12,20 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.xmppclient.internal.handler;
|
package org.openhab.binding.xmppclient.internal.handler;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.jivesoftware.smack.XMPPException;
|
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
|
||||||
import org.openhab.binding.xmppclient.internal.XMPPClient;
|
|
||||||
import org.openhab.binding.xmppclient.internal.action.XMPPActions;
|
import org.openhab.binding.xmppclient.internal.action.XMPPActions;
|
||||||
|
import org.openhab.binding.xmppclient.internal.client.XMPPClient;
|
||||||
|
import org.openhab.binding.xmppclient.internal.client.XMPPClientConfigException;
|
||||||
|
import org.openhab.binding.xmppclient.internal.client.XMPPClientEventlistener;
|
||||||
|
import org.openhab.binding.xmppclient.internal.client.XMPPClientException;
|
||||||
import org.openhab.core.thing.Bridge;
|
import org.openhab.core.thing.Bridge;
|
||||||
import org.openhab.core.thing.Channel;
|
import org.openhab.core.thing.Channel;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
@ -40,15 +43,15 @@ import org.slf4j.LoggerFactory;
|
|||||||
*
|
*
|
||||||
* @author Pavel Gololobov - Initial contribution
|
* @author Pavel Gololobov - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class XMPPClientHandler extends BaseBridgeHandler {
|
public class XMPPClientHandler extends BaseBridgeHandler implements XMPPClientEventlistener {
|
||||||
private final Logger logger = LoggerFactory.getLogger(XMPPClientHandler.class);
|
private final Logger logger = LoggerFactory.getLogger(XMPPClientHandler.class);
|
||||||
private XMPPClient xmppClient;
|
private XMPPClient xmppClient;
|
||||||
private XMPPClientConfiguration config;
|
|
||||||
private final Map<ChannelUID, PublishTriggerChannel> channelStateByChannelUID = new HashMap<>();
|
private final Map<ChannelUID, PublishTriggerChannel> channelStateByChannelUID = new HashMap<>();
|
||||||
|
|
||||||
public XMPPClientHandler(Bridge thing) {
|
public XMPPClientHandler(Bridge thing) {
|
||||||
super(thing);
|
super(thing);
|
||||||
|
xmppClient = new XMPPClient(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public XMPPClient getXMPPClient() {
|
public XMPPClient getXMPPClient() {
|
||||||
@ -85,12 +88,22 @@ public class XMPPClientHandler extends BaseBridgeHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void doConnect() {
|
private void doConnect() {
|
||||||
config = getConfigAs(XMPPClientConfiguration.class);
|
XMPPClientConfiguration config = getConfigAs(XMPPClientConfiguration.class);
|
||||||
xmppClient = new XMPPClient();
|
if (!config.isValid()) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Please check configuration");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
xmppClient.connect(config.host, config.port, config.username, config.domain, config.password);
|
xmppClient.connect(Objects.requireNonNullElse(config.host, ""), config.port, config.username, config.domain,
|
||||||
} catch (SmackException | IOException | XMPPException e) {
|
config.password, SecurityMode.valueOf(config.securityMode));
|
||||||
logger.info("XMPP connection error", e);
|
updateStatus(ThingStatus.ONLINE);
|
||||||
|
} catch (XMPPClientConfigException e) {
|
||||||
|
logger.debug("XMPP connection error", e);
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||||
|
return;
|
||||||
|
} catch (XMPPClientException e) {
|
||||||
|
logger.debug("XMPP connection error", e);
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -103,7 +116,15 @@ public class XMPPClientHandler extends BaseBridgeHandler {
|
|||||||
logger.info("XMPP added channel {} payload {}", channel.getUID().toString(), channelConfig.payload);
|
logger.info("XMPP added channel {} payload {}", channel.getUID().toString(), channelConfig.payload);
|
||||||
}
|
}
|
||||||
channelStateByChannelUID.values().forEach(c -> c.start());
|
channelStateByChannelUID.values().forEach(c -> c.start());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onErrorEvent(String errorMessage) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAllOk() {
|
||||||
updateStatus(ThingStatus.ONLINE);
|
updateStatus(ThingStatus.ONLINE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.xmppclient.internal.handler;
|
package org.openhab.binding.xmppclient.internal.handler;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscriber interface
|
* Subscriber interface
|
||||||
*
|
*
|
||||||
* @author Pavel Gololobov - Initial contribution
|
* @author Pavel Gololobov - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public interface XMPPClientMessageSubscriber {
|
public interface XMPPClientMessageSubscriber {
|
||||||
void processMessage(String from, String payload);
|
void processMessage(String from, String payload);
|
||||||
|
|
||||||
|
@ -30,6 +30,19 @@
|
|||||||
<parameter name="port" type="integer">
|
<parameter name="port" type="integer">
|
||||||
<label>XMPP Server Port</label>
|
<label>XMPP Server Port</label>
|
||||||
<description>The default port is 5222.</description>
|
<description>The default port is 5222.</description>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="securityMode" type="text" required="true">
|
||||||
|
<label>Security Mode</label>
|
||||||
|
<description>An enumeration for TLS security modes that are available when making a connection to the XMPP server.</description>
|
||||||
|
<limitToOptions>true</limitToOptions>
|
||||||
|
<options>
|
||||||
|
<option value="required">Required</option>
|
||||||
|
<option value="ifpossible">Optional</option>
|
||||||
|
<option value="disabled">Disabled</option>
|
||||||
|
</options>
|
||||||
|
<default>required</default>
|
||||||
|
<advanced>true</advanced>
|
||||||
</parameter>
|
</parameter>
|
||||||
</config-description>
|
</config-description>
|
||||||
</bridge-type>
|
</bridge-type>
|
||||||
|
Loading…
Reference in New Issue
Block a user