From 217e3d44ba24c5d1881eb7ddec8b411bacd0c458 Mon Sep 17 00:00:00 2001 From: Simon Johnson <2924684+simon622@users.noreply.github.com> Date: Mon, 18 Sep 2023 18:35:20 +0100 Subject: [PATCH] version increment --- .gitignore | 1 + mqtt-sn-client/pom.xml | 2 +- mqtt-sn-cloud-client/pom.xml | 2 +- mqtt-sn-codec/pom.xml | 4 +- mqtt-sn-core/lib/mqtt-tree-0.5.4.jar | Bin 45595 -> 0 bytes mqtt-sn-core/pom.xml | 9 +- mqtt-sn-core/src/main/resources/logback.xml | 6 +- mqtt-sn-gateway-connector-aws-iotcore/pom.xml | 2 +- .../pom.xml | 115 -------- ...CoreAggregatingGatewayInteractiveMain.java | 55 ---- .../GoogleIoTCoreMqttsnConnection.java | 259 ------------------ .../iotcore/GoogleIoTCoreMqttsnConnector.java | 67 ----- mqtt-sn-gateway-connector-paho/pom.xml | 2 +- .../dependency-reduced-pom.xml | 2 +- mqtt-sn-gateway-console/pom.xml | 2 +- mqtt-sn-gateway/pom.xml | 12 +- .../type/MqttsnAggregatingGateway.java | 16 +- mqtt-sn-load-test/pom.xml | 2 +- mqtt-sn-protection-runtimes/pom.xml | 2 +- mqtt-sn-protection/pom.xml | 2 +- pom.xml | 5 +- 21 files changed, 33 insertions(+), 534 deletions(-) delete mode 100644 mqtt-sn-core/lib/mqtt-tree-0.5.4.jar delete mode 100644 mqtt-sn-gateway-connector-google-iotcore/pom.xml delete mode 100644 mqtt-sn-gateway-connector-google-iotcore/src/main/java/org/slj/mqtt/sn/gateway/connector/google/iotcore/GoogleIoTCoreAggregatingGatewayInteractiveMain.java delete mode 100644 mqtt-sn-gateway-connector-google-iotcore/src/main/java/org/slj/mqtt/sn/gateway/connector/google/iotcore/GoogleIoTCoreMqttsnConnection.java delete mode 100644 mqtt-sn-gateway-connector-google-iotcore/src/main/java/org/slj/mqtt/sn/gateway/connector/google/iotcore/GoogleIoTCoreMqttsnConnector.java diff --git a/.gitignore b/.gitignore index d05f9f23..23d440d9 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ mqtt-sn-client-sec/ /mqtt-sn-client/dependency-reduced-pom.xml /mqtt-sn-runtimes/mqtt-sn-gateway/_message-queues-overflow/34643532633864362D323037652D346663342D386531342D333333653366646564646638 /mqtt-sn-runtimes/ +/site diff --git a/mqtt-sn-client/pom.xml b/mqtt-sn-client/pom.xml index 3060bd4f..7f7e54f9 100644 --- a/mqtt-sn-client/pom.xml +++ b/mqtt-sn-client/pom.xml @@ -31,7 +31,7 @@ org.slj mqtt-sn - 0.2.1 + 0.2.2 jar diff --git a/mqtt-sn-cloud-client/pom.xml b/mqtt-sn-cloud-client/pom.xml index b7eebbdb..1748f6ea 100644 --- a/mqtt-sn-cloud-client/pom.xml +++ b/mqtt-sn-cloud-client/pom.xml @@ -31,7 +31,7 @@ org.slj mqtt-sn - 0.2.1 + 0.2.2 mqtt-sn-cloud-client diff --git a/mqtt-sn-codec/pom.xml b/mqtt-sn-codec/pom.xml index f300888c..7543487f 100644 --- a/mqtt-sn-codec/pom.xml +++ b/mqtt-sn-codec/pom.xml @@ -47,11 +47,11 @@ org.slj mqtt-sn - 0.2.1 + 0.2.2 org.mqtt-sn - 0.2.1 + 0.2.2 mqtt-sn-codec diff --git a/mqtt-sn-core/lib/mqtt-tree-0.5.4.jar b/mqtt-sn-core/lib/mqtt-tree-0.5.4.jar deleted file mode 100644 index 833ff54268fa1ee0f481091d313491a3fc8028bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45595 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

;cmfZtMzbO^ixFLKM}RHFXB-VPwByjZ(WKi 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 diff --git a/mqtt-sn-core/pom.xml b/mqtt-sn-core/pom.xml index b8f1e568..ad2a0afd 100644 --- a/mqtt-sn-core/pom.xml +++ b/mqtt-sn-core/pom.xml @@ -31,7 +31,7 @@ org.slj mqtt-sn - 0.2.1 + 0.2.2 mqtt-sn-core @@ -50,13 +50,6 @@ javax.json 1.1.4 - - org.slj - mqtt-tree - 0.5.4 - system - ${basedir}/lib/mqtt-tree-0.5.4.jar - diff --git a/mqtt-sn-core/src/main/resources/logback.xml b/mqtt-sn-core/src/main/resources/logback.xml index 93b4f4d5..58ab83aa 100644 --- a/mqtt-sn-core/src/main/resources/logback.xml +++ b/mqtt-sn-core/src/main/resources/logback.xml @@ -47,9 +47,9 @@ - - - + + + diff --git a/mqtt-sn-gateway-connector-aws-iotcore/pom.xml b/mqtt-sn-gateway-connector-aws-iotcore/pom.xml index e69e3df3..e99b069e 100644 --- a/mqtt-sn-gateway-connector-aws-iotcore/pom.xml +++ b/mqtt-sn-gateway-connector-aws-iotcore/pom.xml @@ -31,7 +31,7 @@ org.slj mqtt-sn - 0.2.1 + 0.2.2 mqtt-sn-gateway-connector-aws-iotcore diff --git a/mqtt-sn-gateway-connector-google-iotcore/pom.xml b/mqtt-sn-gateway-connector-google-iotcore/pom.xml deleted file mode 100644 index 5b31e44b..00000000 --- a/mqtt-sn-gateway-connector-google-iotcore/pom.xml +++ /dev/null @@ -1,115 +0,0 @@ - - - - - 4.0.0 - - - org.slj - mqtt-sn - 0.2.1 - - - mqtt-sn-gateway-connector-google-iotcore - - - 2.4.3 - - - - - org.slj - mqtt-sn-core - ${mqtt-sn.version} - - - org.mqtt-sn - mqtt-sn-codec - ${mqtt-sn.version} - - - org.slj - mqtt-sn-gateway - ${mqtt-sn.version} - - - org.slj - mqtt-sn-gateway-connector-paho - ${mqtt-sn.version} - - - io.jsonwebtoken - jjwt - 0.9.1 - - - joda-time - joda-time - 2.10.13 - - - - - mqtt-sn-google-iotcore-gateway-${version} - - - - org.apache.maven.plugins - maven-shade-plugin - 2.3 - - - - package - - shade - - - - - org.slj.mqtt.sn.gateway.connector.google.iotcore.GoogleIoTCoreAggregatingGatewayInteractiveMain - - - - - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - - - - - - - - - - - \ No newline at end of file diff --git a/mqtt-sn-gateway-connector-google-iotcore/src/main/java/org/slj/mqtt/sn/gateway/connector/google/iotcore/GoogleIoTCoreAggregatingGatewayInteractiveMain.java b/mqtt-sn-gateway-connector-google-iotcore/src/main/java/org/slj/mqtt/sn/gateway/connector/google/iotcore/GoogleIoTCoreAggregatingGatewayInteractiveMain.java deleted file mode 100644 index 93b19955..00000000 --- a/mqtt-sn-gateway-connector-google-iotcore/src/main/java/org/slj/mqtt/sn/gateway/connector/google/iotcore/GoogleIoTCoreAggregatingGatewayInteractiveMain.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2021 Simon Johnson - * - * Find me on GitHub: - * https://github.com/simon622 - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.slj.mqtt.sn.gateway.connector.google.iotcore; - -import org.slj.mqtt.sn.gateway.cli.MqttsnInteractiveGatewayLauncher; -import org.slj.mqtt.sn.gateway.cli.MqttsnInteractiveGatewayWithKeystore; -import org.slj.mqtt.sn.gateway.impl.MqttsnGatewayRuntimeRegistry; -import org.slj.mqtt.sn.gateway.impl.gateway.type.MqttsnAggregatingGateway; -import org.slj.mqtt.sn.gateway.spi.connector.MqttsnConnectorOptions; -import org.slj.mqtt.sn.gateway.spi.gateway.MqttsnGatewayOptions; -import org.slj.mqtt.sn.impl.AbstractMqttsnRuntimeRegistry; -import org.slj.mqtt.sn.model.MqttsnOptions; -import org.slj.mqtt.sn.spi.IMqttsnStorageService; -import org.slj.mqtt.sn.spi.IMqttsnTransport; - -public class GoogleIoTCoreAggregatingGatewayInteractiveMain { - public static void main(String[] args) throws Exception { - MqttsnInteractiveGatewayLauncher.launch(new MqttsnInteractiveGatewayWithKeystore() { - protected AbstractMqttsnRuntimeRegistry createRuntimeRegistry(IMqttsnStorageService storageService, MqttsnOptions options, IMqttsnTransport transport) { - - IMqttsnStorageService namespacePreferences = storageService.getPreferenceNamespace(GoogleIoTCoreMqttsnConnector.DESCRIPTOR); - MqttsnConnectorOptions connectorOptions = new MqttsnConnectorOptions(); - storageService.initializeFieldsFromStorage(connectorOptions); - namespacePreferences.initializeFieldsFromStorage(connectorOptions); - - return MqttsnGatewayRuntimeRegistry.defaultConfiguration(storageService, (MqttsnGatewayOptions) options). - withConnector(new GoogleIoTCoreMqttsnConnector(GoogleIoTCoreMqttsnConnector.DESCRIPTOR, connectorOptions)). - withBackendService(new MqttsnAggregatingGateway()). - withTransport(createTransport(storageService)); - } - }, true, "Welcome to the Google IoT Core version of the gateway. You will need to connect your gateway to your Google IoT via the credentials available in your Google console."); - } -} diff --git a/mqtt-sn-gateway-connector-google-iotcore/src/main/java/org/slj/mqtt/sn/gateway/connector/google/iotcore/GoogleIoTCoreMqttsnConnection.java b/mqtt-sn-gateway-connector-google-iotcore/src/main/java/org/slj/mqtt/sn/gateway/connector/google/iotcore/GoogleIoTCoreMqttsnConnection.java deleted file mode 100644 index bf4ba8b1..00000000 --- a/mqtt-sn-gateway-connector-google-iotcore/src/main/java/org/slj/mqtt/sn/gateway/connector/google/iotcore/GoogleIoTCoreMqttsnConnection.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2021 Simon Johnson - * - * Find me on GitHub: - * https://github.com/simon622 - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.slj.mqtt.sn.gateway.connector.google.iotcore; - -import io.jsonwebtoken.JwtBuilder; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import org.eclipse.paho.client.mqttv3.MqttClient; -import org.eclipse.paho.client.mqttv3.MqttConnectOptions; -import org.eclipse.paho.client.mqttv3.MqttMessage; -import org.joda.time.DateTime; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slj.mqtt.sn.gateway.connector.paho.PahoMqttsnBrokerConnection; -import org.slj.mqtt.sn.gateway.spi.ConnectResult; -import org.slj.mqtt.sn.gateway.spi.DisconnectResult; -import org.slj.mqtt.sn.gateway.spi.PublishResult; -import org.slj.mqtt.sn.gateway.spi.Result; -import org.slj.mqtt.sn.gateway.spi.connector.MqttsnConnectorException; -import org.slj.mqtt.sn.gateway.spi.connector.MqttsnConnectorOptions; -import org.slj.mqtt.sn.model.IClientIdentifierContext; -import org.slj.mqtt.sn.spi.IMqttsnMessage; -import org.slj.mqtt.sn.spi.IMqttsnMessageFactory; -import org.slj.mqtt.sn.utils.MqttsnUtils; -import org.slj.mqtt.sn.utils.TopicPath; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; - -/** - * @author simonjohnson - * - * Uses the AWS SDK (which in turn uses PAHO) to connect to the AWS IoT Core - */ -public class GoogleIoTCoreMqttsnConnection extends PahoMqttsnBrokerConnection { - - private Logger logger = LoggerFactory.getLogger(GoogleIoTCoreMqttsnConnection.class); - - static final String ALG_RSA = "RS256"; - static final String ALG_ES = "ES256"; - - static final int TOKEN_EXPIRY_MINUTES = 60; - - public GoogleIoTCoreMqttsnConnection(MqttsnConnectorOptions options) { - super(options); - } - - @Override - protected String createClientId(MqttsnConnectorOptions options) { - final String mqttClientId = - String.format( - "projects/%s/locations/%s/registries/%s/devices/%s", - getGoogleIoTProjectId(options), - getGoogleIoTCloudRegion(options), - getGoogleIoTRegistryId(options), - getGoogleIoTGatewayId(options)); - - return mqttClientId; - } - - @Override - public ConnectResult connect(IClientIdentifierContext context, IMqttsnMessage message) throws MqttsnConnectorException { - if(isConnected()){ - logger.info("attaching {} device by clientId", context.getId()); - IMqttsnMessageFactory factory = backendService.getRegistry().getCodec().createMessageFactory(); - //-- tell IoT core we are attaching a device & register for device changes - String topicPath = String.format("/devices/%s/attach", context.getId()); - IMqttsnMessage publish = - factory.createPublish(1, false, false, topicPath, new byte[0]); - if(!super.publish(context, new TopicPath(topicPath), 1, false, new byte[0], publish).isError()){ - logger.info("device {} attached, subscribing or config changes", context.getId()); - topicPath = String.format("/devices/%s/config", context.getId()); - IMqttsnMessage subscribe = factory.createSubscribe(0, topicPath); - subscribe(context, new TopicPath(topicPath), subscribe); - } - return new ConnectResult(Result.STATUS.SUCCESS); - } - return new ConnectResult(Result.STATUS.NOOP); - } - - @Override - public DisconnectResult disconnect(IClientIdentifierContext context, IMqttsnMessage message) throws MqttsnConnectorException { - if(isConnected()){ - logger.info("detaching gateway device " + context.getId()); - IMqttsnMessageFactory factory = backendService.getRegistry().getCodec().createMessageFactory(); - String topicPath = String.format("/devices/%s/detach", context.getId()); - IMqttsnMessage publish = - factory.createPublish(1, false, false, topicPath, new byte[0]); - super.publish(context, new TopicPath(topicPath), 1, false, new byte[0], publish); - return new DisconnectResult(Result.STATUS.SUCCESS); - } - return new DisconnectResult(Result.STATUS.NOOP); - } - - @Override - public PublishResult publish(IClientIdentifierContext context, TopicPath topicPath, int qos, boolean retained, byte[] data, IMqttsnMessage message) throws MqttsnConnectorException { - return super.publish(context, topicPath, qos, retained, data, message); - } - - @Override - public boolean canAccept(IClientIdentifierContext context, TopicPath topicPath, byte[] data, IMqttsnMessage message) { - return MqttsnUtils.in(topicPath.toString(), new String[] { - String.format("/devices/%s/state", context.getId()), - String.format("/devices/%s/events", context.getId()) - }); - } - - @Override - protected void onClientConnected(MqttClient client){ - try { - ///devices/{gateway_ID}/errors - { - String topic = String.format("/devices/%s/errors", getGoogleIoTGatewayId(options)); - logger.info("subscribing to Google gateway error topic {}", topic); - client.subscribe(topic, 0); - } - - ///devices/{gateway_ID}/config - { - String topic = String.format("/devices/%s/config", getGoogleIoTGatewayId(options)); - logger.info("subscribing to Google gateway error topic {}", topic); - client.subscribe(topic, 0); - } - } catch(Exception e){ - logger.error("error subscribing to error topic", e); - } - } - - @Override - protected String createConnectionString(MqttsnConnectorOptions options) { - return "ssl://mqtt.googleapis.com:8883"; - } - - @Override - protected MqttConnectOptions createConnectOptions(MqttsnConnectorOptions options) throws MqttsnConnectorException { - try { - MqttConnectOptions connectOptions = super.createConnectOptions(options); - connectOptions.setUserName("unused"); //per the GGL documents - connectOptions.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1); - - String alg = System.getProperty("algorithm"); - if(alg == null || alg.equals(ALG_ES)){ - connectOptions.setPassword( - createJwtEs(getGoogleIoTProjectId(options), - options.getPrivateKeyFileLocation()).toCharArray()); - } else { - connectOptions.setPassword( - createJwtRsa(getGoogleIoTProjectId(options), - options.getPrivateKeyFileLocation()).toCharArray()); - } - return connectOptions; - } catch(Exception e){ - throw new MqttsnConnectorException(e); - } - } - - /** Create a Cloud IoT Core JWT for the given project id, signed with the given RSA key. */ - private static String createJwtRsa(String projectId, String privateKeyFile) - throws NoSuchAlgorithmException, IOException, InvalidKeySpecException { - DateTime now = new DateTime(); - // Create a JWT to authenticate this device. The device will be disconnected after the token - // expires, and will have to reconnect with a new token. The audience field should always be set - // to the GCP project id. - JwtBuilder jwtBuilder = - Jwts.builder() - .setIssuedAt(now.toDate()) - .setExpiration(now.plusMinutes(TOKEN_EXPIRY_MINUTES).toDate()) - .setAudience(projectId); - - byte[] keyBytes = Files.readAllBytes(Paths.get(privateKeyFile)); - PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); - KeyFactory kf = KeyFactory.getInstance("RSA"); - return jwtBuilder.signWith(SignatureAlgorithm.RS256, kf.generatePrivate(spec)).compact(); - } - - /** Create a Cloud IoT Core JWT for the given project id, signed with the given ES key. */ - private static String createJwtEs(String projectId, String privateKeyFile) - throws NoSuchAlgorithmException, IOException, InvalidKeySpecException { - DateTime now = new DateTime(); - // Create a JWT to authenticate this device. The device will be disconnected after the token - // expires, and will have to reconnect with a new token. The audience field should always be set - // to the GCP project id. - JwtBuilder jwtBuilder = - Jwts.builder() - .setIssuedAt(now.toDate()) - .setExpiration(now.plusMinutes(TOKEN_EXPIRY_MINUTES).toDate()) - .setAudience(projectId); - - byte[] keyBytes = Files.readAllBytes(Paths.get(privateKeyFile)); - PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); - KeyFactory kf = KeyFactory.getInstance("EC"); - return jwtBuilder.signWith(SignatureAlgorithm.ES256, kf.generatePrivate(spec)).compact(); - } - - protected String getGoogleIoTProjectId(MqttsnConnectorOptions options){ - final String projectId = System.getProperty("projectId"); - if(projectId == null){ - throw new IllegalArgumentException("please specify -DprojectId="); - } - return projectId; - } - - protected String getGoogleIoTGatewayId(MqttsnConnectorOptions options){ - final String gatewayId = System.getProperty("gatewayId"); - if(gatewayId == null){ - throw new IllegalArgumentException("please specify -DprojectId="); - } - return gatewayId; - } - - protected String getGoogleIoTRegistryId(MqttsnConnectorOptions options){ - final String registryId = System.getProperty("registryId"); - if(registryId == null){ - throw new IllegalArgumentException("please specify -DregistryId="); - } - return registryId; - } - - protected String getGoogleIoTCloudRegion(MqttsnConnectorOptions options){ - final String cloudRegion = System.getProperty("cloudRegion"); - if(cloudRegion == null){ - throw new IllegalArgumentException("please specify -DcloudRegion="); - } - return cloudRegion; - } - - @Override - public void messageArrived(String s, MqttMessage mqttMessage) throws Exception { - logger.info("received message from google iot {} -> {}", s, new String(mqttMessage.getPayload())); - super.messageArrived(s, mqttMessage); - } -} diff --git a/mqtt-sn-gateway-connector-google-iotcore/src/main/java/org/slj/mqtt/sn/gateway/connector/google/iotcore/GoogleIoTCoreMqttsnConnector.java b/mqtt-sn-gateway-connector-google-iotcore/src/main/java/org/slj/mqtt/sn/gateway/connector/google/iotcore/GoogleIoTCoreMqttsnConnector.java deleted file mode 100644 index 573958d7..00000000 --- a/mqtt-sn-gateway-connector-google-iotcore/src/main/java/org/slj/mqtt/sn/gateway/connector/google/iotcore/GoogleIoTCoreMqttsnConnector.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2021 Simon Johnson - * - * Find me on GitHub: - * https://github.com/simon622 - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.slj.mqtt.sn.gateway.connector.google.iotcore; - -import org.slj.mqtt.sn.cloud.MqttsnConnectorDescriptor; -import org.slj.mqtt.sn.gateway.impl.connector.AbstractMqttsnConnector; -import org.slj.mqtt.sn.gateway.spi.connector.MqttsnConnectorException; -import org.slj.mqtt.sn.gateway.spi.connector.MqttsnConnectorOptions; - -public class GoogleIoTCoreMqttsnConnector - extends AbstractMqttsnConnector{ - - public static final MqttsnConnectorDescriptor DESCRIPTOR = new MqttsnConnectorDescriptor(); - static { - DESCRIPTOR.setClassName(GoogleIoTCoreMqttsnConnector.class.getName()); - DESCRIPTOR.setCompanyName("Google"); - DESCRIPTOR.setProtocol("MQTT"); - DESCRIPTOR.setDescription("This connector is deprecated"); - DESCRIPTOR.setName("AWS IoT Core Connector (Deprecated)"); - DESCRIPTOR.setDeveloper("Goodle"); - } - - public GoogleIoTCoreMqttsnConnector(MqttsnConnectorDescriptor descriptor, MqttsnConnectorOptions options) { - super(descriptor, options); - } - - @Override - public GoogleIoTCoreMqttsnConnection createConnection(MqttsnConnectorOptions options, String clientId) throws MqttsnConnectorException { - try { - GoogleIoTCoreMqttsnConnection connection = new GoogleIoTCoreMqttsnConnection(options); - connection.connect(); - return connection; - } catch(Exception e){ - throw new MqttsnConnectorException("error creating connection;", e); - } - } - - @Override - public String getConnectionString() { - return String.format("%s@%s:%s", - options.getClientId(), - options.getHostName(), - options.getPort()); - } -} diff --git a/mqtt-sn-gateway-connector-paho/pom.xml b/mqtt-sn-gateway-connector-paho/pom.xml index 10513d1d..9662486d 100644 --- a/mqtt-sn-gateway-connector-paho/pom.xml +++ b/mqtt-sn-gateway-connector-paho/pom.xml @@ -31,7 +31,7 @@ org.slj mqtt-sn - 0.2.1 + 0.2.2 mqtt-sn-gateway-connector-paho diff --git a/mqtt-sn-gateway-console/dependency-reduced-pom.xml b/mqtt-sn-gateway-console/dependency-reduced-pom.xml index ee803d09..1fd323ab 100644 --- a/mqtt-sn-gateway-console/dependency-reduced-pom.xml +++ b/mqtt-sn-gateway-console/dependency-reduced-pom.xml @@ -3,7 +3,7 @@ mqtt-sn org.slj - 0.2.1 + 0.2.2 4.0.0 mqtt-sn-gateway-console diff --git a/mqtt-sn-gateway-console/pom.xml b/mqtt-sn-gateway-console/pom.xml index c4ad5117..63103b2d 100644 --- a/mqtt-sn-gateway-console/pom.xml +++ b/mqtt-sn-gateway-console/pom.xml @@ -29,7 +29,7 @@ mqtt-sn org.slj - 0.2.1 + 0.2.2 4.0.0 diff --git a/mqtt-sn-gateway/pom.xml b/mqtt-sn-gateway/pom.xml index b2c3dde3..87671c52 100644 --- a/mqtt-sn-gateway/pom.xml +++ b/mqtt-sn-gateway/pom.xml @@ -31,7 +31,7 @@ org.slj mqtt-sn - 0.2.1 + 0.2.2 mqtt-sn-gateway @@ -50,11 +50,11 @@ mqtt-sn-core ${mqtt-sn.version} - - com.google.guava - guava - 32.0.0-jre - + + + + + com.fasterxml.jackson.core jackson-databind diff --git a/mqtt-sn-gateway/src/main/java/org/slj/mqtt/sn/gateway/impl/gateway/type/MqttsnAggregatingGateway.java b/mqtt-sn-gateway/src/main/java/org/slj/mqtt/sn/gateway/impl/gateway/type/MqttsnAggregatingGateway.java index 22399ac2..5385ff3d 100644 --- a/mqtt-sn-gateway/src/main/java/org/slj/mqtt/sn/gateway/impl/gateway/type/MqttsnAggregatingGateway.java +++ b/mqtt-sn-gateway/src/main/java/org/slj/mqtt/sn/gateway/impl/gateway/type/MqttsnAggregatingGateway.java @@ -24,7 +24,6 @@ package org.slj.mqtt.sn.gateway.impl.gateway.type; -import com.google.common.util.concurrent.RateLimiter; import org.slj.mqtt.sn.cloud.MqttsnConnectorDescriptor; import org.slj.mqtt.sn.gateway.impl.backend.AbstractMqttsnBackendConnection; import org.slj.mqtt.sn.gateway.impl.backend.AbstractMqttsnBackendService; @@ -37,7 +36,10 @@ import org.slj.mqtt.sn.impl.metrics.MqttsnCountingMetric; import org.slj.mqtt.sn.impl.metrics.MqttsnSnapshotMetric; import org.slj.mqtt.sn.model.IClientIdentifierContext; -import org.slj.mqtt.sn.spi.*; +import org.slj.mqtt.sn.spi.IMqttsnMessage; +import org.slj.mqtt.sn.spi.IMqttsnRuntimeRegistry; +import org.slj.mqtt.sn.spi.MqttsnException; +import org.slj.mqtt.sn.spi.MqttsnIllegalFormatException; import org.slj.mqtt.sn.utils.MqttsnUtils; import org.slj.mqtt.sn.utils.TopicPath; @@ -56,7 +58,7 @@ public class MqttsnAggregatingGateway extends AbstractMqttsnBackendService { private Thread publishingThread = null; private final Object monitor = new Object(); private final Queue queue = new LinkedBlockingQueue<>(); - private volatile RateLimiter rateLimiter = null; +// private volatile RateLimiter rateLimiter = null; private static final long PUBLISH_THREAD_MAX_WAIT = 10000; private static final long MANAGED_CONNECTION_VALIDATION_TIME = 10000; private static final long MAX_ERROR_RETRIES = 5; @@ -71,7 +73,7 @@ public void start(IMqttsnRuntimeRegistry runtime) throws MqttsnException { super.start(runtime); double limiter = ((MqttsnGatewayOptions)runtime.getOptions()). getMaxBrokerPublishesPerSecond(); - rateLimiter = limiter == 0d ? null : RateLimiter.create(limiter); +// rateLimiter = limiter == 0d ? null : RateLimiter.create(limiter); stopped = false; connectOnStartup(); initPublisher(); @@ -82,10 +84,10 @@ public void start(IMqttsnRuntimeRegistry runtime) throws MqttsnException { public synchronized boolean initializeConnector(MqttsnConnectorDescriptor descriptor, MqttsnConnectorOptions options) throws MqttsnException { int qps = descriptor.getRateLimit(); if(qps > 0){ - rateLimiter = RateLimiter.create(qps); +// rateLimiter = RateLimiter.create(qps); logger.warn("re-initialising connector rate-limiter with {} permits", qps); } else { - rateLimiter = null; +// rateLimiter = null; } return super.initializeConnector(descriptor, options); } @@ -222,7 +224,7 @@ private void initPublisher(){ BrokerPublishOperation op = queue.poll(); if(op != null){ if(connection.canAccept(op.context, op.topicPath, op.payload, op.initialMessage)){ - if(rateLimiter != null) rateLimiter.acquire(); +// if(rateLimiter != null) rateLimiter.acquire(); logger.debug("de-queuing message to broker from queue, {} remaining", queue.size()); PublishResult res = super.publish(op.context, op.topicPath, op.qos, op.retained, op.payload, op.initialMessage); if(res.isError()){ diff --git a/mqtt-sn-load-test/pom.xml b/mqtt-sn-load-test/pom.xml index 255bd711..6842c328 100644 --- a/mqtt-sn-load-test/pom.xml +++ b/mqtt-sn-load-test/pom.xml @@ -31,7 +31,7 @@ org.slj mqtt-sn - 0.2.1 + 0.2.2 mqtt-sn-load-test diff --git a/mqtt-sn-protection-runtimes/pom.xml b/mqtt-sn-protection-runtimes/pom.xml index 4c0e0d9d..b9fb8e93 100644 --- a/mqtt-sn-protection-runtimes/pom.xml +++ b/mqtt-sn-protection-runtimes/pom.xml @@ -6,7 +6,7 @@ org.slj mqtt-sn - 0.2.1 + 0.2.2 mqtt-sn-protection-runtimes diff --git a/mqtt-sn-protection/pom.xml b/mqtt-sn-protection/pom.xml index f23c748a..e5a61be3 100644 --- a/mqtt-sn-protection/pom.xml +++ b/mqtt-sn-protection/pom.xml @@ -6,7 +6,7 @@ org.slj mqtt-sn - 0.2.1 + 0.2.2 mqtt-sn-protection diff --git a/pom.xml b/pom.xml index 3a162977..7d0b48b4 100644 --- a/pom.xml +++ b/pom.xml @@ -29,7 +29,7 @@ org.slj mqtt-sn - 0.2.1 + 0.2.2 pom @@ -60,7 +60,6 @@ mqtt-sn-core mqtt-sn-gateway mqtt-sn-gateway-connector-aws-iotcore - mqtt-sn-gateway-connector-google-iotcore mqtt-sn-gateway-connector-paho mqtt-sn-load-test mqtt-sn-gateway-console @@ -81,7 +80,7 @@ 3.4.1 2.10.2 1.11 - 0.2.1 + 0.2.2