Commit c5c8fbd3f73e5def00efd4390449ca99acaf080f

Authored by ShvaykaD
Committed by GitHub
1 parent dff593a3

[3.2.2] [WIP] coap transport (#4239)

* init CoapDeviceProfile & added ui components

* added transport payload type configuration for default coap device type

* added AbstractCoapTransportResource & updated efento resource

* fixed coap device profile save & update

* fixed Attribute Updates notifications

* revert CoapOkCallback onSuccess changes

* updated provision request to handle proto payload type

* fix license

* updated Rpc subscribe/unsubscribe action

* add more device emulator clients

* added fix for Coap Transport: ability to handle requests with oneElementUriPaths and MultiElementUriPaths

* fix TbCoapServer implementation

* changed response type to CREATED in POST requests

* improved implementation

* fix typos

* minor bug-fixes & improvements

* fix TbCoapServerMessageDeliverer class

* improved relay sensor implementation

* added tests for CoAP transport\

* fix typo

* removed nosql tests

* fix coap endpoint creation & improved getAttributes tests

* transport tests refactoring
Showing 137 changed files with 5265 additions and 787 deletions
application/src/test/java/org/thingsboard/server/transport/AbstractTransportIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/AbstractMqttIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt;
  16 +package org.thingsboard.server.transport;
17 17
18 18 import com.fasterxml.jackson.databind.node.ObjectNode;
19 19 import lombok.extern.slf4j.Slf4j;
... ... @@ -56,13 +56,14 @@ import static org.junit.Assert.assertNotNull;
56 56 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
57 57
58 58 @Slf4j
59   -public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest {
  59 +public abstract class AbstractTransportIntegrationTest extends AbstractControllerTest {
60 60
61 61 protected static final String MQTT_URL = "tcp://localhost:1883";
  62 + protected static final String COAP_BASE_URL = "coap://localhost:5683/api/v1/";
62 63
63   - private static final AtomicInteger atomicInteger = new AtomicInteger(2);
  64 + protected static final AtomicInteger atomicInteger = new AtomicInteger(2);
64 65
65   - public static final String DEVICE_TELEMETRY_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
  66 + protected static final String DEVICE_TELEMETRY_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
66 67 "\n" +
67 68 "package test;\n" +
68 69 "\n" +
... ... @@ -83,7 +84,7 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
83 84 " }\n" +
84 85 "}";
85 86
86   - public static final String DEVICE_ATTRIBUTES_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
  87 + protected static final String DEVICE_ATTRIBUTES_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
87 88 "\n" +
88 89 "package test;\n" +
89 90 "\n" +
... ... @@ -110,81 +111,8 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
110 111 protected Device savedDevice;
111 112 protected String accessToken;
112 113
113   - protected Device savedGateway;
114   - protected String gatewayAccessToken;
115   -
116 114 protected DeviceProfile deviceProfile;
117 115
118   - protected void processBeforeTest (String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception {
119   - this.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic, null, null, DeviceProfileProvisionType.DISABLED, null, null);
120   - }
121   -
122   - protected void processBeforeTest(String deviceName,
123   - String gatewayName,
124   - TransportPayloadType payloadType,
125   - String telemetryTopic,
126   - String attributesTopic,
127   - String telemetryProtoSchema,
128   - String attributesProtoSchema,
129   - DeviceProfileProvisionType provisionType,
130   - String provisionKey, String provisionSecret
131   - ) throws Exception {
132   - loginSysAdmin();
133   -
134   - Tenant tenant = new Tenant();
135   - tenant.setTitle("My tenant");
136   - savedTenant = doPost("/api/tenant", tenant, Tenant.class);
137   - Assert.assertNotNull(savedTenant);
138   -
139   - tenantAdmin = new User();
140   - tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
141   - tenantAdmin.setTenantId(savedTenant.getId());
142   - tenantAdmin.setEmail("tenant" + atomicInteger.getAndIncrement() + "@thingsboard.org");
143   - tenantAdmin.setFirstName("Joe");
144   - tenantAdmin.setLastName("Downs");
145   -
146   - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
147   -
148   - Device device = new Device();
149   - device.setName(deviceName);
150   - device.setType("default");
151   -
152   - Device gateway = new Device();
153   - gateway.setName(gatewayName);
154   - gateway.setType("default");
155   - ObjectNode additionalInfo = mapper.createObjectNode();
156   - additionalInfo.put("gateway", true);
157   - gateway.setAdditionalInfo(additionalInfo);
158   -
159   - if (payloadType != null) {
160   - DeviceProfile mqttDeviceProfile = createMqttDeviceProfile(payloadType, telemetryTopic, attributesTopic, telemetryProtoSchema, attributesProtoSchema, provisionType, provisionKey, provisionSecret);
161   - deviceProfile = doPost("/api/deviceProfile", mqttDeviceProfile, DeviceProfile.class);
162   - device.setType(deviceProfile.getName());
163   - device.setDeviceProfileId(deviceProfile.getId());
164   - gateway.setType(deviceProfile.getName());
165   - gateway.setDeviceProfileId(deviceProfile.getId());
166   - }
167   -
168   - savedDevice = doPost("/api/device", device, Device.class);
169   -
170   - DeviceCredentials deviceCredentials =
171   - doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
172   -
173   - savedGateway = doPost("/api/device", gateway, Device.class);
174   -
175   - DeviceCredentials gatewayCredentials =
176   - doGet("/api/device/" + savedGateway.getId().getId().toString() + "/credentials", DeviceCredentials.class);
177   -
178   - assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
179   - accessToken = deviceCredentials.getCredentialsId();
180   - assertNotNull(accessToken);
181   -
182   - assertEquals(savedGateway.getId(), gatewayCredentials.getDeviceId());
183   - gatewayAccessToken = gatewayCredentials.getCredentialsId();
184   - assertNotNull(gatewayAccessToken);
185   -
186   - }
187   -
188 116 protected void processAfterTest() throws Exception {
189 117 loginSysAdmin();
190 118 if (savedTenant != null) {
... ... @@ -192,22 +120,6 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
192 120 }
193 121 }
194 122
195   - protected MqttAsyncClient getMqttAsyncClient(String accessToken) throws MqttException {
196   - String clientId = MqttAsyncClient.generateClientId();
197   - MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId, new MemoryPersistence());
198   -
199   - MqttConnectOptions options = new MqttConnectOptions();
200   - options.setUserName(accessToken);
201   - client.connect(options).waitForCompletion();
202   - return client;
203   - }
204   -
205   - protected void publishMqttMsg(MqttAsyncClient client, byte[] payload, String topic) throws MqttException {
206   - MqttMessage message = new MqttMessage();
207   - message.setPayload(payload);
208   - client.publish(topic, message);
209   - }
210   -
211 123 protected List<TransportProtos.KeyValueProto> getKvProtos(List<String> expectedKeys) {
212 124 List<TransportProtos.KeyValueProto> keyValueProtos = new ArrayList<>();
213 125 TransportProtos.KeyValueProto strKeyValueProto = getKeyValueProto(expectedKeys.get(0), "value1", TransportProtos.KeyValueType.STRING_V);
... ... @@ -247,72 +159,6 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
247 159 return keyValueProtoBuilder.build();
248 160 }
249 161
250   - protected DeviceProfile createMqttDeviceProfile(TransportPayloadType transportPayloadType,
251   - String telemetryTopic, String attributesTopic,
252   - String telemetryProtoSchema, String attributesProtoSchema,
253   - DeviceProfileProvisionType provisionType,
254   - String provisionKey, String provisionSecret) {
255   - DeviceProfile deviceProfile = new DeviceProfile();
256   - deviceProfile.setName(transportPayloadType.name());
257   - deviceProfile.setType(DeviceProfileType.DEFAULT);
258   - deviceProfile.setTransportType(DeviceTransportType.MQTT);
259   - deviceProfile.setProvisionType(provisionType);
260   - deviceProfile.setProvisionDeviceKey(provisionKey);
261   - deviceProfile.setDescription(transportPayloadType.name() + " Test");
262   - DeviceProfileData deviceProfileData = new DeviceProfileData();
263   - DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
264   - MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = new MqttDeviceProfileTransportConfiguration();
265   - if (!StringUtils.isEmpty(telemetryTopic)) {
266   - mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(telemetryTopic);
267   - }
268   - if (!StringUtils.isEmpty(attributesTopic)) {
269   - mqttDeviceProfileTransportConfiguration.setDeviceAttributesTopic(attributesTopic);
270   - }
271   - TransportPayloadTypeConfiguration transportPayloadTypeConfiguration;
272   - if (TransportPayloadType.JSON.equals(transportPayloadType)) {
273   - transportPayloadTypeConfiguration = new JsonTransportPayloadConfiguration();
274   - } else {
275   - ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = new ProtoTransportPayloadConfiguration();
276   - if (StringUtils.isEmpty(telemetryProtoSchema)) {
277   - telemetryProtoSchema = DEVICE_TELEMETRY_PROTO_SCHEMA;
278   - }
279   - if (StringUtils.isEmpty(attributesProtoSchema)) {
280   - attributesProtoSchema = DEVICE_ATTRIBUTES_PROTO_SCHEMA;
281   - }
282   - protoTransportPayloadConfiguration.setDeviceTelemetryProtoSchema(telemetryProtoSchema);
283   - protoTransportPayloadConfiguration.setDeviceAttributesProtoSchema(attributesProtoSchema);
284   - transportPayloadTypeConfiguration = protoTransportPayloadConfiguration;
285   - }
286   - mqttDeviceProfileTransportConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration);
287   - deviceProfileData.setTransportConfiguration(mqttDeviceProfileTransportConfiguration);
288   - DeviceProfileProvisionConfiguration provisionConfiguration;
289   - switch (provisionType) {
290   - case ALLOW_CREATE_NEW_DEVICES:
291   - provisionConfiguration = new AllowCreateNewDevicesDeviceProfileProvisionConfiguration(provisionSecret);
292   - break;
293   - case CHECK_PRE_PROVISIONED_DEVICES:
294   - provisionConfiguration = new CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration(provisionSecret);
295   - break;
296   - case DISABLED:
297   - default:
298   - provisionConfiguration = new DisabledDeviceProfileProvisionConfiguration(provisionSecret);
299   - break;
300   - }
301   - deviceProfileData.setProvisionConfiguration(provisionConfiguration);
302   - deviceProfileData.setConfiguration(configuration);
303   - deviceProfile.setProfileData(deviceProfileData);
304   - deviceProfile.setDefault(false);
305   - deviceProfile.setDefaultRuleChainId(null);
306   - return deviceProfile;
307   - }
308   -
309   - protected TransportProtos.PostAttributeMsg getPostAttributeMsg(List<String> expectedKeys) {
310   - List<TransportProtos.KeyValueProto> kvProtos = getKvProtos(expectedKeys);
311   - TransportProtos.PostAttributeMsg.Builder builder = TransportProtos.PostAttributeMsg.newBuilder();
312   - builder.addAllKv(kvProtos);
313   - return builder.build();
314   - }
315   -
316 162 protected <T> T doExecuteWithRetriesAndInterval(SupplierWithThrowable<T> supplier, int retries, int intervalMs) throws Exception {
317 163 int count = 0;
318 164 T result = null;
... ...
application/src/test/java/org/thingsboard/server/transport/TransportNoSqlTestSuite.java renamed from application/src/test/java/org/thingsboard/server/mqtt/MqttNoSqlTestSuite.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt;
  16 +package org.thingsboard.server.transport;
17 17
18 18 import org.cassandraunit.dataset.cql.ClassPathCQLDataSet;
19 19 import org.junit.BeforeClass;
... ... @@ -28,8 +28,8 @@ import java.util.Arrays;
28 28
29 29 @RunWith(ClasspathSuite.class)
30 30 @ClasspathSuite.ClassnameFilters({
31   - "org.thingsboard.server.mqtt.*.nosql.*Test"})
32   -public class MqttNoSqlTestSuite {
  31 + "org.thingsboard.server.transport.*.telemetry.timeseries.nosql.*Test"})
  32 +public class TransportNoSqlTestSuite {
33 33
34 34 @ClassRule
35 35 public static CustomSqlUnit sqlUnit = new CustomSqlUnit(
... ...
application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java renamed from application/src/test/java/org/thingsboard/server/mqtt/MqttSqlTestSuite.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt;
  16 +package org.thingsboard.server.transport;
17 17
18 18 import org.junit.BeforeClass;
19 19 import org.junit.ClassRule;
... ... @@ -26,15 +26,15 @@ import java.util.Arrays;
26 26
27 27 @RunWith(ClasspathSuite.class)
28 28 @ClasspathSuite.ClassnameFilters({
29   - "org.thingsboard.server.mqtt.rpc.sql.*Test",
30   - "org.thingsboard.server.mqtt.telemetry.timeseries.sql.*Test",
31   - "org.thingsboard.server.mqtt.telemetry.attributes.sql.*Test",
32   - "org.thingsboard.server.mqtt.attributes.updates.sql.*Test",
33   - "org.thingsboard.server.mqtt.attributes.request.sql.*Test",
34   - "org.thingsboard.server.mqtt.claim.sql.*Test",
35   - "org.thingsboard.server.mqtt.provision.sql.*Test"
  29 + "org.thingsboard.server.transport.*.rpc.sql.*Test",
  30 + "org.thingsboard.server.transport.*.telemetry.timeseries.sql.*Test",
  31 + "org.thingsboard.server.transport.*.telemetry.attributes.sql.*Test",
  32 + "org.thingsboard.server.transport.*.attributes.updates.sql.*Test",
  33 + "org.thingsboard.server.transport.*.attributes.request.sql.*Test",
  34 + "org.thingsboard.server.transport.*.claim.sql.*Test",
  35 + "org.thingsboard.server.transport.*.provision.sql.*Test"
36 36 })
37   -public class MqttSqlTestSuite {
  37 +public class TransportSqlTestSuite {
38 38
39 39 @ClassRule
40 40 public static CustomSqlUnit sqlUnit = new CustomSqlUnit(
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.eclipse.californium.core.CoapClient;
  20 +import org.junit.Assert;
  21 +import org.springframework.util.StringUtils;
  22 +import org.thingsboard.server.common.data.CoapDeviceType;
  23 +import org.thingsboard.server.common.data.Device;
  24 +import org.thingsboard.server.common.data.DeviceProfile;
  25 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
  26 +import org.thingsboard.server.common.data.DeviceProfileType;
  27 +import org.thingsboard.server.common.data.DeviceTransportType;
  28 +import org.thingsboard.server.common.data.Tenant;
  29 +import org.thingsboard.server.common.data.TransportPayloadType;
  30 +import org.thingsboard.server.common.data.User;
  31 +import org.thingsboard.server.common.data.device.profile.AllowCreateNewDevicesDeviceProfileProvisionConfiguration;
  32 +import org.thingsboard.server.common.data.device.profile.CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration;
  33 +import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
  34 +import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration;
  35 +import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration;
  36 +import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
  37 +import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
  38 +import org.thingsboard.server.common.data.device.profile.DeviceProfileProvisionConfiguration;
  39 +import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration;
  40 +import org.thingsboard.server.common.data.device.profile.EfentoCoapDeviceTypeConfiguration;
  41 +import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration;
  42 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  43 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
  44 +import org.thingsboard.server.common.data.security.Authority;
  45 +import org.thingsboard.server.common.data.security.DeviceCredentials;
  46 +import org.thingsboard.server.common.msg.session.FeatureType;
  47 +import org.thingsboard.server.transport.AbstractTransportIntegrationTest;
  48 +
  49 +import static org.junit.Assert.assertEquals;
  50 +import static org.junit.Assert.assertNotNull;
  51 +
  52 +@Slf4j
  53 +public abstract class AbstractCoapIntegrationTest extends AbstractTransportIntegrationTest {
  54 +
  55 + protected void processBeforeTest(String deviceName, CoapDeviceType coapDeviceType, TransportPayloadType payloadType) throws Exception {
  56 + this.processBeforeTest(deviceName, coapDeviceType, payloadType, null, null, DeviceProfileProvisionType.DISABLED, null, null);
  57 + }
  58 +
  59 + protected void processBeforeTest(String deviceName,
  60 + CoapDeviceType coapDeviceType,
  61 + TransportPayloadType payloadType,
  62 + String telemetryProtoSchema,
  63 + String attributesProtoSchema,
  64 + DeviceProfileProvisionType provisionType,
  65 + String provisionKey, String provisionSecret
  66 + ) throws Exception {
  67 + loginSysAdmin();
  68 +
  69 + Tenant tenant = new Tenant();
  70 + tenant.setTitle("My tenant");
  71 + savedTenant = doPost("/api/tenant", tenant, Tenant.class);
  72 + Assert.assertNotNull(savedTenant);
  73 +
  74 + tenantAdmin = new User();
  75 + tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
  76 + tenantAdmin.setTenantId(savedTenant.getId());
  77 + tenantAdmin.setEmail("tenant" + atomicInteger.getAndIncrement() + "@thingsboard.org");
  78 + tenantAdmin.setFirstName("Joe");
  79 + tenantAdmin.setLastName("Downs");
  80 +
  81 + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
  82 +
  83 + Device device = new Device();
  84 + device.setName(deviceName);
  85 + device.setType("default");
  86 +
  87 + if (coapDeviceType != null) {
  88 + DeviceProfile coapDeviceProfile = createCoapDeviceProfile(payloadType, coapDeviceType, attributesProtoSchema, provisionType, provisionKey, provisionSecret, telemetryProtoSchema);
  89 + deviceProfile = doPost("/api/deviceProfile", coapDeviceProfile, DeviceProfile.class);
  90 + device.setType(deviceProfile.getName());
  91 + device.setDeviceProfileId(deviceProfile.getId());
  92 + }
  93 +
  94 + savedDevice = doPost("/api/device", device, Device.class);
  95 +
  96 + DeviceCredentials deviceCredentials =
  97 + doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
  98 +
  99 + assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
  100 + accessToken = deviceCredentials.getCredentialsId();
  101 + assertNotNull(accessToken);
  102 +
  103 + }
  104 +
  105 + protected DeviceProfile createCoapDeviceProfile(TransportPayloadType transportPayloadType, CoapDeviceType coapDeviceType,
  106 + String attributesProtoSchema, DeviceProfileProvisionType provisionType,
  107 + String provisionKey, String provisionSecret, String telemetryProtoSchema) {
  108 + DeviceProfile deviceProfile = new DeviceProfile();
  109 + deviceProfile.setName(transportPayloadType.name());
  110 + deviceProfile.setType(DeviceProfileType.DEFAULT);
  111 + deviceProfile.setProvisionType(provisionType);
  112 + deviceProfile.setProvisionDeviceKey(provisionKey);
  113 + deviceProfile.setDescription(transportPayloadType.name() + " Test");
  114 + DeviceProfileData deviceProfileData = new DeviceProfileData();
  115 + DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
  116 + deviceProfile.setTransportType(DeviceTransportType.COAP);
  117 + CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = new CoapDeviceProfileTransportConfiguration();
  118 + CoapDeviceTypeConfiguration coapDeviceTypeConfiguration;
  119 + if (CoapDeviceType.DEFAULT.equals(coapDeviceType)) {
  120 + DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = new DefaultCoapDeviceTypeConfiguration();
  121 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration;
  122 + if (TransportPayloadType.PROTOBUF.equals(transportPayloadType)) {
  123 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = new ProtoTransportPayloadConfiguration();
  124 + if (StringUtils.isEmpty(telemetryProtoSchema)) {
  125 + telemetryProtoSchema = DEVICE_TELEMETRY_PROTO_SCHEMA;
  126 + }
  127 + if (StringUtils.isEmpty(attributesProtoSchema)) {
  128 + attributesProtoSchema = DEVICE_ATTRIBUTES_PROTO_SCHEMA;
  129 + }
  130 + protoTransportPayloadConfiguration.setDeviceTelemetryProtoSchema(telemetryProtoSchema);
  131 + protoTransportPayloadConfiguration.setDeviceAttributesProtoSchema(attributesProtoSchema);
  132 + transportPayloadTypeConfiguration = protoTransportPayloadConfiguration;
  133 + } else {
  134 + transportPayloadTypeConfiguration = new JsonTransportPayloadConfiguration();
  135 + }
  136 + defaultCoapDeviceTypeConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration);
  137 + coapDeviceTypeConfiguration = defaultCoapDeviceTypeConfiguration;
  138 + } else {
  139 + coapDeviceTypeConfiguration = new EfentoCoapDeviceTypeConfiguration();
  140 + }
  141 + coapDeviceProfileTransportConfiguration.setCoapDeviceTypeConfiguration(coapDeviceTypeConfiguration);
  142 + deviceProfileData.setTransportConfiguration(coapDeviceProfileTransportConfiguration);
  143 + DeviceProfileProvisionConfiguration provisionConfiguration;
  144 + switch (provisionType) {
  145 + case ALLOW_CREATE_NEW_DEVICES:
  146 + provisionConfiguration = new AllowCreateNewDevicesDeviceProfileProvisionConfiguration(provisionSecret);
  147 + break;
  148 + case CHECK_PRE_PROVISIONED_DEVICES:
  149 + provisionConfiguration = new CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration(provisionSecret);
  150 + break;
  151 + case DISABLED:
  152 + default:
  153 + provisionConfiguration = new DisabledDeviceProfileProvisionConfiguration(provisionSecret);
  154 + break;
  155 + }
  156 + deviceProfileData.setProvisionConfiguration(provisionConfiguration);
  157 + deviceProfileData.setConfiguration(configuration);
  158 + deviceProfile.setProfileData(deviceProfileData);
  159 + deviceProfile.setDefault(false);
  160 + deviceProfile.setDefaultRuleChainId(null);
  161 + return deviceProfile;
  162 + }
  163 +
  164 + protected CoapClient getCoapClient(FeatureType featureType) {
  165 + return new CoapClient(getFeatureTokenUrl(accessToken, featureType));
  166 + }
  167 +
  168 + protected CoapClient getCoapClient(String featureTokenUrl) {
  169 + return new CoapClient(featureTokenUrl);
  170 + }
  171 +
  172 + protected String getFeatureTokenUrl(String token, FeatureType featureType) {
  173 + return COAP_BASE_URL + token + "/" + featureType.name().toLowerCase();
  174 + }
  175 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.attributes;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
  20 +import org.thingsboard.server.common.data.CoapDeviceType;
  21 +import org.thingsboard.server.common.data.TransportPayloadType;
  22 +import org.thingsboard.server.gen.transport.TransportProtos;
  23 +
  24 +import java.util.ArrayList;
  25 +import java.util.List;
  26 +
  27 +@Slf4j
  28 +public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoapIntegrationTest {
  29 +
  30 + protected static final String POST_ATTRIBUTES_PAYLOAD = "{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73," +
  31 + "\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}";
  32 +
  33 + protected void processBeforeTest(String deviceName, CoapDeviceType coapDeviceType, TransportPayloadType payloadType) throws Exception {
  34 + super.processBeforeTest(deviceName, coapDeviceType, payloadType);
  35 + }
  36 +
  37 + protected void processAfterTest() throws Exception {
  38 + super.processAfterTest();
  39 + }
  40 +
  41 + protected List<TransportProtos.TsKvProto> getTsKvProtoList() {
  42 + TransportProtos.TsKvProto tsKvProtoAttribute1 = getTsKvProto("attribute1", "value1", TransportProtos.KeyValueType.STRING_V);
  43 + TransportProtos.TsKvProto tsKvProtoAttribute2 = getTsKvProto("attribute2", "true", TransportProtos.KeyValueType.BOOLEAN_V);
  44 + TransportProtos.TsKvProto tsKvProtoAttribute3 = getTsKvProto("attribute3", "42.0", TransportProtos.KeyValueType.DOUBLE_V);
  45 + TransportProtos.TsKvProto tsKvProtoAttribute4 = getTsKvProto("attribute4", "73", TransportProtos.KeyValueType.LONG_V);
  46 + TransportProtos.TsKvProto tsKvProtoAttribute5 = getTsKvProto("attribute5", "{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}", TransportProtos.KeyValueType.JSON_V);
  47 + List<TransportProtos.TsKvProto> tsKvProtoList = new ArrayList<>();
  48 + tsKvProtoList.add(tsKvProtoAttribute1);
  49 + tsKvProtoList.add(tsKvProtoAttribute2);
  50 + tsKvProtoList.add(tsKvProtoAttribute3);
  51 + tsKvProtoList.add(tsKvProtoAttribute4);
  52 + tsKvProtoList.add(tsKvProtoAttribute5);
  53 + return tsKvProtoList;
  54 + }
  55 +
  56 + protected TransportProtos.TsKvProto getTsKvProto(String key, String value, TransportProtos.KeyValueType keyValueType) {
  57 + TransportProtos.TsKvProto.Builder tsKvProtoBuilder = TransportProtos.TsKvProto.newBuilder();
  58 + TransportProtos.KeyValueProto keyValueProto = getKeyValueProto(key, value, keyValueType);
  59 + tsKvProtoBuilder.setKv(keyValueProto);
  60 + return tsKvProtoBuilder.build();
  61 + }
  62 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.attributes.request;
  17 +
  18 +import com.fasterxml.jackson.core.type.TypeReference;
  19 +import com.google.protobuf.InvalidProtocolBufferException;
  20 +import lombok.extern.slf4j.Slf4j;
  21 +import org.eclipse.californium.core.CoapClient;
  22 +import org.eclipse.californium.core.CoapResponse;
  23 +import org.eclipse.californium.core.coap.CoAP;
  24 +import org.eclipse.californium.core.coap.MediaTypeRegistry;
  25 +import org.junit.After;
  26 +import org.junit.Before;
  27 +import org.junit.Test;
  28 +import org.thingsboard.server.transport.coap.attributes.AbstractCoapAttributesIntegrationTest;
  29 +import org.thingsboard.server.common.msg.session.FeatureType;
  30 +import org.thingsboard.server.dao.util.mapping.JacksonUtil;
  31 +
  32 +import java.nio.charset.StandardCharsets;
  33 +import java.util.List;
  34 +
  35 +import static org.junit.Assert.assertEquals;
  36 +import static org.junit.Assert.assertNotNull;
  37 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  38 +
  39 +@Slf4j
  40 +public abstract class AbstractCoapAttributesRequestIntegrationTest extends AbstractCoapAttributesIntegrationTest {
  41 +
  42 + protected static final long CLIENT_REQUEST_TIMEOUT = 60000L;
  43 +
  44 + @Before
  45 + public void beforeTest() throws Exception {
  46 + processBeforeTest("Test Request attribute values from the server", null, null);
  47 + }
  48 +
  49 + @After
  50 + public void afterTest() throws Exception {
  51 + processAfterTest();
  52 + }
  53 +
  54 + @Test
  55 + public void testRequestAttributesValuesFromTheServer() throws Exception {
  56 + processTestRequestAttributesValuesFromTheServer();
  57 + }
  58 +
  59 + protected void processTestRequestAttributesValuesFromTheServer() throws Exception {
  60 + postAttributes();
  61 +
  62 + long start = System.currentTimeMillis();
  63 + long end = System.currentTimeMillis() + 5000;
  64 +
  65 + List<String> savedAttributeKeys = null;
  66 + while (start <= end) {
  67 + savedAttributeKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/keys/attributes/CLIENT_SCOPE", new TypeReference<>() {});
  68 + if (savedAttributeKeys.size() == 5) {
  69 + break;
  70 + }
  71 + Thread.sleep(100);
  72 + start += 100;
  73 + }
  74 + assertNotNull(savedAttributeKeys);
  75 +
  76 + String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
  77 + String featureTokenUrl = getFeatureTokenUrl(accessToken, FeatureType.ATTRIBUTES) + "?clientKeys=" + keys + "&sharedKeys=" + keys;
  78 + CoapClient client = getCoapClient(featureTokenUrl);
  79 +
  80 + CoapResponse getAttributesResponse = client.setTimeout(CLIENT_REQUEST_TIMEOUT).get();
  81 + validateResponse(getAttributesResponse);
  82 + }
  83 +
  84 + protected void postAttributes() throws Exception {
  85 + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
  86 + CoapClient client = getCoapClient(FeatureType.ATTRIBUTES);
  87 + CoapResponse coapResponse = client.setTimeout(CLIENT_REQUEST_TIMEOUT).post(POST_ATTRIBUTES_PAYLOAD.getBytes(), MediaTypeRegistry.APPLICATION_JSON);
  88 + assertEquals(CoAP.ResponseCode.CREATED, coapResponse.getCode());
  89 + }
  90 +
  91 + protected void validateResponse(CoapResponse getAttributesResponse) throws InvalidProtocolBufferException {
  92 + assertEquals(CoAP.ResponseCode.CONTENT, getAttributesResponse.getCode());
  93 + String expectedRequestPayload = "{\"client\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}},\"shared\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}";
  94 + assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(getAttributesResponse.getPayload(), StandardCharsets.UTF_8)));
  95 + }
  96 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.attributes.request;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.junit.After;
  20 +import org.junit.Before;
  21 +import org.junit.Test;
  22 +import org.thingsboard.server.common.data.CoapDeviceType;
  23 +import org.thingsboard.server.common.data.TransportPayloadType;
  24 +
  25 +@Slf4j
  26 +public abstract class AbstractCoapAttributesRequestJsonIntegrationTest extends AbstractCoapAttributesRequestIntegrationTest {
  27 +
  28 + @Before
  29 + public void beforeTest() throws Exception {
  30 + processBeforeTest("Test Request attribute values from the server json", CoapDeviceType.DEFAULT, TransportPayloadType.JSON);
  31 + }
  32 +
  33 + @After
  34 + public void afterTest() throws Exception {
  35 + processAfterTest();
  36 + }
  37 +
  38 + @Test
  39 + public void testRequestAttributesValuesFromTheServer() throws Exception {
  40 + super.testRequestAttributesValuesFromTheServer();
  41 + }
  42 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.attributes.request;
  17 +
  18 +import com.github.os72.protobuf.dynamic.DynamicSchema;
  19 +import com.google.protobuf.Descriptors;
  20 +import com.google.protobuf.DynamicMessage;
  21 +import com.google.protobuf.InvalidProtocolBufferException;
  22 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
  23 +import lombok.extern.slf4j.Slf4j;
  24 +import org.eclipse.californium.core.CoapClient;
  25 +import org.eclipse.californium.core.CoapResponse;
  26 +import org.eclipse.californium.core.coap.CoAP;
  27 +import org.eclipse.californium.core.coap.MediaTypeRegistry;
  28 +import org.junit.After;
  29 +import org.junit.Test;
  30 +import org.thingsboard.server.common.data.CoapDeviceType;
  31 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
  32 +import org.thingsboard.server.common.data.TransportPayloadType;
  33 +import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
  34 +import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration;
  35 +import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration;
  36 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  37 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  38 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
  39 +import org.thingsboard.server.common.msg.session.FeatureType;
  40 +import org.thingsboard.server.gen.transport.TransportProtos;
  41 +
  42 +import java.util.List;
  43 +import java.util.stream.Collectors;
  44 +
  45 +import static org.junit.Assert.assertEquals;
  46 +import static org.junit.Assert.assertNotNull;
  47 +import static org.junit.Assert.assertTrue;
  48 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  49 +
  50 +@Slf4j
  51 +public abstract class AbstractCoapAttributesRequestProtoIntegrationTest extends AbstractCoapAttributesRequestIntegrationTest {
  52 +
  53 + public static final String ATTRIBUTES_SCHEMA_STR = "syntax =\"proto3\";\n" +
  54 + "\n" +
  55 + "package test;\n" +
  56 + "\n" +
  57 + "message PostAttributes {\n" +
  58 + " string attribute1 = 1;\n" +
  59 + " bool attribute2 = 2;\n" +
  60 + " double attribute3 = 3;\n" +
  61 + " int32 attribute4 = 4;\n" +
  62 + " JsonObject attribute5 = 5;\n" +
  63 + "\n" +
  64 + " message JsonObject {\n" +
  65 + " int32 someNumber = 6;\n" +
  66 + " repeated int32 someArray = 7;\n" +
  67 + " NestedJsonObject someNestedObject = 8;\n" +
  68 + " message NestedJsonObject {\n" +
  69 + " string key = 9;\n" +
  70 + " }\n" +
  71 + " }\n" +
  72 + "}";
  73 +
  74 + @After
  75 + public void afterTest() throws Exception {
  76 + processAfterTest();
  77 + }
  78 +
  79 + @Test
  80 + public void testRequestAttributesValuesFromTheServer() throws Exception {
  81 + super.processBeforeTest("Test Request attribute values from the server proto", CoapDeviceType.DEFAULT,
  82 + TransportPayloadType.PROTOBUF, null, ATTRIBUTES_SCHEMA_STR, DeviceProfileProvisionType.DISABLED, null, null);
  83 + processTestRequestAttributesValuesFromTheServer();
  84 + }
  85 +
  86 + protected void postAttributes() throws Exception {
  87 + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
  88 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  89 + assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration);
  90 + CoapDeviceProfileTransportConfiguration coapTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration;
  91 + CoapDeviceTypeConfiguration coapDeviceTypeConfiguration = coapTransportConfiguration.getCoapDeviceTypeConfiguration();
  92 + assertTrue(coapDeviceTypeConfiguration instanceof DefaultCoapDeviceTypeConfiguration);
  93 + DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = (DefaultCoapDeviceTypeConfiguration) coapDeviceTypeConfiguration;
  94 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = defaultCoapDeviceTypeConfiguration.getTransportPayloadTypeConfiguration();
  95 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  96 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  97 + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(ATTRIBUTES_SCHEMA_STR);
  98 + DynamicSchema attributesSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA);
  99 +
  100 + DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject");
  101 + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
  102 + assertNotNull(nestedJsonObjectBuilderDescriptor);
  103 + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
  104 +
  105 + DynamicMessage.Builder jsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject");
  106 + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
  107 + assertNotNull(jsonObjectBuilderDescriptor);
  108 + DynamicMessage jsonObject = jsonObjectBuilder
  109 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
  110 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
  111 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
  112 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
  113 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
  114 + .build();
  115 +
  116 + DynamicMessage.Builder postAttributesBuilder = attributesSchema.newMessageBuilder("PostAttributes");
  117 + Descriptors.Descriptor postAttributesMsgDescriptor = postAttributesBuilder.getDescriptorForType();
  118 + assertNotNull(postAttributesMsgDescriptor);
  119 + DynamicMessage postAttributesMsg = postAttributesBuilder
  120 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute1"), "value1")
  121 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute2"), true)
  122 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute3"), 42.0)
  123 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute4"), 73)
  124 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute5"), jsonObject)
  125 + .build();
  126 + byte[] payload = postAttributesMsg.toByteArray();
  127 + CoapClient client = getCoapClient(FeatureType.ATTRIBUTES);
  128 + CoapResponse coapResponse = client.setTimeout(CLIENT_REQUEST_TIMEOUT).post(payload, MediaTypeRegistry.APPLICATION_JSON);
  129 + assertEquals(CoAP.ResponseCode.CREATED, coapResponse.getCode());
  130 + }
  131 +
  132 + protected void validateResponse(CoapResponse getAttributesResponse) throws InvalidProtocolBufferException {
  133 + TransportProtos.GetAttributeResponseMsg expectedAttributesResponse = getExpectedAttributeResponseMsg();
  134 + TransportProtos.GetAttributeResponseMsg actualAttributesResponse = TransportProtos.GetAttributeResponseMsg.parseFrom(getAttributesResponse.getPayload());
  135 + assertEquals(expectedAttributesResponse.getRequestId(), actualAttributesResponse.getRequestId());
  136 + List<TransportProtos.KeyValueProto> expectedClientKeyValueProtos = expectedAttributesResponse.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  137 + List<TransportProtos.KeyValueProto> expectedSharedKeyValueProtos = expectedAttributesResponse.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  138 + List<TransportProtos.KeyValueProto> actualClientKeyValueProtos = actualAttributesResponse.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  139 + List<TransportProtos.KeyValueProto> actualSharedKeyValueProtos = actualAttributesResponse.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  140 + assertTrue(actualClientKeyValueProtos.containsAll(expectedClientKeyValueProtos));
  141 + assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos));
  142 + }
  143 +
  144 + private TransportProtos.GetAttributeResponseMsg getExpectedAttributeResponseMsg() {
  145 + TransportProtos.GetAttributeResponseMsg.Builder result = TransportProtos.GetAttributeResponseMsg.newBuilder();
  146 + List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList();
  147 + result.addAllClientAttributeList(tsKvProtoList);
  148 + result.addAllSharedAttributeList(tsKvProtoList);
  149 + result.setRequestId(0);
  150 + return result.build();
  151 + }
  152 +
  153 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.attributes.request.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.attributes.request.AbstractCoapAttributesRequestJsonIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +@DaoSqlTest
  22 +public class CoapAttributesRequestJsonSqlIntegrationTest extends AbstractCoapAttributesRequestJsonIntegrationTest {
  23 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.attributes.request.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.attributes.request.AbstractCoapAttributesRequestProtoIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +@DaoSqlTest
  22 +public class CoapAttributesRequestProtoSqlIntegrationTest extends AbstractCoapAttributesRequestProtoIntegrationTest {
  23 +}
... ...
application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/sql/CoapAttributesRequestSqlIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/attributes/nosql/MqttAttributesNoSqlProtoIntegrationTest.java
... ... @@ -13,11 +13,11 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.attributes.nosql;
  16 +package org.thingsboard.server.transport.coap.attributes.request.sql;
17 17
18   -import org.thingsboard.server.dao.service.DaoNoSqlTest;
19   -import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest;
  18 +import org.thingsboard.server.transport.coap.attributes.request.AbstractCoapAttributesRequestIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
20 20
21   -@DaoNoSqlTest
22   -public class MqttAttributesNoSqlProtoIntegrationTest extends AbstractMqttAttributesProtoIntegrationTest {
  21 +@DaoSqlTest
  22 +public class CoapAttributesRequestSqlIntegrationTest extends AbstractCoapAttributesRequestIntegrationTest {
23 23 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.attributes.updates;
  17 +
  18 +import com.google.protobuf.InvalidProtocolBufferException;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.eclipse.californium.core.CoapClient;
  21 +import org.eclipse.californium.core.CoapHandler;
  22 +import org.eclipse.californium.core.CoapObserveRelation;
  23 +import org.eclipse.californium.core.CoapResponse;
  24 +import org.eclipse.californium.core.coap.CoAP;
  25 +import org.eclipse.californium.core.coap.Request;
  26 +import org.junit.After;
  27 +import org.junit.Before;
  28 +import org.junit.Test;
  29 +import org.thingsboard.server.transport.coap.attributes.AbstractCoapAttributesIntegrationTest;
  30 +import org.thingsboard.server.common.msg.session.FeatureType;
  31 +import org.thingsboard.server.dao.util.mapping.JacksonUtil;
  32 +
  33 +import java.nio.charset.StandardCharsets;
  34 +import java.util.concurrent.CountDownLatch;
  35 +import java.util.concurrent.TimeUnit;
  36 +
  37 +import static org.junit.Assert.assertEquals;
  38 +import static org.junit.Assert.assertNotNull;
  39 +import static org.junit.Assert.assertTrue;
  40 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  41 +
  42 +@Slf4j
  43 +public abstract class AbstractCoapAttributesUpdatesIntegrationTest extends AbstractCoapAttributesIntegrationTest {
  44 +
  45 + private static final String RESPONSE_ATTRIBUTES_PAYLOAD_DELETED = "{\"deleted\":[\"attribute5\"]}";
  46 +
  47 + @Before
  48 + public void beforeTest() throws Exception {
  49 + processBeforeTest("Test Subscribe to attribute updates", null, null);
  50 + }
  51 +
  52 + @After
  53 + public void afterTest() throws Exception {
  54 + processAfterTest();
  55 + }
  56 +
  57 + @Test
  58 + public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception {
  59 + processTestSubscribeToAttributesUpdates();
  60 + }
  61 +
  62 + protected void processTestSubscribeToAttributesUpdates() throws Exception {
  63 +
  64 + CoapClient client = getCoapClient(FeatureType.ATTRIBUTES);
  65 +
  66 + CountDownLatch latch = new CountDownLatch(1);
  67 + TestCoapCallback testCoapCallback = new TestCoapCallback(latch);
  68 +
  69 + Request request = Request.newGet().setObserve();
  70 + request.setType(CoAP.Type.CON);
  71 + CoapObserveRelation observeRelation = client.observe(request, testCoapCallback);
  72 +
  73 + Thread.sleep(1000);
  74 +
  75 + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
  76 + latch.await(3, TimeUnit.SECONDS);
  77 +
  78 + validateUpdateAttributesResponse(testCoapCallback);
  79 +
  80 + latch = new CountDownLatch(1);
  81 +
  82 + doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class);
  83 + latch.await(3, TimeUnit.SECONDS);
  84 +
  85 + validateDeleteAttributesResponse(testCoapCallback);
  86 +
  87 + observeRelation.proactiveCancel();
  88 + assertTrue(observeRelation.isCanceled());
  89 + }
  90 +
  91 + protected void validateUpdateAttributesResponse(TestCoapCallback callback) throws InvalidProtocolBufferException {
  92 + assertNotNull(callback.getPayloadBytes());
  93 + assertNotNull(callback.getObserve());
  94 + assertEquals(0, callback.getObserve().intValue());
  95 + String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8);
  96 + assertEquals(JacksonUtil.toJsonNode(POST_ATTRIBUTES_PAYLOAD), JacksonUtil.toJsonNode(response));
  97 + }
  98 +
  99 + protected void validateDeleteAttributesResponse(TestCoapCallback callback) throws InvalidProtocolBufferException {
  100 + assertNotNull(callback.getPayloadBytes());
  101 + assertNotNull(callback.getObserve());
  102 + assertEquals(1, callback.getObserve().intValue());
  103 + String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8);
  104 + assertEquals(JacksonUtil.toJsonNode(RESPONSE_ATTRIBUTES_PAYLOAD_DELETED), JacksonUtil.toJsonNode(response));
  105 + }
  106 +
  107 + protected static class TestCoapCallback implements CoapHandler {
  108 +
  109 + private final CountDownLatch latch;
  110 +
  111 + private Integer observe;
  112 + private byte[] payloadBytes;
  113 +
  114 + public byte[] getPayloadBytes() {
  115 + return payloadBytes;
  116 + }
  117 +
  118 + public Integer getObserve() {
  119 + return observe;
  120 + }
  121 +
  122 + private TestCoapCallback(CountDownLatch latch) {
  123 + this.latch = latch;
  124 + }
  125 +
  126 + @Override
  127 + public void onLoad(CoapResponse response) {
  128 + assertNotNull(response.getPayload());
  129 + assertEquals(response.getCode(), CoAP.ResponseCode.CONTENT);
  130 + observe = response.getOptions().getObserve();
  131 + payloadBytes = response.getPayload();
  132 + latch.countDown();
  133 + }
  134 +
  135 + @Override
  136 + public void onError() {
  137 + log.warn("Command Response Ack Error, No connect");
  138 + }
  139 +
  140 + }
  141 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.attributes.updates;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.junit.After;
  20 +import org.junit.Before;
  21 +import org.junit.Test;
  22 +import org.thingsboard.server.common.data.CoapDeviceType;
  23 +import org.thingsboard.server.common.data.TransportPayloadType;
  24 +
  25 +@Slf4j
  26 +public abstract class AbstractCoapAttributesUpdatesJsonIntegrationTest extends AbstractCoapAttributesUpdatesIntegrationTest {
  27 +
  28 + @Before
  29 + public void beforeTest() throws Exception {
  30 + processBeforeTest("Test Subscribe to attribute updates", CoapDeviceType.DEFAULT, TransportPayloadType.JSON);
  31 + }
  32 +
  33 + @After
  34 + public void afterTest() throws Exception {
  35 + processAfterTest();
  36 + }
  37 +
  38 + @Test
  39 + public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception {
  40 + super.testSubscribeToAttributesUpdatesFromTheServer();
  41 + }
  42 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.attributes.updates;
  17 +
  18 +import com.google.protobuf.InvalidProtocolBufferException;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.junit.After;
  21 +import org.junit.Before;
  22 +import org.junit.Test;
  23 +import org.thingsboard.server.common.data.CoapDeviceType;
  24 +import org.thingsboard.server.common.data.TransportPayloadType;
  25 +import org.thingsboard.server.gen.transport.TransportProtos;
  26 +
  27 +import java.util.List;
  28 +import java.util.stream.Collectors;
  29 +
  30 +import static org.junit.Assert.assertEquals;
  31 +import static org.junit.Assert.assertNotNull;
  32 +import static org.junit.Assert.assertTrue;
  33 +
  34 +@Slf4j
  35 +public abstract class AbstractCoapAttributesUpdatesProtoIntegrationTest extends AbstractCoapAttributesUpdatesIntegrationTest {
  36 +
  37 + @Before
  38 + public void beforeTest() throws Exception {
  39 + processBeforeTest("Test Subscribe to attribute updates", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF);
  40 + }
  41 +
  42 + @After
  43 + public void afterTest() throws Exception {
  44 + processAfterTest();
  45 + }
  46 +
  47 + @Test
  48 + public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception {
  49 + processTestSubscribeToAttributesUpdates();
  50 + }
  51 +
  52 + protected void validateUpdateAttributesResponse(TestCoapCallback callback) throws InvalidProtocolBufferException {
  53 + assertNotNull(callback.getPayloadBytes());
  54 + TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
  55 + List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList();
  56 + attributeUpdateNotificationMsgBuilder.addAllSharedUpdated(tsKvProtoList);
  57 +
  58 + TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build();
  59 + TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = TransportProtos.AttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes());
  60 +
  61 + List<TransportProtos.KeyValueProto> actualSharedUpdatedList = actualAttributeUpdateNotificationMsg.getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  62 + List<TransportProtos.KeyValueProto> expectedSharedUpdatedList = expectedAttributeUpdateNotificationMsg.getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  63 +
  64 + assertEquals(expectedSharedUpdatedList.size(), actualSharedUpdatedList.size());
  65 + assertTrue(actualSharedUpdatedList.containsAll(expectedSharedUpdatedList));
  66 +
  67 + }
  68 +
  69 + protected void validateDeleteAttributesResponse(TestCoapCallback callback) throws InvalidProtocolBufferException {
  70 + assertNotNull(callback.getPayloadBytes());
  71 + TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
  72 + attributeUpdateNotificationMsgBuilder.addSharedDeleted("attribute5");
  73 +
  74 + TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build();
  75 + TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = TransportProtos.AttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes());
  76 +
  77 + assertEquals(expectedAttributeUpdateNotificationMsg.getSharedDeletedList().size(), actualAttributeUpdateNotificationMsg.getSharedDeletedList().size());
  78 + assertEquals("attribute5", actualAttributeUpdateNotificationMsg.getSharedDeletedList().get(0));
  79 +
  80 + }
  81 +
  82 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.attributes.updates.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.attributes.updates.AbstractCoapAttributesUpdatesIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +@DaoSqlTest
  22 +public class CoapAttributesUpdatesSqlIntegrationTest extends AbstractCoapAttributesUpdatesIntegrationTest {
  23 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.attributes.updates.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.attributes.updates.AbstractCoapAttributesUpdatesJsonIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +@DaoSqlTest
  22 +public class CoapAttributesUpdatesSqlJsonIntegrationTest extends AbstractCoapAttributesUpdatesJsonIntegrationTest {
  23 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.attributes.updates.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.attributes.updates.AbstractCoapAttributesUpdatesProtoIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +@DaoSqlTest
  22 +public class CoapAttributesUpdatesSqlProtoIntegrationTest extends AbstractCoapAttributesUpdatesProtoIntegrationTest {
  23 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.claim;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.eclipse.californium.core.CoapClient;
  20 +import org.eclipse.californium.core.CoapResponse;
  21 +import org.eclipse.californium.core.coap.CoAP;
  22 +import org.eclipse.californium.core.coap.MediaTypeRegistry;
  23 +import org.eclipse.californium.elements.exception.ConnectorException;
  24 +import org.junit.After;
  25 +import org.junit.Before;
  26 +import org.junit.Test;
  27 +import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
  28 +import org.thingsboard.server.common.data.ClaimRequest;
  29 +import org.thingsboard.server.common.data.Customer;
  30 +import org.thingsboard.server.common.data.Device;
  31 +import org.thingsboard.server.common.data.User;
  32 +import org.thingsboard.server.common.data.security.Authority;
  33 +import org.thingsboard.server.common.msg.session.FeatureType;
  34 +import org.thingsboard.server.dao.device.claim.ClaimResponse;
  35 +import org.thingsboard.server.dao.device.claim.ClaimResult;
  36 +
  37 +import java.io.IOException;
  38 +
  39 +import static org.junit.Assert.assertEquals;
  40 +import static org.junit.Assert.assertNotNull;
  41 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  42 +
  43 +@Slf4j
  44 +public abstract class AbstractCoapClaimDeviceTest extends AbstractCoapIntegrationTest {
  45 +
  46 + protected static final String CUSTOMER_USER_PASSWORD = "customerUser123!";
  47 +
  48 + protected User customerAdmin;
  49 + protected Customer savedCustomer;
  50 +
  51 + @Before
  52 + public void beforeTest() throws Exception {
  53 + super.processBeforeTest("Test Claim device", null, null);
  54 + createCustomerAndUser();
  55 + }
  56 +
  57 + protected void createCustomerAndUser() throws Exception {
  58 + Customer customer = new Customer();
  59 + customer.setTenantId(savedTenant.getId());
  60 + customer.setTitle("Test Claiming Customer");
  61 + savedCustomer = doPost("/api/customer", customer, Customer.class);
  62 + assertNotNull(savedCustomer);
  63 + assertEquals(savedTenant.getId(), savedCustomer.getTenantId());
  64 +
  65 + User user = new User();
  66 + user.setAuthority(Authority.CUSTOMER_USER);
  67 + user.setTenantId(savedTenant.getId());
  68 + user.setCustomerId(savedCustomer.getId());
  69 + user.setEmail("customer@thingsboard.org");
  70 +
  71 + customerAdmin = createUser(user, CUSTOMER_USER_PASSWORD);
  72 + assertNotNull(customerAdmin);
  73 + assertEquals(customerAdmin.getCustomerId(), savedCustomer.getId());
  74 + }
  75 +
  76 + @After
  77 + public void afterTest() throws Exception {
  78 + super.processAfterTest();
  79 + }
  80 +
  81 + @Test
  82 + public void testClaimingDevice() throws Exception {
  83 + processTestClaimingDevice(false);
  84 + }
  85 +
  86 + @Test
  87 + public void testClaimingDeviceWithoutSecretAndDuration() throws Exception {
  88 + processTestClaimingDevice(true);
  89 + }
  90 +
  91 + protected void processTestClaimingDevice(boolean emptyPayload) throws Exception {
  92 + log.warn("[testClaimingDevice] Device: {}, Transport type: {}", savedDevice.getName(), savedDevice.getType());
  93 + CoapClient client = getCoapClient(FeatureType.CLAIM);
  94 + byte[] payloadBytes;
  95 + byte[] failurePayloadBytes;
  96 + if (emptyPayload) {
  97 + payloadBytes = "{}".getBytes();
  98 + failurePayloadBytes = "{\"durationMs\":1}".getBytes();
  99 + } else {
  100 + payloadBytes = "{\"secretKey\":\"value\", \"durationMs\":60000}".getBytes();
  101 + failurePayloadBytes = "{\"secretKey\":\"value\", \"durationMs\":1}".getBytes();
  102 + }
  103 + validateClaimResponse(emptyPayload, client, payloadBytes, failurePayloadBytes);
  104 + }
  105 +
  106 + protected void validateClaimResponse(boolean emptyPayload, CoapClient client, byte[] payloadBytes, byte[] failurePayloadBytes) throws Exception {
  107 + postClaimRequest(client, failurePayloadBytes);
  108 +
  109 + loginUser(customerAdmin.getName(), CUSTOMER_USER_PASSWORD);
  110 + ClaimRequest claimRequest;
  111 + if (!emptyPayload) {
  112 + claimRequest = new ClaimRequest("value");
  113 + } else {
  114 + claimRequest = new ClaimRequest(null);
  115 + }
  116 +
  117 + ClaimResponse claimResponse = doExecuteWithRetriesAndInterval(
  118 + () -> doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResponse.class, status().isBadRequest()),
  119 + 20,
  120 + 100
  121 + );
  122 +
  123 + assertEquals(claimResponse, ClaimResponse.FAILURE);
  124 +
  125 + postClaimRequest(client, payloadBytes);
  126 +
  127 + ClaimResult claimResult = doExecuteWithRetriesAndInterval(
  128 + () -> doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResult.class, status().isOk()),
  129 + 20,
  130 + 100
  131 + );
  132 + assertEquals(claimResult.getResponse(), ClaimResponse.SUCCESS);
  133 + Device claimedDevice = claimResult.getDevice();
  134 + assertNotNull(claimedDevice);
  135 + assertNotNull(claimedDevice.getCustomerId());
  136 + assertEquals(customerAdmin.getCustomerId(), claimedDevice.getCustomerId());
  137 +
  138 + claimResponse = doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResponse.class, status().isBadRequest());
  139 + assertEquals(claimResponse, ClaimResponse.CLAIMED);
  140 + }
  141 +
  142 + private void postClaimRequest(CoapClient client, byte[] payload) throws IOException, ConnectorException {
  143 + CoapResponse coapResponse = client.setTimeout((long) 60000).post(payload, MediaTypeRegistry.APPLICATION_JSON);
  144 + assertEquals(CoAP.ResponseCode.CREATED, coapResponse.getCode());
  145 + }
  146 +
  147 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.claim;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.junit.After;
  20 +import org.junit.Before;
  21 +import org.junit.Test;
  22 +import org.thingsboard.server.common.data.CoapDeviceType;
  23 +import org.thingsboard.server.common.data.TransportPayloadType;
  24 +
  25 +@Slf4j
  26 +public abstract class AbstractCoapClaimJsonDeviceTest extends AbstractCoapClaimDeviceTest {
  27 +
  28 + @Before
  29 + public void beforeTest() throws Exception {
  30 + super.processBeforeTest("Test Claim device Json", CoapDeviceType.DEFAULT, TransportPayloadType.JSON);
  31 + createCustomerAndUser();
  32 + }
  33 +
  34 + @After
  35 + public void afterTest() throws Exception {
  36 + super.afterTest();
  37 + }
  38 +
  39 + @Test
  40 + public void testClaimingDevice() throws Exception {
  41 + super.testClaimingDevice();
  42 + }
  43 +
  44 + @Test
  45 + public void testClaimingDeviceWithoutSecretAndDuration() throws Exception {
  46 + super.testClaimingDeviceWithoutSecretAndDuration();
  47 + }
  48 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.claim;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.eclipse.californium.core.CoapClient;
  20 +import org.junit.After;
  21 +import org.junit.Before;
  22 +import org.junit.Test;
  23 +import org.thingsboard.server.common.data.CoapDeviceType;
  24 +import org.thingsboard.server.common.data.TransportPayloadType;
  25 +import org.thingsboard.server.common.msg.session.FeatureType;
  26 +import org.thingsboard.server.gen.transport.TransportApiProtos;
  27 +
  28 +@Slf4j
  29 +public abstract class AbstractCoapClaimProtoDeviceTest extends AbstractCoapClaimDeviceTest {
  30 +
  31 + @Before
  32 + public void beforeTest() throws Exception {
  33 + processBeforeTest("Test Claim device Proto", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF);
  34 + createCustomerAndUser();
  35 + }
  36 +
  37 + @After
  38 + public void afterTest() throws Exception { super.afterTest(); }
  39 +
  40 + @Test
  41 + public void testClaimingDevice() throws Exception {
  42 + processTestClaimingDevice(false);
  43 + }
  44 +
  45 + @Test
  46 + public void testClaimingDeviceWithoutSecretAndDuration() throws Exception {
  47 + processTestClaimingDevice(true);
  48 + }
  49 +
  50 + @Override
  51 + protected void processTestClaimingDevice(boolean emptyPayload) throws Exception {
  52 + CoapClient client = getCoapClient(FeatureType.CLAIM);
  53 + byte[] payloadBytes;
  54 + if (emptyPayload) {
  55 + TransportApiProtos.ClaimDevice claimDevice = getClaimDevice(0, emptyPayload);
  56 + payloadBytes = claimDevice.toByteArray();
  57 + } else {
  58 + TransportApiProtos.ClaimDevice claimDevice = getClaimDevice(60000, emptyPayload);
  59 + payloadBytes = claimDevice.toByteArray();
  60 + }
  61 + TransportApiProtos.ClaimDevice claimDevice = getClaimDevice(1, emptyPayload);
  62 + byte[] failurePayloadBytes = claimDevice.toByteArray();
  63 + validateClaimResponse(emptyPayload, client, payloadBytes, failurePayloadBytes);
  64 + }
  65 +
  66 + private TransportApiProtos.ClaimDevice getClaimDevice(long duration, boolean emptyPayload) {
  67 + TransportApiProtos.ClaimDevice.Builder claimDeviceBuilder = TransportApiProtos.ClaimDevice.newBuilder();
  68 + if (!emptyPayload) {
  69 + claimDeviceBuilder.setSecretKey("value");
  70 + }
  71 + if (duration > 0) {
  72 + claimDeviceBuilder.setSecretKey("value");
  73 + claimDeviceBuilder.setDurationMs(duration);
  74 + } else {
  75 + claimDeviceBuilder.setDurationMs(0);
  76 + }
  77 + return claimDeviceBuilder.build();
  78 + }
  79 +
  80 +
  81 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.claim.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.claim.AbstractCoapClaimJsonDeviceTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +@DaoSqlTest
  22 +public class CoapClaimDeviceJsonSqlTest extends AbstractCoapClaimJsonDeviceTest {
  23 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.claim.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.claim.AbstractCoapClaimProtoDeviceTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +@DaoSqlTest
  22 +public class CoapClaimDeviceProtoSqlTest extends AbstractCoapClaimProtoDeviceTest {
  23 +}
... ...
application/src/test/java/org/thingsboard/server/transport/coap/claim/sql/CoapClaimDeviceSqlTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/updates/nosql/MqttAttributesUpdatesNoSqlIntegrationTest.java
... ... @@ -13,12 +13,11 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes.updates.nosql;
  16 +package org.thingsboard.server.transport.coap.claim.sql;
17 17
18   -import org.thingsboard.server.dao.service.DaoNoSqlTest;
19   -import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest;
  18 +import org.thingsboard.server.transport.coap.claim.AbstractCoapClaimDeviceTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
20 20
21   -
22   -@DaoNoSqlTest
23   -public class MqttAttributesUpdatesNoSqlIntegrationTest extends AbstractMqttAttributesUpdatesJsonIntegrationTest {
  21 +@DaoSqlTest
  22 +public class CoapClaimDeviceSqlTest extends AbstractCoapClaimDeviceTest {
24 23 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.provision;
  17 +
  18 +import com.google.gson.JsonObject;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.eclipse.californium.core.CoapClient;
  21 +import org.eclipse.californium.core.CoapResponse;
  22 +import org.eclipse.californium.core.coap.MediaTypeRegistry;
  23 +import org.eclipse.californium.elements.exception.ConnectorException;
  24 +import org.junit.After;
  25 +import org.junit.Assert;
  26 +import org.junit.Test;
  27 +import org.springframework.beans.factory.annotation.Autowired;
  28 +import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
  29 +import org.thingsboard.server.common.data.CoapDeviceType;
  30 +import org.thingsboard.server.common.data.Device;
  31 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
  32 +import org.thingsboard.server.common.data.TransportPayloadType;
  33 +import org.thingsboard.server.common.data.security.DeviceCredentials;
  34 +import org.thingsboard.server.common.msg.EncryptionUtil;
  35 +import org.thingsboard.server.common.msg.session.FeatureType;
  36 +import org.thingsboard.server.common.transport.util.JsonUtils;
  37 +import org.thingsboard.server.dao.device.DeviceCredentialsService;
  38 +import org.thingsboard.server.dao.device.DeviceService;
  39 +import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus;
  40 +
  41 +import java.io.IOException;
  42 +
  43 +import static org.junit.Assert.assertEquals;
  44 +
  45 +@Slf4j
  46 +public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIntegrationTest {
  47 +
  48 + @Autowired
  49 + DeviceCredentialsService deviceCredentialsService;
  50 +
  51 + @Autowired
  52 + DeviceService deviceService;
  53 +
  54 + @After
  55 + public void afterTest() throws Exception {
  56 + super.processAfterTest();
  57 + }
  58 +
  59 + @Test
  60 + public void testProvisioningDisabledDevice() throws Exception {
  61 + processTestProvisioningDisabledDevice();
  62 + }
  63 +
  64 + @Test
  65 + public void testProvisioningCheckPreProvisionedDevice() throws Exception {
  66 + processTestProvisioningCheckPreProvisionedDevice();
  67 + }
  68 +
  69 + @Test
  70 + public void testProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
  71 + processTestProvisioningCreateNewDeviceWithoutCredentials();
  72 + }
  73 +
  74 + @Test
  75 + public void testProvisioningCreateNewDeviceWithAccessToken() throws Exception {
  76 + processTestProvisioningCreateNewDeviceWithAccessToken();
  77 + }
  78 +
  79 + @Test
  80 + public void testProvisioningCreateNewDeviceWithCert() throws Exception {
  81 + processTestProvisioningCreateNewDeviceWithCert();
  82 + }
  83 +
  84 + @Test
  85 + public void testProvisioningWithBadKeyDevice() throws Exception {
  86 + processTestProvisioningWithBadKeyDevice();
  87 + }
  88 +
  89 +
  90 + private void processTestProvisioningDisabledDevice() throws Exception {
  91 + super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.DISABLED, null, null);
  92 + byte[] result = createCoapClientAndPublish().getPayload();
  93 + JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
  94 + Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
  95 + Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.get("status").getAsString());
  96 + }
  97 +
  98 +
  99 + private void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
  100 + super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  101 + byte[] result = createCoapClientAndPublish().getPayload();
  102 + JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
  103 +
  104 + Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
  105 +
  106 + Assert.assertNotNull(createdDevice);
  107 +
  108 + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
  109 +
  110 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
  111 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
  112 + }
  113 +
  114 +
  115 + private void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
  116 + super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  117 + String requestCredentials = ",\"credentialsType\": \"ACCESS_TOKEN\",\"token\": \"test_token\"";
  118 + byte[] result = createCoapClientAndPublish(requestCredentials).getPayload();
  119 + JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
  120 +
  121 + Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
  122 +
  123 + Assert.assertNotNull(createdDevice);
  124 +
  125 + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
  126 +
  127 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
  128 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "ACCESS_TOKEN");
  129 + Assert.assertEquals(deviceCredentials.getCredentialsId(), "test_token");
  130 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
  131 + }
  132 +
  133 +
  134 + private void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
  135 + super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  136 + String requestCredentials = ",\"credentialsType\": \"X509_CERTIFICATE\",\"hash\": \"testHash\"";
  137 + byte[] result = createCoapClientAndPublish(requestCredentials).getPayload();
  138 + JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
  139 +
  140 + Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
  141 +
  142 + Assert.assertNotNull(createdDevice);
  143 +
  144 + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
  145 +
  146 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
  147 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "X509_CERTIFICATE");
  148 +
  149 + String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue());
  150 + String sha3Hash = EncryptionUtil.getSha3Hash(cert);
  151 +
  152 + Assert.assertEquals(deviceCredentials.getCredentialsId(), sha3Hash);
  153 +
  154 + Assert.assertEquals(deviceCredentials.getCredentialsValue(), "testHash");
  155 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
  156 + }
  157 +
  158 + private void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
  159 + super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret");
  160 + byte[] result = createCoapClientAndPublish().getPayload();
  161 + JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
  162 +
  163 + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId());
  164 +
  165 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
  166 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
  167 + }
  168 +
  169 + private void processTestProvisioningWithBadKeyDevice() throws Exception {
  170 + super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret");
  171 + byte[] result = createCoapClientAndPublish().getPayload();
  172 + JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
  173 + Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
  174 + Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.get("status").getAsString());
  175 + }
  176 +
  177 + private CoapResponse createCoapClientAndPublish() throws Exception {
  178 + return createCoapClientAndPublish("");
  179 + }
  180 +
  181 + private CoapResponse createCoapClientAndPublish(String deviceCredentials) throws Exception {
  182 + String provisionRequestMsg = createTestProvisionMessage(deviceCredentials);
  183 + CoapClient client = getCoapClient(FeatureType.PROVISION);
  184 + return postProvision(client, provisionRequestMsg.getBytes());
  185 + }
  186 +
  187 +
  188 + private CoapResponse postProvision(CoapClient client, byte[] payload) throws IOException, ConnectorException {
  189 + return client.setTimeout((long) 60000).post(payload, MediaTypeRegistry.APPLICATION_JSON);
  190 + }
  191 +
  192 + private String createTestProvisionMessage(String deviceCredentials) {
  193 + return "{\"deviceName\":\"Test Provision device\",\"provisionDeviceKey\":\"testProvisionKey\", \"provisionDeviceSecret\":\"testProvisionSecret\"" + deviceCredentials + "}";
  194 + }
  195 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.provision;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.eclipse.californium.core.CoapClient;
  20 +import org.eclipse.californium.core.CoapResponse;
  21 +import org.eclipse.californium.core.coap.MediaTypeRegistry;
  22 +import org.eclipse.californium.elements.exception.ConnectorException;
  23 +import org.junit.After;
  24 +import org.junit.Assert;
  25 +import org.junit.Test;
  26 +import org.springframework.beans.factory.annotation.Autowired;
  27 +import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
  28 +import org.thingsboard.server.common.data.CoapDeviceType;
  29 +import org.thingsboard.server.common.data.Device;
  30 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
  31 +import org.thingsboard.server.common.data.TransportPayloadType;
  32 +import org.thingsboard.server.common.data.security.DeviceCredentials;
  33 +import org.thingsboard.server.common.data.security.DeviceCredentialsType;
  34 +import org.thingsboard.server.common.msg.EncryptionUtil;
  35 +import org.thingsboard.server.common.msg.session.FeatureType;
  36 +import org.thingsboard.server.dao.device.DeviceCredentialsService;
  37 +import org.thingsboard.server.dao.device.DeviceService;
  38 +import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus;
  39 +import org.thingsboard.server.gen.transport.TransportProtos.CredentialsDataProto;
  40 +import org.thingsboard.server.gen.transport.TransportProtos.CredentialsType;
  41 +import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceCredentialsMsg;
  42 +import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
  43 +import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg;
  44 +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg;
  45 +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg;
  46 +
  47 +import java.io.IOException;
  48 +
  49 +@Slf4j
  50 +public abstract class AbstractCoapProvisionProtoDeviceTest extends AbstractCoapIntegrationTest {
  51 +
  52 + @Autowired
  53 + DeviceCredentialsService deviceCredentialsService;
  54 +
  55 + @Autowired
  56 + DeviceService deviceService;
  57 +
  58 + @After
  59 + public void afterTest() throws Exception {
  60 + super.processAfterTest();
  61 + }
  62 +
  63 + @Test
  64 + public void testProvisioningDisabledDevice() throws Exception {
  65 + processTestProvisioningDisabledDevice();
  66 + }
  67 +
  68 + @Test
  69 + public void testProvisioningCheckPreProvisionedDevice() throws Exception {
  70 + processTestProvisioningCheckPreProvisionedDevice();
  71 + }
  72 +
  73 + @Test
  74 + public void testProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
  75 + processTestProvisioningCreateNewDeviceWithoutCredentials();
  76 + }
  77 +
  78 + @Test
  79 + public void testProvisioningCreateNewDeviceWithAccessToken() throws Exception {
  80 + processTestProvisioningCreateNewDeviceWithAccessToken();
  81 + }
  82 +
  83 + @Test
  84 + public void testProvisioningCreateNewDeviceWithCert() throws Exception {
  85 + processTestProvisioningCreateNewDeviceWithCert();
  86 + }
  87 +
  88 + @Test
  89 + public void testProvisioningWithBadKeyDevice() throws Exception {
  90 + processTestProvisioningWithBadKeyDevice();
  91 + }
  92 +
  93 +
  94 + private void processTestProvisioningDisabledDevice() throws Exception {
  95 + super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.DISABLED, null, null);
  96 + ProvisionDeviceResponseMsg result = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
  97 + Assert.assertNotNull(result);
  98 + Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), result.getStatus().toString());
  99 + }
  100 +
  101 + private void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
  102 + super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  103 + ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
  104 +
  105 + Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
  106 +
  107 + Assert.assertNotNull(createdDevice);
  108 +
  109 + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
  110 +
  111 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
  112 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
  113 + }
  114 +
  115 + private void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
  116 + super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  117 + CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceTokenRequestMsg(ValidateDeviceTokenRequestMsg.newBuilder().setToken("test_token").build()).build();
  118 +
  119 + ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish(createTestsProvisionMessage(CredentialsType.ACCESS_TOKEN, requestCredentials)).getPayload());
  120 +
  121 + Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
  122 +
  123 + Assert.assertNotNull(createdDevice);
  124 +
  125 + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
  126 +
  127 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
  128 + Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.ACCESS_TOKEN);
  129 + Assert.assertEquals(deviceCredentials.getCredentialsId(), "test_token");
  130 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
  131 + }
  132 +
  133 + private void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
  134 + super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  135 + CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceX509CertRequestMsg(ValidateDeviceX509CertRequestMsg.newBuilder().setHash("testHash").build()).build();
  136 +
  137 + ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish(createTestsProvisionMessage(CredentialsType.X509_CERTIFICATE, requestCredentials)).getPayload());
  138 +
  139 + Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
  140 +
  141 + Assert.assertNotNull(createdDevice);
  142 +
  143 + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
  144 +
  145 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
  146 + Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.X509_CERTIFICATE);
  147 +
  148 + String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue());
  149 + String sha3Hash = EncryptionUtil.getSha3Hash(cert);
  150 +
  151 + Assert.assertEquals(deviceCredentials.getCredentialsId(), sha3Hash);
  152 +
  153 + Assert.assertEquals(deviceCredentials.getCredentialsValue(), "testHash");
  154 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
  155 + }
  156 +
  157 + private void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
  158 + super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret");
  159 + ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
  160 +
  161 + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId());
  162 +
  163 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
  164 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
  165 + }
  166 +
  167 + private void processTestProvisioningWithBadKeyDevice() throws Exception {
  168 + super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret");
  169 + ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
  170 + Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.getStatus().toString());
  171 + }
  172 +
  173 + private CoapResponse createCoapClientAndPublish() throws Exception {
  174 + byte[] provisionRequestMsg = createTestProvisionMessage();
  175 + return createCoapClientAndPublish(provisionRequestMsg);
  176 + }
  177 +
  178 + private CoapResponse createCoapClientAndPublish(byte[] provisionRequestMsg) throws Exception {
  179 + CoapClient client = getCoapClient(FeatureType.PROVISION);
  180 + return postProvision(client, provisionRequestMsg);
  181 + }
  182 +
  183 + private CoapResponse postProvision(CoapClient client, byte[] payload) throws IOException, ConnectorException {
  184 + return client.setTimeout((long) 60000).post(payload, MediaTypeRegistry.APPLICATION_JSON);
  185 + }
  186 +
  187 + private byte[] createTestsProvisionMessage(CredentialsType credentialsType, CredentialsDataProto credentialsData) throws Exception {
  188 + return ProvisionDeviceRequestMsg.newBuilder()
  189 + .setDeviceName("Test Provision device")
  190 + .setCredentialsType(credentialsType != null ? credentialsType : CredentialsType.ACCESS_TOKEN)
  191 + .setCredentialsDataProto(credentialsData != null ? credentialsData: CredentialsDataProto.newBuilder().build())
  192 + .setProvisionDeviceCredentialsMsg(
  193 + ProvisionDeviceCredentialsMsg.newBuilder()
  194 + .setProvisionDeviceKey("testProvisionKey")
  195 + .setProvisionDeviceSecret("testProvisionSecret")
  196 + ).build()
  197 + .toByteArray();
  198 + }
  199 +
  200 +
  201 + private byte[] createTestProvisionMessage() throws Exception {
  202 + return createTestsProvisionMessage(null, null);
  203 + }
  204 +
  205 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.provision.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.provision.AbstractCoapProvisionJsonDeviceTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +@DaoSqlTest
  22 +public class CoapProvisionDeviceJsonSqlTest extends AbstractCoapProvisionJsonDeviceTest {
  23 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.provision.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.provision.AbstractCoapProvisionProtoDeviceTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +@DaoSqlTest
  22 +public class CoapProvisionDeviceProtoSqlTest extends AbstractCoapProvisionProtoDeviceTest {
  23 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.rpc;
  17 +
  18 +import com.datastax.oss.driver.api.core.uuid.Uuids;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.junit.After;
  21 +import org.junit.Assert;
  22 +import org.junit.Before;
  23 +import org.junit.Test;
  24 +import org.thingsboard.server.service.security.AccessValidator;
  25 +
  26 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  27 +
  28 +@Slf4j
  29 +public abstract class AbstractCoapServerSideRpcDefaultIntegrationTest extends AbstractCoapServerSideRpcIntegrationTest {
  30 +
  31 + @Before
  32 + public void beforeTest() throws Exception {
  33 + processBeforeTest("RPC test device", null, null);
  34 + }
  35 +
  36 + @After
  37 + public void afterTest() throws Exception {
  38 + super.processAfterTest();
  39 + }
  40 +
  41 + @Test
  42 + public void testServerCoapOneWayRpcDeviceOffline() throws Exception {
  43 + String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"24\",\"value\": 1},\"timeout\": 6000}";
  44 + String deviceId = savedDevice.getId().getId().toString();
  45 +
  46 + doPostAsync("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().is(409),
  47 + asyncContextTimeoutToUseRpcPlugin);
  48 + }
  49 +
  50 + @Test
  51 + public void testServerCoapOneWayRpcDeviceDoesNotExist() throws Exception {
  52 + String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"25\",\"value\": 1}}";
  53 + String nonExistentDeviceId = Uuids.timeBased().toString();
  54 +
  55 + String result = doPostAsync("/api/plugins/rpc/oneway/" + nonExistentDeviceId, setGpioRequest, String.class,
  56 + status().isNotFound());
  57 + Assert.assertEquals(AccessValidator.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result);
  58 + }
  59 +
  60 + @Test
  61 + public void testServerCoapTwoWayRpcDeviceOffline() throws Exception {
  62 + String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"27\",\"value\": 1},\"timeout\": 6000}";
  63 + String deviceId = savedDevice.getId().getId().toString();
  64 +
  65 + doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().is(409),
  66 + asyncContextTimeoutToUseRpcPlugin);
  67 + }
  68 +
  69 + @Test
  70 + public void testServerCoapTwoWayRpcDeviceDoesNotExist() throws Exception {
  71 + String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"28\",\"value\": 1}}";
  72 + String nonExistentDeviceId = Uuids.timeBased().toString();
  73 +
  74 + String result = doPostAsync("/api/plugins/rpc/twoway/" + nonExistentDeviceId, setGpioRequest, String.class,
  75 + status().isNotFound());
  76 + Assert.assertEquals(AccessValidator.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result);
  77 + }
  78 +
  79 + @Test
  80 + public void testServerCoapOneWayRpc() throws Exception {
  81 + processOneWayRpcTest();
  82 + }
  83 +
  84 + @Test
  85 + public void testServerCoapTwoWayRpc() throws Exception {
  86 + processTwoWayRpcTest();
  87 + }
  88 +
  89 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.rpc;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.apache.commons.lang3.StringUtils;
  20 +import org.eclipse.californium.core.CoapClient;
  21 +import org.eclipse.californium.core.CoapHandler;
  22 +import org.eclipse.californium.core.CoapObserveRelation;
  23 +import org.eclipse.californium.core.CoapResponse;
  24 +import org.eclipse.californium.core.coap.CoAP;
  25 +import org.eclipse.californium.core.coap.MediaTypeRegistry;
  26 +import org.eclipse.californium.core.coap.Request;
  27 +import org.junit.Assert;
  28 +import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
  29 +import org.thingsboard.server.common.data.CoapDeviceType;
  30 +import org.thingsboard.server.common.data.TransportPayloadType;
  31 +import org.thingsboard.server.common.msg.session.FeatureType;
  32 +
  33 +import java.util.concurrent.CountDownLatch;
  34 +import java.util.concurrent.TimeUnit;
  35 +
  36 +import static org.junit.Assert.assertEquals;
  37 +import static org.junit.Assert.assertNotNull;
  38 +import static org.junit.Assert.assertTrue;
  39 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  40 +
  41 +@Slf4j
  42 +public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractCoapIntegrationTest {
  43 +
  44 + protected static final String DEVICE_RESPONSE = "{\"value1\":\"A\",\"value2\":\"B\"}";
  45 +
  46 + protected Long asyncContextTimeoutToUseRpcPlugin;
  47 +
  48 + protected void processBeforeTest(String deviceName, CoapDeviceType coapDeviceType, TransportPayloadType payloadType) throws Exception {
  49 + super.processBeforeTest(deviceName, coapDeviceType, payloadType);
  50 + asyncContextTimeoutToUseRpcPlugin = 10000L;
  51 + }
  52 +
  53 + protected void processOneWayRpcTest() throws Exception {
  54 + CoapClient client = getCoapClient(FeatureType.RPC);
  55 + client.useCONs();
  56 +
  57 + CountDownLatch latch = new CountDownLatch(1);
  58 + TestCoapCallback testCoapCallback = new TestCoapCallback(client, latch, true);
  59 +
  60 + Request request = Request.newGet().setObserve();
  61 + CoapObserveRelation observeRelation = client.observe(request, testCoapCallback);
  62 +
  63 + String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}";
  64 + String deviceId = savedDevice.getId().getId().toString();
  65 + String result = doPostAsync("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().isOk());
  66 + Assert.assertTrue(StringUtils.isEmpty(result));
  67 + latch.await(3, TimeUnit.SECONDS);
  68 + assertEquals(0, testCoapCallback.getObserve().intValue());
  69 + observeRelation.proactiveCancel();
  70 + assertTrue(observeRelation.isCanceled());
  71 + }
  72 +
  73 + protected void processTwoWayRpcTest() throws Exception {
  74 + CoapClient client = getCoapClient(FeatureType.RPC);
  75 + client.useCONs();
  76 +
  77 + CountDownLatch latch = new CountDownLatch(1);
  78 + TestCoapCallback testCoapCallback = new TestCoapCallback(client, latch, false);
  79 +
  80 + Request request = Request.newGet().setObserve();
  81 + request.setType(CoAP.Type.CON);
  82 + CoapObserveRelation observeRelation = client.observe(request, testCoapCallback);
  83 +
  84 + String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}";
  85 + String deviceId = savedDevice.getId().getId().toString();
  86 +
  87 + String expected = "{\"value1\":\"A\",\"value2\":\"B\"}";
  88 +
  89 + String result = doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
  90 + latch.await(3, TimeUnit.SECONDS);
  91 +
  92 + assertEquals(expected, result);
  93 + assertEquals(0, testCoapCallback.getObserve().intValue());
  94 + observeRelation.proactiveCancel();
  95 + assertTrue(observeRelation.isCanceled());
  96 +
  97 +// // TODO: 3/11/21 Fix test to validate next RPC
  98 +// latch = new CountDownLatch(1);
  99 +//
  100 +// result = doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
  101 +// latch.await(3, TimeUnit.SECONDS);
  102 +//
  103 +// assertEquals(expected, result);
  104 +// assertEquals(1, testCoapCallback.getObserve().intValue());
  105 + }
  106 +
  107 + protected void processOnLoadResponse(CoapResponse response, CoapClient client, Integer observe, CountDownLatch latch) {
  108 + client.setURI(getRpcResponseFeatureTokenUrl(accessToken, observe));
  109 + client.post(new CoapHandler() {
  110 + @Override
  111 + public void onLoad(CoapResponse response) {
  112 + log.warn("Command Response Ack: {}, {}", response.getCode(), response.getResponseText());
  113 + latch.countDown();
  114 + }
  115 +
  116 + @Override
  117 + public void onError() {
  118 + log.warn("Command Response Ack Error, No connect");
  119 + }
  120 + }, DEVICE_RESPONSE, MediaTypeRegistry.APPLICATION_JSON);
  121 + }
  122 +
  123 + protected String getRpcResponseFeatureTokenUrl(String token, int requestId) {
  124 + return COAP_BASE_URL + token + "/" + FeatureType.RPC.name().toLowerCase() + "/" + requestId;
  125 + }
  126 +
  127 + private class TestCoapCallback implements CoapHandler {
  128 +
  129 + private final CoapClient client;
  130 + private final CountDownLatch latch;
  131 + private final boolean isOneWayRpc;
  132 +
  133 + public Integer getObserve() {
  134 + return observe;
  135 + }
  136 +
  137 + private Integer observe;
  138 +
  139 + private TestCoapCallback(CoapClient client, CountDownLatch latch, boolean isOneWayRpc) {
  140 + this.client = client;
  141 + this.latch = latch;
  142 + this.isOneWayRpc = isOneWayRpc;
  143 + }
  144 +
  145 + @Override
  146 + public void onLoad(CoapResponse response) {
  147 + log.warn("coap response: {}, {}", response, response.getCode());
  148 + assertNotNull(response.getPayload());
  149 + assertEquals(response.getCode(), CoAP.ResponseCode.CONTENT);
  150 + observe = response.getOptions().getObserve();
  151 + if (!isOneWayRpc) {
  152 + processOnLoadResponse(response, client, observe, latch);
  153 + } else {
  154 + latch.countDown();
  155 + }
  156 + }
  157 +
  158 + @Override
  159 + public void onError() {
  160 + log.warn("Command Response Ack Error, No connect");
  161 + }
  162 +
  163 + }
  164 +
  165 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.rpc;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.junit.After;
  20 +import org.junit.Before;
  21 +import org.junit.Test;
  22 +import org.thingsboard.server.common.data.CoapDeviceType;
  23 +import org.thingsboard.server.common.data.TransportPayloadType;
  24 +
  25 +@Slf4j
  26 +public abstract class AbstractCoapServerSideRpcJsonIntegrationTest extends AbstractCoapServerSideRpcIntegrationTest {
  27 +
  28 + @Before
  29 + public void beforeTest() throws Exception {
  30 + processBeforeTest("RPC test device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON);
  31 + }
  32 +
  33 + @After
  34 + public void afterTest() throws Exception {
  35 + super.processAfterTest();
  36 + }
  37 +
  38 + @Test
  39 + public void testServerMqttOneWayRpc() throws Exception {
  40 + processOneWayRpcTest();
  41 + }
  42 +
  43 + @Test
  44 + public void testServerMqttTwoWayRpc() throws Exception {
  45 + processTwoWayRpcTest();
  46 + }
  47 +
  48 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.rpc;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.eclipse.californium.core.CoapClient;
  20 +import org.eclipse.californium.core.CoapHandler;
  21 +import org.eclipse.californium.core.CoapResponse;
  22 +import org.eclipse.californium.core.coap.MediaTypeRegistry;
  23 +import org.junit.After;
  24 +import org.junit.Before;
  25 +import org.junit.Test;
  26 +import org.thingsboard.server.common.data.CoapDeviceType;
  27 +import org.thingsboard.server.common.data.TransportPayloadType;
  28 +import org.thingsboard.server.gen.transport.TransportProtos;
  29 +
  30 +import java.util.concurrent.CountDownLatch;
  31 +
  32 +@Slf4j
  33 +public abstract class AbstractCoapServerSideRpcProtoIntegrationTest extends AbstractCoapServerSideRpcIntegrationTest {
  34 +
  35 + @Before
  36 + public void beforeTest() throws Exception {
  37 + processBeforeTest("RPC test device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF);
  38 + }
  39 +
  40 + @After
  41 + public void afterTest() throws Exception {
  42 + super.processAfterTest();
  43 + }
  44 +
  45 + @Test
  46 + public void testServerMqttOneWayRpc() throws Exception {
  47 + processOneWayRpcTest();
  48 + }
  49 +
  50 + @Test
  51 + public void testServerMqttTwoWayRpc() throws Exception {
  52 + processTwoWayRpcTest();
  53 + }
  54 +
  55 + @Override
  56 + protected void processOnLoadResponse(CoapResponse response, CoapClient client, Integer observe, CountDownLatch latch) {
  57 + client.setURI(getRpcResponseFeatureTokenUrl(accessToken, observe));
  58 + TransportProtos.ToDeviceRpcResponseMsg toDeviceRpcResponseMsg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
  59 + .setPayload(DEVICE_RESPONSE)
  60 + .setRequestId(observe)
  61 + .build();
  62 + client.post(new CoapHandler() {
  63 + @Override
  64 + public void onLoad(CoapResponse response) {
  65 + log.warn("Command Response Ack: {}, {}", response.getCode(), response.getResponseText());
  66 + latch.countDown();
  67 + }
  68 +
  69 + @Override
  70 + public void onError() {
  71 + log.warn("Command Response Ack Error, No connect");
  72 + }
  73 + }, toDeviceRpcResponseMsg.toByteArray(), MediaTypeRegistry.APPLICATION_JSON);
  74 + }
  75 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.rpc.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.rpc.AbstractCoapServerSideRpcJsonIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +@DaoSqlTest
  22 +public class CoapServerSideRpcJsonSqlIntegrationTest extends AbstractCoapServerSideRpcJsonIntegrationTest {
  23 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.rpc.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.rpc.AbstractCoapServerSideRpcProtoIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +
  22 +@DaoSqlTest
  23 +public class CoapServerSideRpcProtoSqlIntegrationTest extends AbstractCoapServerSideRpcProtoIntegrationTest {
  24 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.rpc.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.rpc.AbstractCoapServerSideRpcDefaultIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +@DaoSqlTest
  22 +public class CoapServerSideRpcSqlIntegrationTest extends AbstractCoapServerSideRpcDefaultIntegrationTest {
  23 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.telemetry.attributes;
  17 +
  18 +import com.fasterxml.jackson.core.JsonProcessingException;
  19 +import com.fasterxml.jackson.core.type.TypeReference;
  20 +import lombok.extern.slf4j.Slf4j;
  21 +import org.eclipse.californium.core.CoapClient;
  22 +import org.eclipse.californium.core.CoapResponse;
  23 +import org.eclipse.californium.core.coap.CoAP;
  24 +import org.eclipse.californium.core.coap.MediaTypeRegistry;
  25 +import org.eclipse.californium.elements.exception.ConnectorException;
  26 +import org.junit.After;
  27 +import org.junit.Before;
  28 +import org.junit.Test;
  29 +import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
  30 +import org.thingsboard.server.common.data.id.DeviceId;
  31 +import org.thingsboard.server.common.msg.session.FeatureType;
  32 +
  33 +import java.io.IOException;
  34 +import java.util.Arrays;
  35 +import java.util.HashSet;
  36 +import java.util.LinkedHashMap;
  37 +import java.util.List;
  38 +import java.util.Map;
  39 +import java.util.Set;
  40 +
  41 +import static org.junit.Assert.assertEquals;
  42 +import static org.junit.Assert.assertNotNull;
  43 +import static org.junit.Assert.assertTrue;
  44 +
  45 +@Slf4j
  46 +public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoapIntegrationTest {
  47 +
  48 + private static final String PAYLOAD_VALUES_STR = "{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," +
  49 + " \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}";
  50 +
  51 + @Before
  52 + public void beforeTest() throws Exception {
  53 + processBeforeTest("Test Post Attributes device", null, null);
  54 + }
  55 +
  56 + @After
  57 + public void afterTest() throws Exception {
  58 + processAfterTest();
  59 + }
  60 +
  61 + @Test
  62 + public void testPushAttributes() throws Exception {
  63 + List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
  64 + processAttributesTest(expectedKeys, PAYLOAD_VALUES_STR.getBytes());
  65 + }
  66 +
  67 + protected void processAttributesTest(List<String> expectedKeys, byte[] payload) throws Exception {
  68 + log.warn("[testPushAttributes] Device: {}, Transport type: {}", savedDevice.getName(), savedDevice.getType());
  69 + CoapClient client = getCoapClient(FeatureType.ATTRIBUTES);
  70 +
  71 + postAttributes(client, payload);
  72 +
  73 + DeviceId deviceId = savedDevice.getId();
  74 +
  75 + long start = System.currentTimeMillis();
  76 + long end = System.currentTimeMillis() + 5000;
  77 +
  78 + List<String> actualKeys = null;
  79 + while (start <= end) {
  80 + actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/attributes/CLIENT_SCOPE", new TypeReference<>() {});
  81 + if (actualKeys.size() == expectedKeys.size()) {
  82 + break;
  83 + }
  84 + Thread.sleep(100);
  85 + start += 100;
  86 + }
  87 + assertNotNull(actualKeys);
  88 +
  89 + Set<String> actualKeySet = new HashSet<>(actualKeys);
  90 +
  91 + Set<String> expectedKeySet = new HashSet<>(expectedKeys);
  92 +
  93 + assertEquals(expectedKeySet, actualKeySet);
  94 +
  95 + String getAttributesValuesUrl = getAttributesValuesUrl(deviceId, actualKeySet);
  96 + List<Map<String, Object>> values = doGetAsyncTyped(getAttributesValuesUrl, new TypeReference<>() {});
  97 + assertAttributesValues(values, expectedKeySet);
  98 + String deleteAttributesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet);
  99 + doDelete(deleteAttributesUrl);
  100 + }
  101 +
  102 + private void postAttributes(CoapClient client, byte[] payload) throws IOException, ConnectorException {
  103 + if (payload == null) {
  104 + payload = PAYLOAD_VALUES_STR.getBytes();
  105 + }
  106 + CoapResponse coapResponse = client.setTimeout((long) 60000).post(payload, MediaTypeRegistry.APPLICATION_JSON);
  107 + assertEquals(CoAP.ResponseCode.CREATED, coapResponse.getCode());
  108 + }
  109 +
  110 + @SuppressWarnings("unchecked")
  111 + protected void assertAttributesValues(List<Map<String, Object>> deviceValues, Set<String> expectedKeySet) throws JsonProcessingException {
  112 + for (Map<String, Object> map : deviceValues) {
  113 + String key = (String) map.get("key");
  114 + Object value = map.get("value");
  115 + assertTrue(expectedKeySet.contains(key));
  116 + switch (key) {
  117 + case "key1":
  118 + assertEquals("value1", value);
  119 + break;
  120 + case "key2":
  121 + assertEquals(true, value);
  122 + break;
  123 + case "key3":
  124 + assertEquals(3.0, value);
  125 + break;
  126 + case "key4":
  127 + assertEquals(4, value);
  128 + break;
  129 + case "key5":
  130 + assertNotNull(value);
  131 + assertEquals(3, ((LinkedHashMap) value).size());
  132 + assertEquals(42, ((LinkedHashMap) value).get("someNumber"));
  133 + assertEquals(Arrays.asList(1, 2, 3), ((LinkedHashMap) value).get("someArray"));
  134 + LinkedHashMap<String, String> someNestedObject = (LinkedHashMap) ((LinkedHashMap) value).get("someNestedObject");
  135 + assertEquals("value", someNestedObject.get("key"));
  136 + break;
  137 + }
  138 + }
  139 + }
  140 +
  141 + private String getAttributesValuesUrl(DeviceId deviceId, Set<String> actualKeySet) {
  142 + return "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/attributes/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet);
  143 + }
  144 +
  145 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.telemetry.attributes;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.junit.After;
  20 +import org.junit.Before;
  21 +import org.junit.Test;
  22 +import org.thingsboard.server.common.data.CoapDeviceType;
  23 +import org.thingsboard.server.common.data.TransportPayloadType;
  24 +
  25 +@Slf4j
  26 +public abstract class AbstractCoapAttributesJsonIntegrationTest extends AbstractCoapAttributesIntegrationTest {
  27 +
  28 + @Before
  29 + public void beforeTest() throws Exception {
  30 + processBeforeTest("Test Post Attributes device Json", CoapDeviceType.DEFAULT, TransportPayloadType.JSON);
  31 + }
  32 +
  33 + @After
  34 + public void afterTest() throws Exception {
  35 + processAfterTest();
  36 + }
  37 +
  38 + @Test
  39 + public void testPushAttributes() throws Exception {
  40 + super.testPushAttributes();
  41 + }
  42 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.telemetry.attributes;
  17 +
  18 +import com.github.os72.protobuf.dynamic.DynamicSchema;
  19 +import com.google.protobuf.Descriptors;
  20 +import com.google.protobuf.DynamicMessage;
  21 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
  22 +import lombok.extern.slf4j.Slf4j;
  23 +import org.junit.After;
  24 +import org.junit.Test;
  25 +import org.thingsboard.server.common.data.CoapDeviceType;
  26 +import org.thingsboard.server.common.data.TransportPayloadType;
  27 +import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
  28 +import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration;
  29 +import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration;
  30 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  31 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  32 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
  33 +
  34 +import java.util.Arrays;
  35 +import java.util.List;
  36 +
  37 +import static org.junit.Assert.assertNotNull;
  38 +import static org.junit.Assert.assertTrue;
  39 +
  40 +@Slf4j
  41 +public abstract class AbstractCoapAttributesProtoIntegrationTest extends AbstractCoapAttributesIntegrationTest {
  42 +
  43 + @After
  44 + public void afterTest() throws Exception {
  45 + processAfterTest();
  46 + }
  47 +
  48 + @Test
  49 + public void testPushAttributes() throws Exception {
  50 + super.processBeforeTest("Test Post Attributes device Proto", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF);
  51 + List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
  52 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  53 + assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration);
  54 + CoapDeviceProfileTransportConfiguration coapTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration;
  55 + CoapDeviceTypeConfiguration coapDeviceTypeConfiguration = coapTransportConfiguration.getCoapDeviceTypeConfiguration();
  56 + assertTrue(coapDeviceTypeConfiguration instanceof DefaultCoapDeviceTypeConfiguration);
  57 + DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = (DefaultCoapDeviceTypeConfiguration) coapDeviceTypeConfiguration;
  58 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = defaultCoapDeviceTypeConfiguration.getTransportPayloadTypeConfiguration();
  59 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  60 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  61 + ProtoFileElement transportProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_ATTRIBUTES_PROTO_SCHEMA);
  62 + DynamicSchema attributesSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchemaFile, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA);
  63 +
  64 + DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject");
  65 + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
  66 + assertNotNull(nestedJsonObjectBuilderDescriptor);
  67 + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
  68 +
  69 + DynamicMessage.Builder jsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject");
  70 + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
  71 + assertNotNull(jsonObjectBuilderDescriptor);
  72 + DynamicMessage jsonObject = jsonObjectBuilder
  73 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
  74 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
  75 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
  76 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
  77 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
  78 + .build();
  79 +
  80 + DynamicMessage.Builder postAttributesBuilder = attributesSchema.newMessageBuilder("PostAttributes");
  81 + Descriptors.Descriptor postAttributesMsgDescriptor = postAttributesBuilder.getDescriptorForType();
  82 + assertNotNull(postAttributesMsgDescriptor);
  83 + DynamicMessage postAttributesMsg = postAttributesBuilder
  84 + .setField(postAttributesMsgDescriptor.findFieldByName("key1"), "value1")
  85 + .setField(postAttributesMsgDescriptor.findFieldByName("key2"), true)
  86 + .setField(postAttributesMsgDescriptor.findFieldByName("key3"), 3.0)
  87 + .setField(postAttributesMsgDescriptor.findFieldByName("key4"), 4)
  88 + .setField(postAttributesMsgDescriptor.findFieldByName("key5"), jsonObject)
  89 + .build();
  90 + processAttributesTest(expectedKeys, postAttributesMsg.toByteArray());
  91 + }
  92 +
  93 +}
... ...
application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/sql/CoapAttributesSqlIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/rpc/nosql/MqttServerSideRpcNoSqlIntegrationTest.java
... ... @@ -13,14 +13,14 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.rpc.nosql;
  16 +package org.thingsboard.server.transport.coap.telemetry.attributes.sql;
17 17
18   -import org.thingsboard.server.dao.service.DaoNoSqlTest;
19   -import org.thingsboard.server.mqtt.rpc.AbstractMqttServerSideRpcDefaultIntegrationTest;
  18 +import org.thingsboard.server.transport.coap.telemetry.attributes.AbstractCoapAttributesIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
20 20
21 21 /**
22 22 * Created by Valerii Sosliuk on 8/22/2017.
23 23 */
24   -@DaoNoSqlTest
25   -public class MqttServerSideRpcNoSqlIntegrationTest extends AbstractMqttServerSideRpcDefaultIntegrationTest {
  24 +@DaoSqlTest
  25 +public class CoapAttributesSqlIntegrationTest extends AbstractCoapAttributesIntegrationTest {
26 26 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.telemetry.attributes.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.telemetry.attributes.AbstractCoapAttributesJsonIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +/**
  22 + * Created by Valerii Sosliuk on 8/22/2017.
  23 + */
  24 +@DaoSqlTest
  25 +public class CoapAttributesSqlJsonIntegrationTest extends AbstractCoapAttributesJsonIntegrationTest {
  26 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.telemetry.attributes.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.telemetry.attributes.AbstractCoapAttributesProtoIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +/**
  22 + * Created by Valerii Sosliuk on 8/22/2017.
  23 + */
  24 +@DaoSqlTest
  25 +public class CoapAttributesSqlProtoIntegrationTest extends AbstractCoapAttributesProtoIntegrationTest {
  26 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.telemetry.timeseries;
  17 +
  18 +import com.fasterxml.jackson.core.type.TypeReference;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.eclipse.californium.core.CoapClient;
  21 +import org.eclipse.californium.core.CoapResponse;
  22 +import org.eclipse.californium.core.coap.CoAP;
  23 +import org.eclipse.californium.core.coap.MediaTypeRegistry;
  24 +import org.eclipse.californium.elements.exception.ConnectorException;
  25 +import org.junit.After;
  26 +import org.junit.Before;
  27 +import org.junit.Test;
  28 +import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
  29 +import org.thingsboard.server.common.msg.session.FeatureType;
  30 +
  31 +import java.io.IOException;
  32 +import java.util.Arrays;
  33 +import java.util.HashSet;
  34 +import java.util.List;
  35 +import java.util.Map;
  36 +import java.util.Set;
  37 +
  38 +import static org.junit.Assert.assertEquals;
  39 +import static org.junit.Assert.assertNotNull;
  40 +
  41 +@Slf4j
  42 +public abstract class AbstractCoapTimeseriesIntegrationTest extends AbstractCoapIntegrationTest {
  43 +
  44 + private static final String PAYLOAD_VALUES_STR = "{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," +
  45 + " \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}";
  46 +
  47 + @Before
  48 + public void beforeTest() throws Exception {
  49 + processBeforeTest("Test Post Telemetry device", null, null);
  50 + }
  51 +
  52 + @After
  53 + public void afterTest() throws Exception {
  54 + processAfterTest();
  55 + }
  56 +
  57 + @Test
  58 + public void testPushTelemetry() throws Exception {
  59 + processTestPostTelemetry(null, false);
  60 + }
  61 +
  62 + @Test
  63 + public void testPushTelemetryWithTs() throws Exception {
  64 + String payloadStr = "{\"ts\": 10000, \"values\": " + PAYLOAD_VALUES_STR + "}";
  65 + processTestPostTelemetry(payloadStr.getBytes(), true);
  66 + }
  67 +
  68 + protected void processTestPostTelemetry(byte[] payloadBytes, boolean withTs) throws Exception {
  69 + log.warn("[testPushTelemetry] Device: {}, Transport type: {}", savedDevice.getName(), savedDevice.getType());
  70 + List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
  71 + CoapClient coapClient = getCoapClient(FeatureType.TELEMETRY);
  72 + postTelemetry(coapClient, payloadBytes);
  73 +
  74 + String deviceId = savedDevice.getId().getId().toString();
  75 +
  76 + long start = System.currentTimeMillis();
  77 + long end = System.currentTimeMillis() + 5000;
  78 +
  79 + List<String> actualKeys = null;
  80 + while (start <= end) {
  81 + actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/timeseries", new TypeReference<>() {});
  82 + if (actualKeys.size() == expectedKeys.size()) {
  83 + break;
  84 + }
  85 + Thread.sleep(100);
  86 + start += 100;
  87 + }
  88 + assertNotNull(actualKeys);
  89 +
  90 + Set<String> actualKeySet = new HashSet<>(actualKeys);
  91 + Set<String> expectedKeySet = new HashSet<>(expectedKeys);
  92 +
  93 + assertEquals(expectedKeySet, actualKeySet);
  94 +
  95 + String getTelemetryValuesUrl;
  96 + if (withTs) {
  97 + getTelemetryValuesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?startTs=0&endTs=15000&keys=" + String.join(",", actualKeySet);
  98 + } else {
  99 + getTelemetryValuesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?keys=" + String.join(",", actualKeySet);
  100 + }
  101 + start = System.currentTimeMillis();
  102 + end = System.currentTimeMillis() + 5000;
  103 + Map<String, List<Map<String, Object>>> values = null;
  104 + while (start <= end) {
  105 + values = doGetAsyncTyped(getTelemetryValuesUrl, new TypeReference<>() {});
  106 + boolean valid = values.size() == expectedKeys.size();
  107 + if (valid) {
  108 + for (String key : expectedKeys) {
  109 + List<Map<String, Object>> tsValues = values.get(key);
  110 + if (tsValues != null && tsValues.size() > 0) {
  111 + Object ts = tsValues.get(0).get("ts");
  112 + if (ts == null) {
  113 + valid = false;
  114 + break;
  115 + }
  116 + } else {
  117 + valid = false;
  118 + break;
  119 + }
  120 + }
  121 + }
  122 + if (valid) {
  123 + break;
  124 + }
  125 + Thread.sleep(100);
  126 + start += 100;
  127 + }
  128 + assertNotNull(values);
  129 +
  130 + if (withTs) {
  131 + assertTs(values, expectedKeys, 10000, 0);
  132 + }
  133 + assertValues(values, 0);
  134 + }
  135 +
  136 + private void postTelemetry(CoapClient client, byte[] payload) throws IOException, ConnectorException {
  137 + if (payload == null) {
  138 + payload = PAYLOAD_VALUES_STR.getBytes();
  139 + }
  140 + CoapResponse coapResponse = client.setTimeout((long) 60000).post(payload, MediaTypeRegistry.APPLICATION_JSON);
  141 + assertEquals(CoAP.ResponseCode.CREATED, coapResponse.getCode());
  142 + }
  143 +
  144 + private void assertTs(Map<String, List<Map<String, Object>>> deviceValues, List<String> expectedKeys, int ts, int arrayIndex) {
  145 + assertEquals(ts, deviceValues.get(expectedKeys.get(0)).get(arrayIndex).get("ts"));
  146 + assertEquals(ts, deviceValues.get(expectedKeys.get(1)).get(arrayIndex).get("ts"));
  147 + assertEquals(ts, deviceValues.get(expectedKeys.get(2)).get(arrayIndex).get("ts"));
  148 + assertEquals(ts, deviceValues.get(expectedKeys.get(3)).get(arrayIndex).get("ts"));
  149 + assertEquals(ts, deviceValues.get(expectedKeys.get(4)).get(arrayIndex).get("ts"));
  150 + }
  151 +
  152 + private void assertValues(Map<String, List<Map<String, Object>>> deviceValues, int arrayIndex) {
  153 + for (Map.Entry<String, List<Map<String, Object>>> entry : deviceValues.entrySet()) {
  154 + String key = entry.getKey();
  155 + List<Map<String, Object>> tsKv = entry.getValue();
  156 + String value = (String) tsKv.get(arrayIndex).get("value");
  157 + switch (key) {
  158 + case "key1":
  159 + assertEquals("value1", value);
  160 + break;
  161 + case "key2":
  162 + assertEquals("true", value);
  163 + break;
  164 + case "key3":
  165 + assertEquals("3.0", value);
  166 + break;
  167 + case "key4":
  168 + assertEquals("4", value);
  169 + break;
  170 + case "key5":
  171 + assertEquals("{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}", value);
  172 + break;
  173 + }
  174 + }
  175 + }
  176 +
  177 +
  178 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.telemetry.timeseries;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.junit.After;
  20 +import org.junit.Before;
  21 +import org.junit.Test;
  22 +import org.thingsboard.server.common.data.CoapDeviceType;
  23 +import org.thingsboard.server.common.data.TransportPayloadType;
  24 +
  25 +@Slf4j
  26 +public abstract class AbstractCoapTimeseriesJsonIntegrationTest extends AbstractCoapTimeseriesIntegrationTest {
  27 +
  28 + @Before
  29 + public void beforeTest() throws Exception {
  30 + processBeforeTest("Test Post Telemetry device json payload", CoapDeviceType.DEFAULT, TransportPayloadType.JSON);
  31 + }
  32 +
  33 + @After
  34 + public void afterTest() throws Exception {
  35 + processAfterTest();
  36 + }
  37 +
  38 +
  39 + @Test
  40 + public void testPushTelemetry() throws Exception {
  41 + super.testPushTelemetry();
  42 + }
  43 +
  44 + @Test
  45 + public void testPushTelemetryWithTs() throws Exception {
  46 + super.testPushTelemetryWithTs();
  47 + }
  48 +
  49 +
  50 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.telemetry.timeseries;
  17 +
  18 +import com.github.os72.protobuf.dynamic.DynamicSchema;
  19 +import com.google.protobuf.Descriptors;
  20 +import com.google.protobuf.DynamicMessage;
  21 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
  22 +import lombok.extern.slf4j.Slf4j;
  23 +import org.junit.After;
  24 +import org.junit.Test;
  25 +import org.thingsboard.server.common.data.CoapDeviceType;
  26 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
  27 +import org.thingsboard.server.common.data.TransportPayloadType;
  28 +import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
  29 +import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration;
  30 +import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration;
  31 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  32 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  33 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
  34 +
  35 +import static org.junit.Assert.assertNotNull;
  36 +import static org.junit.Assert.assertTrue;
  37 +
  38 +@Slf4j
  39 +public abstract class AbstractCoapTimeseriesProtoIntegrationTest extends AbstractCoapTimeseriesIntegrationTest {
  40 +
  41 + @After
  42 + public void afterTest() throws Exception {
  43 + processAfterTest();
  44 + }
  45 +
  46 + @Test
  47 + public void testPushTelemetry() throws Exception {
  48 + super.processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF);
  49 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  50 + assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration);
  51 + CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration;
  52 + CoapDeviceTypeConfiguration coapDeviceTypeConfiguration = coapDeviceProfileTransportConfiguration.getCoapDeviceTypeConfiguration();
  53 + assertTrue(coapDeviceTypeConfiguration instanceof DefaultCoapDeviceTypeConfiguration);
  54 + DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = (DefaultCoapDeviceTypeConfiguration) coapDeviceTypeConfiguration;
  55 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = defaultCoapDeviceTypeConfiguration.getTransportPayloadTypeConfiguration();
  56 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  57 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  58 + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_TELEMETRY_PROTO_SCHEMA);
  59 + DynamicSchema telemetrySchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, "telemetrySchema");
  60 +
  61 + DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject");
  62 + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
  63 + assertNotNull(nestedJsonObjectBuilderDescriptor);
  64 + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
  65 +
  66 + DynamicMessage.Builder jsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject");
  67 + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
  68 + assertNotNull(jsonObjectBuilderDescriptor);
  69 + DynamicMessage jsonObject = jsonObjectBuilder
  70 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
  71 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
  72 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
  73 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
  74 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
  75 + .build();
  76 +
  77 + DynamicMessage.Builder postTelemetryBuilder = telemetrySchema.newMessageBuilder("PostTelemetry");
  78 + Descriptors.Descriptor postTelemetryMsgDescriptor = postTelemetryBuilder.getDescriptorForType();
  79 + assertNotNull(postTelemetryMsgDescriptor);
  80 + DynamicMessage postTelemetryMsg = postTelemetryBuilder
  81 + .setField(postTelemetryMsgDescriptor.findFieldByName("key1"), "value1")
  82 + .setField(postTelemetryMsgDescriptor.findFieldByName("key2"), true)
  83 + .setField(postTelemetryMsgDescriptor.findFieldByName("key3"), 3.0)
  84 + .setField(postTelemetryMsgDescriptor.findFieldByName("key4"), 4)
  85 + .setField(postTelemetryMsgDescriptor.findFieldByName("key5"), jsonObject)
  86 + .build();
  87 + processTestPostTelemetry(postTelemetryMsg.toByteArray(), false);
  88 + }
  89 +
  90 + @Test
  91 + public void testPushTelemetryWithTs() throws Exception {
  92 + String schemaStr = "syntax =\"proto3\";\n" +
  93 + "\n" +
  94 + "package test;\n" +
  95 + "\n" +
  96 + "message PostTelemetry {\n" +
  97 + " int64 ts = 1;\n" +
  98 + " Values values = 2;\n" +
  99 + " \n" +
  100 + " message Values {\n" +
  101 + " string key1 = 3;\n" +
  102 + " bool key2 = 4;\n" +
  103 + " double key3 = 5;\n" +
  104 + " int32 key4 = 6;\n" +
  105 + " JsonObject key5 = 7;\n" +
  106 + " }\n" +
  107 + " \n" +
  108 + " message JsonObject {\n" +
  109 + " int32 someNumber = 8;\n" +
  110 + " repeated int32 someArray = 9;\n" +
  111 + " NestedJsonObject someNestedObject = 10;\n" +
  112 + " message NestedJsonObject {\n" +
  113 + " string key = 11;\n" +
  114 + " }\n" +
  115 + " }\n" +
  116 + "}";
  117 + super.processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, schemaStr, null, DeviceProfileProvisionType.DISABLED, null, null);
  118 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  119 + assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration);
  120 + CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration;
  121 + CoapDeviceTypeConfiguration coapDeviceTypeConfiguration = coapDeviceProfileTransportConfiguration.getCoapDeviceTypeConfiguration();
  122 + assertTrue(coapDeviceTypeConfiguration instanceof DefaultCoapDeviceTypeConfiguration);
  123 + DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = (DefaultCoapDeviceTypeConfiguration) coapDeviceTypeConfiguration;
  124 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = defaultCoapDeviceTypeConfiguration.getTransportPayloadTypeConfiguration();
  125 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  126 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  127 + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(schemaStr);
  128 + DynamicSchema telemetrySchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, "telemetrySchema");
  129 +
  130 + DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject");
  131 + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
  132 + assertNotNull(nestedJsonObjectBuilderDescriptor);
  133 + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
  134 +
  135 + DynamicMessage.Builder jsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject");
  136 + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
  137 + assertNotNull(jsonObjectBuilderDescriptor);
  138 + DynamicMessage jsonObject = jsonObjectBuilder
  139 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
  140 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
  141 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
  142 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
  143 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
  144 + .build();
  145 +
  146 +
  147 + DynamicMessage.Builder valuesBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.Values");
  148 + Descriptors.Descriptor valuesDescriptor = valuesBuilder.getDescriptorForType();
  149 + assertNotNull(valuesDescriptor);
  150 +
  151 + DynamicMessage valuesMsg = valuesBuilder
  152 + .setField(valuesDescriptor.findFieldByName("key1"), "value1")
  153 + .setField(valuesDescriptor.findFieldByName("key2"), true)
  154 + .setField(valuesDescriptor.findFieldByName("key3"), 3.0)
  155 + .setField(valuesDescriptor.findFieldByName("key4"), 4)
  156 + .setField(valuesDescriptor.findFieldByName("key5"), jsonObject)
  157 + .build();
  158 +
  159 + DynamicMessage.Builder postTelemetryBuilder = telemetrySchema.newMessageBuilder("PostTelemetry");
  160 + Descriptors.Descriptor postTelemetryMsgDescriptor = postTelemetryBuilder.getDescriptorForType();
  161 + assertNotNull(postTelemetryMsgDescriptor);
  162 + DynamicMessage postTelemetryMsg = postTelemetryBuilder
  163 + .setField(postTelemetryMsgDescriptor.findFieldByName("ts"), 10000L)
  164 + .setField(postTelemetryMsgDescriptor.findFieldByName("values"), valuesMsg)
  165 + .build();
  166 +
  167 + processTestPostTelemetry(postTelemetryMsg.toByteArray(), true);
  168 + }
  169 +
  170 +}
... ...
application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/nosql/CoapTimeseriesNoSqlIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/attributes/nosql/MqttAttributesNoSqlIntegrationTest.java
... ... @@ -13,11 +13,11 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.attributes.nosql;
  16 +package org.thingsboard.server.transport.coap.telemetry.timeseries.nosql;
17 17
  18 +import org.thingsboard.server.transport.coap.telemetry.timeseries.AbstractCoapTimeseriesIntegrationTest;
18 19 import org.thingsboard.server.dao.service.DaoNoSqlTest;
19   -import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest;
20 20
21 21 @DaoNoSqlTest
22   -public class MqttAttributesNoSqlIntegrationTest extends AbstractMqttAttributesIntegrationTest {
  22 +public class CoapTimeseriesNoSqlIntegrationTest extends AbstractCoapTimeseriesIntegrationTest {
23 23 }
... ...
application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/nosql/CoapTimeseriesNoSqlJsonIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/attributes/nosql/MqttAttributesNoSqlJsonIntegrationTest.java
... ... @@ -13,11 +13,11 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.attributes.nosql;
  16 +package org.thingsboard.server.transport.coap.telemetry.timeseries.nosql;
17 17
  18 +import org.thingsboard.server.transport.coap.telemetry.timeseries.AbstractCoapTimeseriesJsonIntegrationTest;
18 19 import org.thingsboard.server.dao.service.DaoNoSqlTest;
19   -import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest;
20 20
21 21 @DaoNoSqlTest
22   -public class MqttAttributesNoSqlJsonIntegrationTest extends AbstractMqttAttributesJsonIntegrationTest {
  22 +public class CoapTimeseriesNoSqlJsonIntegrationTest extends AbstractCoapTimeseriesJsonIntegrationTest {
23 23 }
... ...
application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/nosql/CoapTimeseriesNoSqlProtoIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/claim/nosql/MqttClaimDeviceNoSqlTest.java
... ... @@ -13,12 +13,11 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.claim.nosql;
  16 +package org.thingsboard.server.transport.coap.telemetry.timeseries.nosql;
17 17
  18 +import org.thingsboard.server.transport.coap.telemetry.timeseries.AbstractCoapTimeseriesProtoIntegrationTest;
18 19 import org.thingsboard.server.dao.service.DaoNoSqlTest;
19   -import org.thingsboard.server.mqtt.claim.AbstractMqttClaimDeviceTest;
20   -
21 20
22 21 @DaoNoSqlTest
23   -public class MqttClaimDeviceNoSqlTest extends AbstractMqttClaimDeviceTest {
  22 +public class CoapTimeseriesNoSqlProtoIntegrationTest extends AbstractCoapTimeseriesProtoIntegrationTest {
24 23 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.telemetry.timeseries.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.telemetry.timeseries.AbstractCoapTimeseriesIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +/**
  22 + * Created by Valerii Sosliuk on 8/22/2017.
  23 + */
  24 +@DaoSqlTest
  25 +public class CoapTimeseriesSqlIntegrationTest extends AbstractCoapTimeseriesIntegrationTest {
  26 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.telemetry.timeseries.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.telemetry.timeseries.AbstractCoapTimeseriesJsonIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +/**
  22 + * Created by Valerii Sosliuk on 8/22/2017.
  23 + */
  24 +@DaoSqlTest
  25 +public class CoapTimeseriesSqlJsonIntegrationTest extends AbstractCoapTimeseriesJsonIntegrationTest {
  26 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.telemetry.timeseries.sql;
  17 +
  18 +import org.thingsboard.server.transport.coap.telemetry.timeseries.AbstractCoapTimeseriesProtoIntegrationTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +/**
  22 + * Created by Valerii Sosliuk on 8/22/2017.
  23 + */
  24 +@DaoSqlTest
  25 +public class CoapTimeseriesSqlProtoIntegrationTest extends AbstractCoapTimeseriesProtoIntegrationTest {
  26 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.mqtt;
  17 +
  18 +import com.fasterxml.jackson.databind.node.ObjectNode;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
  21 +import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
  22 +import org.eclipse.paho.client.mqttv3.MqttException;
  23 +import org.eclipse.paho.client.mqttv3.MqttMessage;
  24 +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
  25 +import org.junit.Assert;
  26 +import org.springframework.util.StringUtils;
  27 +import org.thingsboard.server.common.data.Device;
  28 +import org.thingsboard.server.common.data.DeviceProfile;
  29 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
  30 +import org.thingsboard.server.common.data.DeviceProfileType;
  31 +import org.thingsboard.server.common.data.DeviceTransportType;
  32 +import org.thingsboard.server.common.data.Tenant;
  33 +import org.thingsboard.server.common.data.TransportPayloadType;
  34 +import org.thingsboard.server.common.data.User;
  35 +import org.thingsboard.server.common.data.device.profile.AllowCreateNewDevicesDeviceProfileProvisionConfiguration;
  36 +import org.thingsboard.server.common.data.device.profile.CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration;
  37 +import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
  38 +import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
  39 +import org.thingsboard.server.common.data.device.profile.DeviceProfileProvisionConfiguration;
  40 +import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration;
  41 +import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration;
  42 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  43 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  44 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
  45 +import org.thingsboard.server.common.data.security.Authority;
  46 +import org.thingsboard.server.common.data.security.DeviceCredentials;
  47 +import org.thingsboard.server.gen.transport.TransportProtos;
  48 +import org.thingsboard.server.transport.AbstractTransportIntegrationTest;
  49 +
  50 +import java.util.List;
  51 +
  52 +import static org.junit.Assert.assertEquals;
  53 +import static org.junit.Assert.assertNotNull;
  54 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  55 +
  56 +@Slf4j
  57 +public abstract class AbstractMqttIntegrationTest extends AbstractTransportIntegrationTest {
  58 +
  59 + protected Device savedGateway;
  60 + protected String gatewayAccessToken;
  61 +
  62 + protected DeviceProfile deviceProfile;
  63 +
  64 + protected void processBeforeTest (String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception {
  65 + this.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic, null, null, DeviceProfileProvisionType.DISABLED, null, null);
  66 + }
  67 +
  68 + protected void processBeforeTest(String deviceName,
  69 + String gatewayName,
  70 + TransportPayloadType payloadType,
  71 + String telemetryTopic,
  72 + String attributesTopic,
  73 + String telemetryProtoSchema,
  74 + String attributesProtoSchema,
  75 + DeviceProfileProvisionType provisionType,
  76 + String provisionKey, String provisionSecret
  77 + ) throws Exception {
  78 + loginSysAdmin();
  79 +
  80 + Tenant tenant = new Tenant();
  81 + tenant.setTitle("My tenant");
  82 + savedTenant = doPost("/api/tenant", tenant, Tenant.class);
  83 + Assert.assertNotNull(savedTenant);
  84 +
  85 + tenantAdmin = new User();
  86 + tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
  87 + tenantAdmin.setTenantId(savedTenant.getId());
  88 + tenantAdmin.setEmail("tenant" + atomicInteger.getAndIncrement() + "@thingsboard.org");
  89 + tenantAdmin.setFirstName("Joe");
  90 + tenantAdmin.setLastName("Downs");
  91 +
  92 + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
  93 +
  94 + Device device = new Device();
  95 + device.setName(deviceName);
  96 + device.setType("default");
  97 +
  98 + Device gateway = new Device();
  99 + gateway.setName(gatewayName);
  100 + gateway.setType("default");
  101 + ObjectNode additionalInfo = mapper.createObjectNode();
  102 + additionalInfo.put("gateway", true);
  103 + gateway.setAdditionalInfo(additionalInfo);
  104 +
  105 + if (payloadType != null) {
  106 + DeviceProfile mqttDeviceProfile = createMqttDeviceProfile(payloadType, telemetryTopic, attributesTopic, telemetryProtoSchema, attributesProtoSchema, provisionType, provisionKey, provisionSecret);
  107 + deviceProfile = doPost("/api/deviceProfile", mqttDeviceProfile, DeviceProfile.class);
  108 + device.setType(deviceProfile.getName());
  109 + device.setDeviceProfileId(deviceProfile.getId());
  110 + gateway.setType(deviceProfile.getName());
  111 + gateway.setDeviceProfileId(deviceProfile.getId());
  112 + }
  113 +
  114 + savedDevice = doPost("/api/device", device, Device.class);
  115 +
  116 + DeviceCredentials deviceCredentials =
  117 + doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
  118 +
  119 + savedGateway = doPost("/api/device", gateway, Device.class);
  120 +
  121 + DeviceCredentials gatewayCredentials =
  122 + doGet("/api/device/" + savedGateway.getId().getId().toString() + "/credentials", DeviceCredentials.class);
  123 +
  124 + assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
  125 + accessToken = deviceCredentials.getCredentialsId();
  126 + assertNotNull(accessToken);
  127 +
  128 + assertEquals(savedGateway.getId(), gatewayCredentials.getDeviceId());
  129 + gatewayAccessToken = gatewayCredentials.getCredentialsId();
  130 + assertNotNull(gatewayAccessToken);
  131 +
  132 + }
  133 +
  134 + protected void processAfterTest() throws Exception {
  135 + loginSysAdmin();
  136 + if (savedTenant != null) {
  137 + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()).andExpect(status().isOk());
  138 + }
  139 + }
  140 +
  141 + protected MqttAsyncClient getMqttAsyncClient(String accessToken) throws MqttException {
  142 + String clientId = MqttAsyncClient.generateClientId();
  143 + MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId, new MemoryPersistence());
  144 +
  145 + MqttConnectOptions options = new MqttConnectOptions();
  146 + options.setUserName(accessToken);
  147 + client.connect(options).waitForCompletion();
  148 + return client;
  149 + }
  150 +
  151 + protected void publishMqttMsg(MqttAsyncClient client, byte[] payload, String topic) throws MqttException {
  152 + MqttMessage message = new MqttMessage();
  153 + message.setPayload(payload);
  154 + client.publish(topic, message);
  155 + }
  156 +
  157 + protected DeviceProfile createMqttDeviceProfile(TransportPayloadType transportPayloadType,
  158 + String telemetryTopic, String attributesTopic,
  159 + String telemetryProtoSchema, String attributesProtoSchema,
  160 + DeviceProfileProvisionType provisionType,
  161 + String provisionKey, String provisionSecret) {
  162 + DeviceProfile deviceProfile = new DeviceProfile();
  163 + deviceProfile.setName(transportPayloadType.name());
  164 + deviceProfile.setType(DeviceProfileType.DEFAULT);
  165 + deviceProfile.setTransportType(DeviceTransportType.MQTT);
  166 + deviceProfile.setProvisionType(provisionType);
  167 + deviceProfile.setProvisionDeviceKey(provisionKey);
  168 + deviceProfile.setDescription(transportPayloadType.name() + " Test");
  169 + DeviceProfileData deviceProfileData = new DeviceProfileData();
  170 + DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
  171 + MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = new MqttDeviceProfileTransportConfiguration();
  172 + if (!StringUtils.isEmpty(telemetryTopic)) {
  173 + mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(telemetryTopic);
  174 + }
  175 + if (!StringUtils.isEmpty(attributesTopic)) {
  176 + mqttDeviceProfileTransportConfiguration.setDeviceAttributesTopic(attributesTopic);
  177 + }
  178 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration;
  179 + if (TransportPayloadType.JSON.equals(transportPayloadType)) {
  180 + transportPayloadTypeConfiguration = new JsonTransportPayloadConfiguration();
  181 + } else {
  182 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = new ProtoTransportPayloadConfiguration();
  183 + if (StringUtils.isEmpty(telemetryProtoSchema)) {
  184 + telemetryProtoSchema = DEVICE_TELEMETRY_PROTO_SCHEMA;
  185 + }
  186 + if (StringUtils.isEmpty(attributesProtoSchema)) {
  187 + attributesProtoSchema = DEVICE_ATTRIBUTES_PROTO_SCHEMA;
  188 + }
  189 + protoTransportPayloadConfiguration.setDeviceTelemetryProtoSchema(telemetryProtoSchema);
  190 + protoTransportPayloadConfiguration.setDeviceAttributesProtoSchema(attributesProtoSchema);
  191 + transportPayloadTypeConfiguration = protoTransportPayloadConfiguration;
  192 + }
  193 + mqttDeviceProfileTransportConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration);
  194 + deviceProfileData.setTransportConfiguration(mqttDeviceProfileTransportConfiguration);
  195 + DeviceProfileProvisionConfiguration provisionConfiguration;
  196 + switch (provisionType) {
  197 + case ALLOW_CREATE_NEW_DEVICES:
  198 + provisionConfiguration = new AllowCreateNewDevicesDeviceProfileProvisionConfiguration(provisionSecret);
  199 + break;
  200 + case CHECK_PRE_PROVISIONED_DEVICES:
  201 + provisionConfiguration = new CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration(provisionSecret);
  202 + break;
  203 + case DISABLED:
  204 + default:
  205 + provisionConfiguration = new DisabledDeviceProfileProvisionConfiguration(provisionSecret);
  206 + break;
  207 + }
  208 + deviceProfileData.setProvisionConfiguration(provisionConfiguration);
  209 + deviceProfileData.setConfiguration(configuration);
  210 + deviceProfile.setProfileData(deviceProfileData);
  211 + deviceProfile.setDefault(false);
  212 + deviceProfile.setDefaultRuleChainId(null);
  213 + return deviceProfile;
  214 + }
  215 +
  216 + protected TransportProtos.PostAttributeMsg getPostAttributeMsg(List<String> expectedKeys) {
  217 + List<TransportProtos.KeyValueProto> kvProtos = getKvProtos(expectedKeys);
  218 + TransportProtos.PostAttributeMsg.Builder builder = TransportProtos.PostAttributeMsg.newBuilder();
  219 + builder.addAllKv(kvProtos);
  220 + return builder.build();
  221 + }
  222 +}
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/AbstractMqttAttributesIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/AbstractMqttAttributesIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes;
  16 +package org.thingsboard.server.transport.mqtt.attributes;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
... ... @@ -21,7 +21,7 @@ import org.eclipse.paho.client.mqttv3.MqttCallback;
21 21 import org.eclipse.paho.client.mqttv3.MqttMessage;
22 22 import org.thingsboard.server.common.data.TransportPayloadType;
23 23 import org.thingsboard.server.gen.transport.TransportProtos;
24   -import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest;
  24 +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
25 25
26 26 import java.util.ArrayList;
27 27 import java.util.List;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/request/AbstractMqttAttributesRequestIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes.request;
  16 +package org.thingsboard.server.transport.mqtt.attributes.request;
17 17
18 18 import com.google.protobuf.InvalidProtocolBufferException;
19 19 import io.netty.handler.codec.mqtt.MqttQoS;
... ... @@ -27,7 +27,7 @@ import org.junit.Test;
27 27 import org.thingsboard.server.common.data.Device;
28 28 import org.thingsboard.server.common.data.device.profile.MqttTopics;
29 29 import org.thingsboard.server.dao.util.mapping.JacksonUtil;
30   -import org.thingsboard.server.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
  30 +import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
31 31
32 32 import java.nio.charset.StandardCharsets;
33 33 import java.util.concurrent.CountDownLatch;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestJsonIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/request/AbstractMqttAttributesRequestJsonIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes.request;
  16 +package org.thingsboard.server.transport.mqtt.attributes.request;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.junit.After;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/AbstractMqttAttributesRequestProtoIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/request/AbstractMqttAttributesRequestProtoIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes.request;
  16 +package org.thingsboard.server.transport.mqtt.attributes.request;
17 17
18 18 import com.github.os72.protobuf.dynamic.DynamicSchema;
19 19 import com.google.protobuf.Descriptors;
... ... @@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.device.profile.MqttTopics;
37 37 import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
38 38 import org.thingsboard.server.gen.transport.TransportApiProtos;
39 39 import org.thingsboard.server.gen.transport.TransportProtos;
  40 +import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
40 41
41 42 import java.util.ArrayList;
42 43 import java.util.Arrays;
... ... @@ -93,7 +94,7 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends
93 94 }
94 95
95 96 protected void postAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client) throws Exception {
96   - doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
  97 + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", AbstractMqttAttributesIntegrationTest.POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
97 98 DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
98 99 assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
99 100 MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
... ... @@ -148,7 +149,7 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends
148 149 client.publish(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, new MqttMessage(bytes));
149 150 }
150 151
151   - protected void validateResponse(MqttAsyncClient client, CountDownLatch latch, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
  152 + protected void validateResponse(MqttAsyncClient client, CountDownLatch latch, AbstractMqttAttributesIntegrationTest.TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
152 153 String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
153 154 TransportApiProtos.AttributesRequest.Builder attributesRequestBuilder = TransportApiProtos.AttributesRequest.newBuilder();
154 155 attributesRequestBuilder.setClientKeys(keys);
... ... @@ -170,7 +171,7 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends
170 171 assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos));
171 172 }
172 173
173   - protected void validateClientResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
  174 + protected void validateClientResponseGateway(MqttAsyncClient client, AbstractMqttAttributesIntegrationTest.TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
174 175 String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
175 176 TransportApiProtos.GatewayAttributesRequestMsg gatewayAttributesRequestMsg = getGatewayAttributesRequestMsg(keys, true);
176 177 client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, new MqttMessage(gatewayAttributesRequestMsg.toByteArray()));
... ... @@ -189,7 +190,7 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends
189 190 assertTrue(actualClientKeyValueProtos.containsAll(expectedClientKeyValueProtos));
190 191 }
191 192
192   - protected void validateSharedResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
  193 + protected void validateSharedResponseGateway(MqttAsyncClient client, AbstractMqttAttributesIntegrationTest.TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
193 194 String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
194 195 TransportApiProtos.GatewayAttributesRequestMsg gatewayAttributesRequestMsg = getGatewayAttributesRequestMsg(keys, false);
195 196 client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, new MqttMessage(gatewayAttributesRequestMsg.toByteArray()));
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestJsonSqlIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/request/sql/MqttAttributesRequestJsonSqlIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes.request.sql;
  16 +package org.thingsboard.server.transport.mqtt.attributes.request.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestJsonIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.attributes.request.AbstractMqttAttributesRequestJsonIntegrationTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttAttributesRequestJsonSqlIntegrationTest extends AbstractMqttAttributesRequestJsonIntegrationTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestProtoSqlIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/request/sql/MqttAttributesRequestProtoSqlIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes.request.sql;
  16 +package org.thingsboard.server.transport.mqtt.attributes.request.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestProtoIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.attributes.request.AbstractMqttAttributesRequestProtoIntegrationTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttAttributesRequestProtoSqlIntegrationTest extends AbstractMqttAttributesRequestProtoIntegrationTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestSqlIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/request/sql/MqttAttributesRequestSqlIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes.request.sql;
  16 +package org.thingsboard.server.transport.mqtt.attributes.request.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.attributes.request.AbstractMqttAttributesRequestIntegrationTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttAttributesRequestSqlIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/updates/AbstractMqttAttributesUpdatesIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes.updates;
  16 +package org.thingsboard.server.transport.mqtt.attributes.updates;
17 17
18 18 import com.google.protobuf.InvalidProtocolBufferException;
19 19 import io.netty.handler.codec.mqtt.MqttQoS;
... ... @@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.Device;
26 26 import org.thingsboard.server.common.data.TransportPayloadType;
27 27 import org.thingsboard.server.common.data.device.profile.MqttTopics;
28 28 import org.thingsboard.server.dao.util.mapping.JacksonUtil;
29   -import org.thingsboard.server.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
  29 +import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
30 30
31 31 import java.nio.charset.StandardCharsets;
32 32 import java.util.concurrent.TimeUnit;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesJsonIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/updates/AbstractMqttAttributesUpdatesJsonIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes.updates;
  16 +package org.thingsboard.server.transport.mqtt.attributes.updates;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.junit.After;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/AbstractMqttAttributesUpdatesProtoIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/updates/AbstractMqttAttributesUpdatesProtoIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes.updates;
  16 +package org.thingsboard.server.transport.mqtt.attributes.updates;
17 17
18 18 import com.google.protobuf.InvalidProtocolBufferException;
19 19 import lombok.extern.slf4j.Slf4j;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes.updates.sql;
  16 +package org.thingsboard.server.transport.mqtt.attributes.updates.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.attributes.updates.AbstractMqttAttributesUpdatesIntegrationTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttAttributesUpdatesSqlIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlJsonIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlJsonIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes.updates.sql;
  16 +package org.thingsboard.server.transport.mqtt.attributes.updates.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttAttributesUpdatesSqlJsonIntegrationTest extends AbstractMqttAttributesUpdatesJsonIntegrationTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlProtoIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlProtoIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes.updates.sql;
  16 +package org.thingsboard.server.transport.mqtt.attributes.updates.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesProtoIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.attributes.updates.AbstractMqttAttributesUpdatesProtoIntegrationTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttAttributesUpdatesSqlProtoIntegrationTest extends AbstractMqttAttributesUpdatesProtoIntegrationTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimDeviceTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/claim/AbstractMqttClaimDeviceTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.claim;
  16 +package org.thingsboard.server.transport.mqtt.claim;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
... ... @@ -29,7 +29,7 @@ import org.thingsboard.server.common.data.device.profile.MqttTopics;
29 29 import org.thingsboard.server.common.data.security.Authority;
30 30 import org.thingsboard.server.dao.device.claim.ClaimResponse;
31 31 import org.thingsboard.server.dao.device.claim.ClaimResult;
32   -import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest;
  32 +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
33 33
34 34 import static org.junit.Assert.assertEquals;
35 35 import static org.junit.Assert.assertNotNull;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimJsonDeviceTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/claim/AbstractMqttClaimJsonDeviceTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.claim;
  16 +package org.thingsboard.server.transport.mqtt.claim;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.junit.After;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/claim/AbstractMqttClaimProtoDeviceTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/claim/AbstractMqttClaimProtoDeviceTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.claim;
  16 +package org.thingsboard.server.transport.mqtt.claim;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceJsonSqlTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/claim/sql/MqttClaimDeviceJsonSqlTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.claim.sql;
  16 +package org.thingsboard.server.transport.mqtt.claim.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.claim.AbstractMqttClaimJsonDeviceTest;
  19 +import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimJsonDeviceTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttClaimDeviceJsonSqlTest extends AbstractMqttClaimJsonDeviceTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceProtoSqlTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/claim/sql/MqttClaimDeviceProtoSqlTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.claim.sql;
  16 +package org.thingsboard.server.transport.mqtt.claim.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.claim.AbstractMqttClaimProtoDeviceTest;
  19 +import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimProtoDeviceTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttClaimDeviceProtoSqlTest extends AbstractMqttClaimProtoDeviceTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceSqlTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/claim/sql/MqttClaimDeviceSqlTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.claim.sql;
  16 +package org.thingsboard.server.transport.mqtt.claim.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.claim.AbstractMqttClaimDeviceTest;
  19 +import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimDeviceTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttClaimDeviceSqlTest extends AbstractMqttClaimDeviceTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionJsonDeviceTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/provision/AbstractMqttProvisionJsonDeviceTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.provision;
  16 +package org.thingsboard.server.transport.mqtt.provision;
17 17
18 18 import com.google.gson.JsonObject;
19 19 import io.netty.handler.codec.mqtt.MqttQoS;
... ... @@ -38,7 +38,7 @@ import org.thingsboard.server.dao.device.DeviceCredentialsService;
38 38 import org.thingsboard.server.dao.device.DeviceService;
39 39 import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus;
40 40 import org.thingsboard.server.dao.util.mapping.JacksonUtil;
41   -import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest;
  41 +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
42 42
43 43 import java.util.concurrent.CountDownLatch;
44 44 import java.util.concurrent.TimeUnit;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionProtoDeviceTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/provision/AbstractMqttProvisionProtoDeviceTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.provision;
  16 +package org.thingsboard.server.transport.mqtt.provision;
17 17
18 18 import io.netty.handler.codec.mqtt.MqttQoS;
19 19 import lombok.extern.slf4j.Slf4j;
... ... @@ -45,9 +45,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRespo
45 45 import org.thingsboard.server.gen.transport.TransportProtos.ValidateBasicMqttCredRequestMsg;
46 46 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg;
47 47 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg;
48   -import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest;
  48 +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
49 49
50   -import java.util.UUID;
51 50 import java.util.concurrent.CountDownLatch;
52 51 import java.util.concurrent.TimeUnit;
53 52
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceJsonSqlTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/provision/sql/MqttProvisionDeviceJsonSqlTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.provision.sql;
  16 +package org.thingsboard.server.transport.mqtt.provision.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.provision.AbstractMqttProvisionJsonDeviceTest;
  19 +import org.thingsboard.server.transport.mqtt.provision.AbstractMqttProvisionJsonDeviceTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttProvisionDeviceJsonSqlTest extends AbstractMqttProvisionJsonDeviceTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceProtoSqlTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/provision/sql/MqttProvisionDeviceProtoSqlTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.provision.sql;
  16 +package org.thingsboard.server.transport.mqtt.provision.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.provision.AbstractMqttProvisionProtoDeviceTest;
  19 +import org.thingsboard.server.transport.mqtt.provision.AbstractMqttProvisionProtoDeviceTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttProvisionDeviceProtoSqlTest extends AbstractMqttProvisionProtoDeviceTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcDefaultIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcDefaultIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.rpc;
  16 +package org.thingsboard.server.transport.mqtt.rpc;
17 17
18 18 import com.datastax.oss.driver.api.core.uuid.Uuids;
19 19 import lombok.extern.slf4j.Slf4j;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.rpc;
  16 +package org.thingsboard.server.transport.mqtt.rpc;
17 17
18 18 import com.fasterxml.jackson.databind.JsonNode;
19 19 import com.google.protobuf.InvalidProtocolBufferException;
... ... @@ -31,7 +31,7 @@ import org.thingsboard.server.common.data.Device;
31 31 import org.thingsboard.server.common.data.TransportPayloadType;
32 32 import org.thingsboard.server.common.data.device.profile.MqttTopics;
33 33 import org.thingsboard.server.dao.util.mapping.JacksonUtil;
34   -import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest;
  34 +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
35 35
36 36 import java.util.Arrays;
37 37 import java.util.concurrent.CountDownLatch;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcJsonIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcJsonIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.rpc;
  16 +package org.thingsboard.server.transport.mqtt.rpc;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcProtoIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcProtoIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.rpc;
  16 +package org.thingsboard.server.transport.mqtt.rpc;
17 17
18 18 import com.google.protobuf.InvalidProtocolBufferException;
19 19 import lombok.extern.slf4j.Slf4j;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcJsonSqlIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/rpc/sql/MqttServerSideRpcJsonSqlIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.rpc.sql;
  16 +package org.thingsboard.server.transport.mqtt.rpc.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.rpc.AbstractMqttServerSideRpcJsonIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.rpc.AbstractMqttServerSideRpcJsonIntegrationTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttServerSideRpcJsonSqlIntegrationTest extends AbstractMqttServerSideRpcJsonIntegrationTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcProtoSqlIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/rpc/sql/MqttServerSideRpcProtoSqlIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.rpc.sql;
  16 +package org.thingsboard.server.transport.mqtt.rpc.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.rpc.AbstractMqttServerSideRpcProtoIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.rpc.AbstractMqttServerSideRpcProtoIntegrationTest;
20 20
21 21
22 22 @DaoSqlTest
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcSqlIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/rpc/sql/MqttServerSideRpcSqlIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.rpc.sql;
  16 +package org.thingsboard.server.transport.mqtt.rpc.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.rpc.AbstractMqttServerSideRpcDefaultIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.rpc.AbstractMqttServerSideRpcDefaultIntegrationTest;
20 20
21 21 /**
22 22 * Created by Valerii Sosliuk on 8/22/2017.
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/AbstractMqttAttributesIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/attributes/AbstractMqttAttributesIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.attributes;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.attributes;
17 17
18 18 import com.fasterxml.jackson.core.JsonProcessingException;
19 19 import com.fasterxml.jackson.core.type.TypeReference;
... ... @@ -25,7 +25,7 @@ import org.junit.Test;
25 25 import org.thingsboard.server.common.data.Device;
26 26 import org.thingsboard.server.common.data.device.profile.MqttTopics;
27 27 import org.thingsboard.server.common.data.id.DeviceId;
28   -import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest;
  28 +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
29 29
30 30 import java.util.Arrays;
31 31 import java.util.HashSet;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/AbstractMqttAttributesJsonIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/attributes/AbstractMqttAttributesJsonIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.attributes;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.attributes;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.junit.After;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/AbstractMqttAttributesProtoIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/attributes/AbstractMqttAttributesProtoIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.attributes;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.attributes;
17 17
18 18 import com.github.os72.protobuf.dynamic.DynamicSchema;
19 19 import com.google.protobuf.Descriptors;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/attributes/sql/MqttAttributesSqlIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.attributes.sql;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.attributes.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttAttributesSqlIntegrationTest extends AbstractMqttAttributesIntegrationTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlJsonIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/attributes/sql/MqttAttributesSqlJsonIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.attributes.sql;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.attributes.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttAttributesSqlJsonIntegrationTest extends AbstractMqttAttributesJsonIntegrationTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlProtoIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/attributes/sql/MqttAttributesSqlProtoIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.attributes.sql;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.attributes.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest;
20 20
21 21 @DaoSqlTest
22 22 public class MqttAttributesSqlProtoIntegrationTest extends AbstractMqttAttributesProtoIntegrationTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.timeseries;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.timeseries;
17 17
18 18 import com.fasterxml.jackson.core.type.TypeReference;
19 19 import io.netty.handler.codec.mqtt.MqttQoS;
... ... @@ -26,12 +26,11 @@ import org.eclipse.paho.client.mqttv3.MqttMessage;
26 26 import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
27 27 import org.junit.After;
28 28 import org.junit.Before;
29   -import org.junit.Ignore;
30 29 import org.junit.Test;
31 30 import org.thingsboard.server.common.data.Device;
32 31 import org.thingsboard.server.common.data.device.profile.MqttTopics;
33 32 import org.thingsboard.server.common.data.id.DeviceId;
34   -import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest;
  33 +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
35 34
36 35 import java.util.Arrays;
37 36 import java.util.HashSet;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesJsonIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/timeseries/AbstractMqttTimeseriesJsonIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.timeseries;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.timeseries;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.timeseries;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.timeseries;
17 17
18 18 import com.github.os72.protobuf.dynamic.DynamicSchema;
19 19 import com.google.protobuf.Descriptors;
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.timeseries.nosql;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.timeseries.nosql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoNoSqlTest;
19   -import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest;
20 20
21 21 /**
22 22 * Created by Valerii Sosliuk on 8/22/2017.
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlJsonIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlJsonIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.timeseries.nosql;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.timeseries.nosql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoNoSqlTest;
19   -import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest;
20 20
21 21 @DaoNoSqlTest
22 22 public class MqttTimeseriesNoSqlJsonIntegrationTest extends AbstractMqttTimeseriesJsonIntegrationTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlProtoIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlProtoIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.timeseries.nosql;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.timeseries.nosql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoNoSqlTest;
19   -import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest;
20 20
21 21 @DaoNoSqlTest
22 22 public class MqttTimeseriesNoSqlProtoIntegrationTest extends AbstractMqttTimeseriesProtoIntegrationTest {
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.timeseries.sql;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.timeseries.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest;
20 20
21 21 /**
22 22 * Created by Valerii Sosliuk on 8/22/2017.
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlJsonIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlJsonIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.timeseries.sql;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.timeseries.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest;
20 20
21 21 /**
22 22 * Created by Valerii Sosliuk on 8/22/2017.
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlProtoIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlProtoIntegrationTest.java
... ... @@ -13,10 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.telemetry.timeseries.sql;
  16 +package org.thingsboard.server.transport.mqtt.telemetry.timeseries.sql;
17 17
18 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19   -import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest;
  19 +import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest;
20 20
21 21 /**
22 22 * Created by Valerii Sosliuk on 8/22/2017.
... ...
common/data/src/main/java/org/thingsboard/server/common/data/CoapDeviceType.java renamed from application/src/test/java/org/thingsboard/server/mqtt/attributes/request/nosql/MqttAttributesRequestNoSqlIntegrationTest.java
... ... @@ -13,12 +13,9 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt.attributes.request.nosql;
  16 +package org.thingsboard.server.common.data;
17 17
18   -import org.thingsboard.server.dao.service.DaoNoSqlTest;
19   -import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestIntegrationTest;
20   -
21   -
22   -@DaoNoSqlTest
23   -public class MqttAttributesRequestNoSqlIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest {
  18 +public enum CoapDeviceType {
  19 + DEFAULT,
  20 + EFENTO
24 21 }
... ...
... ... @@ -18,5 +18,6 @@ package org.thingsboard.server.common.data;
18 18 public enum DeviceTransportType {
19 19 DEFAULT,
20 20 MQTT,
21   - LWM2M
  21 + LWM2M,
  22 + COAP
22 23 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.common.data.device.data;
  17 +
  18 +import com.fasterxml.jackson.annotation.JsonAnyGetter;
  19 +import com.fasterxml.jackson.annotation.JsonAnySetter;
  20 +import com.fasterxml.jackson.annotation.JsonIgnore;
  21 +import lombok.Data;
  22 +import org.thingsboard.server.common.data.DeviceTransportType;
  23 +
  24 +import java.util.HashMap;
  25 +import java.util.Map;
  26 +
  27 +@Data
  28 +public class CoapDeviceTransportConfiguration implements DeviceTransportConfiguration {
  29 +
  30 + @JsonIgnore
  31 + private Map<String, Object> properties = new HashMap<>();
  32 +
  33 + @JsonAnyGetter
  34 + public Map<String, Object> properties() {
  35 + return this.properties;
  36 + }
  37 +
  38 + @JsonAnySetter
  39 + public void put(String name, Object value) {
  40 + this.properties.put(name, value);
  41 + }
  42 +
  43 + @Override
  44 + public DeviceTransportType getType() {
  45 + return DeviceTransportType.COAP;
  46 + }
  47 +
  48 +}
... ...
... ... @@ -29,7 +29,8 @@ import org.thingsboard.server.common.data.DeviceTransportType;
29 29 @JsonSubTypes({
30 30 @JsonSubTypes.Type(value = DefaultDeviceTransportConfiguration.class, name = "DEFAULT"),
31 31 @JsonSubTypes.Type(value = MqttDeviceTransportConfiguration.class, name = "MQTT"),
32   - @JsonSubTypes.Type(value = Lwm2mDeviceTransportConfiguration.class, name = "LWM2M")})
  32 + @JsonSubTypes.Type(value = Lwm2mDeviceTransportConfiguration.class, name = "LWM2M"),
  33 + @JsonSubTypes.Type(value = CoapDeviceTransportConfiguration.class, name = "COAP")})
33 34 public interface DeviceTransportConfiguration {
34 35
35 36 @JsonIgnore
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.common.data.device.profile;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.DeviceTransportType;
  20 +
  21 +@Data
  22 +public class CoapDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration {
  23 +
  24 + private CoapDeviceTypeConfiguration coapDeviceTypeConfiguration;
  25 +
  26 + @Override
  27 + public DeviceTransportType getType() {
  28 + return DeviceTransportType.COAP;
  29 + }
  30 +
  31 + public CoapDeviceTypeConfiguration getCoapDeviceTypeConfiguration() {
  32 + if (coapDeviceTypeConfiguration != null) {
  33 + return coapDeviceTypeConfiguration;
  34 + } else {
  35 + return new DefaultCoapDeviceTypeConfiguration();
  36 + }
  37 + }
  38 +}
\ No newline at end of file
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.common.data.device.profile;
  17 +
  18 +import com.fasterxml.jackson.annotation.JsonIgnore;
  19 +import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
  20 +import com.fasterxml.jackson.annotation.JsonSubTypes;
  21 +import com.fasterxml.jackson.annotation.JsonTypeInfo;
  22 +import org.thingsboard.server.common.data.CoapDeviceType;
  23 +
  24 +@JsonIgnoreProperties(ignoreUnknown = true)
  25 +@JsonTypeInfo(
  26 + use = JsonTypeInfo.Id.NAME,
  27 + include = JsonTypeInfo.As.PROPERTY,
  28 + property = "coapDeviceType")
  29 +@JsonSubTypes({
  30 + @JsonSubTypes.Type(value = DefaultCoapDeviceTypeConfiguration.class, name = "DEFAULT"),
  31 + @JsonSubTypes.Type(value = EfentoCoapDeviceTypeConfiguration.class, name = "EFENTO")})
  32 +public interface CoapDeviceTypeConfiguration {
  33 +
  34 + @JsonIgnore
  35 + CoapDeviceType getCoapDeviceType();
  36 +
  37 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.common.data.device.profile;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.CoapDeviceType;
  20 +
  21 +@Data
  22 +public class DefaultCoapDeviceTypeConfiguration implements CoapDeviceTypeConfiguration {
  23 +
  24 + private TransportPayloadTypeConfiguration transportPayloadTypeConfiguration;
  25 +
  26 + @Override
  27 + public CoapDeviceType getCoapDeviceType() {
  28 + return CoapDeviceType.DEFAULT;
  29 + }
  30 +
  31 + public TransportPayloadTypeConfiguration getTransportPayloadTypeConfiguration() {
  32 + if (transportPayloadTypeConfiguration != null) {
  33 + return transportPayloadTypeConfiguration;
  34 + } else {
  35 + return new JsonTransportPayloadConfiguration();
  36 + }
  37 + }
  38 +
  39 +}
... ...
... ... @@ -30,7 +30,8 @@ import org.thingsboard.server.common.data.DeviceTransportType;
30 30 @JsonSubTypes({
31 31 @JsonSubTypes.Type(value = DefaultDeviceProfileTransportConfiguration.class, name = "DEFAULT"),
32 32 @JsonSubTypes.Type(value = MqttDeviceProfileTransportConfiguration.class, name = "MQTT"),
33   - @JsonSubTypes.Type(value = Lwm2mDeviceProfileTransportConfiguration.class, name = "LWM2M")})
  33 + @JsonSubTypes.Type(value = Lwm2mDeviceProfileTransportConfiguration.class, name = "LWM2M"),
  34 + @JsonSubTypes.Type(value = CoapDeviceProfileTransportConfiguration.class, name = "COAP")})
34 35 public interface DeviceProfileTransportConfiguration {
35 36
36 37 @JsonIgnore
... ...
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/EfentoCoapDeviceTypeConfiguration.java renamed from application/src/test/java/org/thingsboard/server/mqtt/DbConfigurationTestRule.java
... ... @@ -13,19 +13,16 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.mqtt;
  16 +package org.thingsboard.server.common.data.device.profile;
17 17
18   -import org.junit.rules.TestRule;
19   -import org.junit.runner.Description;
20   -import org.junit.runners.model.Statement;
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.CoapDeviceType;
21 20
22   -/**
23   - * Created by ashvayka on 11.05.18.
24   - */
25   -public class DbConfigurationTestRule implements TestRule {
  21 +@Data
  22 +public class EfentoCoapDeviceTypeConfiguration implements CoapDeviceTypeConfiguration {
26 23
27 24 @Override
28   - public Statement apply(Statement base, Description description) {
29   - return null;
  25 + public CoapDeviceType getCoapDeviceType() {
  26 + return CoapDeviceType.EFENTO;
30 27 }
31 28 }
... ...
... ... @@ -83,6 +83,19 @@
83 83 <artifactId>mockito-core</artifactId>
84 84 <scope>test</scope>
85 85 </dependency>
  86 + <dependency>
  87 + <groupId>com.google.protobuf</groupId>
  88 + <artifactId>protobuf-java</artifactId>
  89 + </dependency>
86 90 </dependencies>
87 91
  92 + <build>
  93 + <plugins>
  94 + <plugin>
  95 + <groupId>org.xolstice.maven.plugins</groupId>
  96 + <artifactId>protobuf-maven-plugin</artifactId>
  97 + </plugin>
  98 + </plugins>
  99 + </build>
  100 +
88 101 </project>
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.eclipse.californium.core.CoapResource;
  20 +import org.eclipse.californium.core.coap.CoAP;
  21 +import org.eclipse.californium.core.server.resources.CoapExchange;
  22 +import org.thingsboard.server.common.data.DeviceProfile;
  23 +import org.thingsboard.server.common.transport.TransportContext;
  24 +import org.thingsboard.server.common.transport.TransportService;
  25 +import org.thingsboard.server.common.transport.TransportServiceCallback;
  26 +import org.thingsboard.server.common.transport.auth.SessionInfoCreator;
  27 +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
  28 +import org.thingsboard.server.gen.transport.TransportProtos;
  29 +
  30 +import java.util.UUID;
  31 +import java.util.function.BiConsumer;
  32 +
  33 +@Slf4j
  34 +public abstract class AbstractCoapTransportResource extends CoapResource {
  35 +
  36 + protected final CoapTransportContext transportContext;
  37 + protected final TransportService transportService;
  38 +
  39 + public AbstractCoapTransportResource(CoapTransportContext context, String name) {
  40 + super(name);
  41 + this.transportContext = context;
  42 + this.transportService = context.getTransportService();
  43 + }
  44 +
  45 + @Override
  46 + public void handleGET(CoapExchange exchange) {
  47 + processHandleGet(exchange);
  48 + }
  49 +
  50 + @Override
  51 + public void handlePOST(CoapExchange exchange) {
  52 + processHandlePost(exchange);
  53 + }
  54 +
  55 + protected abstract void processHandleGet(CoapExchange exchange);
  56 +
  57 + protected abstract void processHandlePost(CoapExchange exchange);
  58 +
  59 + protected void reportActivity(TransportProtos.SessionInfoProto sessionInfo, boolean hasAttributeSubscription, boolean hasRpcSubscription) {
  60 + transportContext.getTransportService().process(sessionInfo, TransportProtos.SubscriptionInfoProto.newBuilder()
  61 + .setAttributeSubscription(hasAttributeSubscription)
  62 + .setRpcSubscription(hasRpcSubscription)
  63 + .setLastActivityTime(System.currentTimeMillis())
  64 + .build(), TransportServiceCallback.EMPTY);
  65 + }
  66 +
  67 + protected static TransportProtos.SessionEventMsg getSessionEventMsg(TransportProtos.SessionEvent event) {
  68 + return TransportProtos.SessionEventMsg.newBuilder()
  69 + .setSessionType(TransportProtos.SessionType.ASYNC)
  70 + .setEvent(event).build();
  71 + }
  72 +
  73 + public static class CoapDeviceAuthCallback implements TransportServiceCallback<ValidateDeviceCredentialsResponse> {
  74 + private final TransportContext transportContext;
  75 + private final CoapExchange exchange;
  76 + private final BiConsumer<TransportProtos.SessionInfoProto, DeviceProfile> onSuccess;
  77 +
  78 + public CoapDeviceAuthCallback(TransportContext transportContext, CoapExchange exchange, BiConsumer<TransportProtos.SessionInfoProto, DeviceProfile> onSuccess) {
  79 + this.transportContext = transportContext;
  80 + this.exchange = exchange;
  81 + this.onSuccess = onSuccess;
  82 + }
  83 +
  84 + @Override
  85 + public void onSuccess(ValidateDeviceCredentialsResponse msg) {
  86 + DeviceProfile deviceProfile = msg.getDeviceProfile();
  87 + if (msg.hasDeviceInfo() && deviceProfile != null) {
  88 + TransportProtos.SessionInfoProto sessionInfoProto = SessionInfoCreator.create(msg, transportContext, UUID.randomUUID());
  89 + onSuccess.accept(sessionInfoProto, deviceProfile);
  90 + } else {
  91 + exchange.respond(CoAP.ResponseCode.UNAUTHORIZED);
  92 + }
  93 + }
  94 +
  95 + @Override
  96 + public void onError(Throwable e) {
  97 + log.warn("Failed to process request", e);
  98 + exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR);
  99 + }
  100 + }
  101 +
  102 + public static class CoapOkCallback implements TransportServiceCallback<Void> {
  103 + private final CoapExchange exchange;
  104 + private final CoAP.ResponseCode onSuccessResponse;
  105 + private final CoAP.ResponseCode onFailureResponse;
  106 +
  107 + public CoapOkCallback(CoapExchange exchange, CoAP.ResponseCode onSuccessResponse, CoAP.ResponseCode onFailureResponse) {
  108 + this.exchange = exchange;
  109 + this.onSuccessResponse = onSuccessResponse;
  110 + this.onFailureResponse = onFailureResponse;
  111 + }
  112 +
  113 + @Override
  114 + public void onSuccess(Void msg) {
  115 + exchange.respond(onSuccessResponse);
  116 + }
  117 +
  118 + @Override
  119 + public void onError(Throwable e) {
  120 + exchange.respond(onFailureResponse);
  121 + }
  122 + }
  123 +
  124 + public static class CoapNoOpCallback implements TransportServiceCallback<Void> {
  125 + private final CoapExchange exchange;
  126 +
  127 + CoapNoOpCallback(CoapExchange exchange) {
  128 + this.exchange = exchange;
  129 + }
  130 +
  131 + @Override
  132 + public void onSuccess(Void msg) {
  133 + }
  134 +
  135 + @Override
  136 + public void onError(Throwable e) {
  137 + exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR);
  138 + }
  139 + }
  140 +}
... ...
... ... @@ -22,7 +22,9 @@ import org.springframework.beans.factory.annotation.Value;
22 22 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
23 23 import org.springframework.stereotype.Component;
24 24 import org.thingsboard.server.common.transport.TransportContext;
25   -import org.thingsboard.server.transport.coap.adaptors.CoapTransportAdaptor;
  25 +import org.thingsboard.server.transport.coap.efento.adaptor.EfentoCoapAdaptor;
  26 +import org.thingsboard.server.transport.coap.adaptors.JsonCoapAdaptor;
  27 +import org.thingsboard.server.transport.coap.adaptors.ProtoCoapAdaptor;
26 28
27 29 /**
28 30 * Created by ashvayka on 18.10.18.
... ... @@ -46,6 +48,14 @@ public class CoapTransportContext extends TransportContext {
46 48
47 49 @Getter
48 50 @Autowired
49   - private CoapTransportAdaptor adaptor;
  51 + private JsonCoapAdaptor jsonCoapAdaptor;
  52 +
  53 + @Getter
  54 + @Autowired
  55 + private ProtoCoapAdaptor protoCoapAdaptor;
  56 +
  57 + @Getter
  58 + @Autowired
  59 + private EfentoCoapAdaptor efentoCoapAdaptor;
50 60
51 61 }
... ...
... ... @@ -15,32 +15,40 @@
15 15 */
16 16 package org.thingsboard.server.transport.coap;
17 17
  18 +import com.google.gson.JsonParseException;
  19 +import com.google.protobuf.Descriptors;
  20 +import lombok.Data;
18 21 import lombok.extern.slf4j.Slf4j;
19   -import org.eclipse.californium.core.CoapResource;
20   -import org.eclipse.californium.core.coap.CoAP.ResponseCode;
  22 +import org.eclipse.californium.core.coap.CoAP;
21 23 import org.eclipse.californium.core.coap.Request;
  24 +import org.eclipse.californium.core.coap.Response;
22 25 import org.eclipse.californium.core.network.Exchange;
23   -import org.eclipse.californium.core.network.ExchangeObserver;
  26 +import org.eclipse.californium.core.observe.ObserveRelation;
24 27 import org.eclipse.californium.core.server.resources.CoapExchange;
25 28 import org.eclipse.californium.core.server.resources.Resource;
26   -import org.springframework.util.ReflectionUtils;
  29 +import org.eclipse.californium.core.server.resources.ResourceObserver;
27 30 import org.thingsboard.server.common.data.DataConstants;
  31 +import org.thingsboard.server.common.data.DeviceProfile;
28 32 import org.thingsboard.server.common.data.DeviceTransportType;
  33 +import org.thingsboard.server.common.data.TransportPayloadType;
  34 +import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
  35 +import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration;
  36 +import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration;
  37 +import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration;
  38 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  39 +import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration;
  40 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  41 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
29 42 import org.thingsboard.server.common.data.security.DeviceTokenCredentials;
30 43 import org.thingsboard.server.common.msg.session.FeatureType;
31 44 import org.thingsboard.server.common.msg.session.SessionMsgType;
32 45 import org.thingsboard.server.common.transport.SessionMsgListener;
33   -import org.thingsboard.server.common.transport.TransportContext;
34   -import org.thingsboard.server.common.transport.TransportService;
35 46 import org.thingsboard.server.common.transport.TransportServiceCallback;
36 47 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
37 48 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
38   -import org.thingsboard.server.common.transport.auth.SessionInfoCreator;
39   -import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
40 49 import org.thingsboard.server.gen.transport.TransportProtos;
41   -import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg;
  50 +import org.thingsboard.server.transport.coap.adaptors.CoapTransportAdaptor;
42 51
43   -import java.lang.reflect.Field;
44 52 import java.util.List;
45 53 import java.util.Optional;
46 54 import java.util.Set;
... ... @@ -48,52 +56,60 @@ import java.util.UUID;
48 56 import java.util.concurrent.ConcurrentHashMap;
49 57 import java.util.concurrent.ConcurrentMap;
50 58 import java.util.concurrent.atomic.AtomicInteger;
51   -import java.util.function.Consumer;
52 59
53 60 @Slf4j
54   -public class CoapTransportResource extends CoapResource {
55   - // coap://localhost:port/api/v1/DEVICE_TOKEN/[attributes|telemetry|rpc[/requestId]]
  61 +public class CoapTransportResource extends AbstractCoapTransportResource {
56 62 private static final int ACCESS_TOKEN_POSITION = 3;
57 63 private static final int FEATURE_TYPE_POSITION = 4;
58 64 private static final int REQUEST_ID_POSITION = 5;
59 65
60   - private final CoapTransportContext transportContext;
61   - private final TransportService transportService;
62   - private final Field observerField;
63   - private final long timeout;
64 66 private final ConcurrentMap<String, TransportProtos.SessionInfoProto> tokenToSessionIdMap = new ConcurrentHashMap<>();
  67 + private final ConcurrentMap<String, AtomicInteger> tokenToNotificationCounterMap = new ConcurrentHashMap<>();
65 68 private final Set<UUID> rpcSubscriptions = ConcurrentHashMap.newKeySet();
66 69 private final Set<UUID> attributeSubscriptions = ConcurrentHashMap.newKeySet();
67 70
68   - public CoapTransportResource(CoapTransportContext context, String name) {
69   - super(name);
70   - this.transportContext = context;
71   - this.transportService = context.getTransportService();
72   - this.timeout = context.getTimeout();
73   - // This is important to turn off existing observable logic in
74   - // CoapResource. We will have our own observe monitoring due to 1:1
75   - // observe relationship.
76   - this.setObservable(false);
77   - observerField = ReflectionUtils.findField(Exchange.class, "observer");
78   - observerField.setAccessible(true);
  71 + public CoapTransportResource(CoapTransportContext coapTransportContext, String name) {
  72 + super(coapTransportContext, name);
  73 + this.setObservable(true); // enable observing
  74 + this.addObserver(new CoapResourceObserver());
  75 +// this.setObservable(false); // disable observing
  76 +// this.setObserveType(CoAP.Type.CON); // configure the notification type to CONs
  77 +// this.getAttributes().setObservable(); // mark observable in the Link-Format
  78 + }
  79 +
  80 + public void checkObserveRelation(Exchange exchange, Response response) {
  81 + String token = getTokenFromRequest(exchange.getRequest());
  82 + final ObserveRelation relation = exchange.getRelation();
  83 + if (relation == null || relation.isCanceled()) {
  84 + return; // because request did not try to establish a relation
  85 + }
  86 + if (CoAP.ResponseCode.isSuccess(response.getCode())) {
  87 +
  88 + if (!relation.isEstablished()) {
  89 + relation.setEstablished();
  90 + addObserveRelation(relation);
  91 + }
  92 + AtomicInteger notificationCounter = tokenToNotificationCounterMap.computeIfAbsent(token, s -> new AtomicInteger(0));
  93 + response.getOptions().setObserve(notificationCounter.getAndIncrement());
  94 + } // ObserveLayer takes care of the else case
79 95 }
80 96
81 97 @Override
82   - public void handleGET(CoapExchange exchange) {
  98 + protected void processHandleGet(CoapExchange exchange) {
83 99 Optional<FeatureType> featureType = getFeatureType(exchange.advanced().getRequest());
84   - if (!featureType.isPresent()) {
  100 + if (featureType.isEmpty()) {
85 101 log.trace("Missing feature type parameter");
86   - exchange.respond(ResponseCode.BAD_REQUEST);
  102 + exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
87 103 } else if (featureType.get() == FeatureType.TELEMETRY) {
88 104 log.trace("Can't fetch/subscribe to timeseries updates");
89   - exchange.respond(ResponseCode.BAD_REQUEST);
  105 + exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
90 106 } else if (exchange.getRequestOptions().hasObserve()) {
91 107 processExchangeGetRequest(exchange, featureType.get());
92 108 } else if (featureType.get() == FeatureType.ATTRIBUTES) {
93 109 processRequest(exchange, SessionMsgType.GET_ATTRIBUTES_REQUEST);
94 110 } else {
95 111 log.trace("Invalid feature type parameter");
96   - exchange.respond(ResponseCode.BAD_REQUEST);
  112 + exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
97 113 }
98 114 }
99 115
... ... @@ -109,11 +125,11 @@ public class CoapTransportResource extends CoapResource {
109 125 }
110 126
111 127 @Override
112   - public void handlePOST(CoapExchange exchange) {
  128 + protected void processHandlePost(CoapExchange exchange) {
113 129 Optional<FeatureType> featureType = getFeatureType(exchange.advanced().getRequest());
114   - if (!featureType.isPresent()) {
  130 + if (featureType.isEmpty()) {
115 131 log.trace("Missing feature type parameter");
116   - exchange.respond(ResponseCode.BAD_REQUEST);
  132 + exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
117 133 } else {
118 134 switch (featureType.get()) {
119 135 case ATTRIBUTES:
... ... @@ -141,14 +157,27 @@ public class CoapTransportResource extends CoapResource {
141 157 }
142 158
143 159 private void processProvision(CoapExchange exchange) {
144   - log.trace("Processing {}", exchange.advanced().getRequest());
145 160 exchange.accept();
146 161 try {
147   - transportService.process(transportContext.getAdaptor().convertToProvisionRequestMsg(UUID.randomUUID(), exchange.advanced().getRequest()),
148   - new DeviceProvisionCallback(exchange));
  162 + UUID sessionId = UUID.randomUUID();
  163 + log.trace("[{}] Processing provision publish msg [{}]!", sessionId, exchange.advanced().getRequest());
  164 + TransportProtos.ProvisionDeviceRequestMsg provisionRequestMsg;
  165 + TransportPayloadType payloadType;
  166 + try {
  167 + provisionRequestMsg = transportContext.getJsonCoapAdaptor().convertToProvisionRequestMsg(sessionId, exchange.advanced().getRequest());
  168 + payloadType = TransportPayloadType.JSON;
  169 + } catch (Exception e) {
  170 + if (e instanceof JsonParseException || (e.getCause() != null && e.getCause() instanceof JsonParseException)) {
  171 + provisionRequestMsg = transportContext.getProtoCoapAdaptor().convertToProvisionRequestMsg(sessionId, exchange.advanced().getRequest());
  172 + payloadType = TransportPayloadType.PROTOBUF;
  173 + } else {
  174 + throw new AdaptorException(e);
  175 + }
  176 + }
  177 + transportService.process(provisionRequestMsg, new DeviceProvisionCallback(exchange, payloadType));
149 178 } catch (AdaptorException e) {
150 179 log.trace("Failed to decode message: ", e);
151   - exchange.respond(ResponseCode.BAD_REQUEST);
  180 + exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
152 181 }
153 182 }
154 183
... ... @@ -159,123 +188,123 @@ public class CoapTransportResource extends CoapResource {
159 188 Request request = advanced.getRequest();
160 189
161 190 Optional<DeviceTokenCredentials> credentials = decodeCredentials(request);
162   - if (!credentials.isPresent()) {
163   - exchange.respond(ResponseCode.BAD_REQUEST);
  191 + if (credentials.isEmpty()) {
  192 + exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
164 193 return;
165 194 }
166 195
167   - transportService.process(DeviceTransportType.DEFAULT, TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(credentials.get().getCredentialsId()).build(),
168   - new DeviceAuthCallback(transportContext, exchange, sessionInfo -> {
  196 + transportService.process(DeviceTransportType.COAP, TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(credentials.get().getCredentialsId()).build(),
  197 + new CoapDeviceAuthCallback(transportContext, exchange, (sessionInfo, deviceProfile) -> {
169 198 UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB());
170 199 try {
  200 + TransportConfigurationContainer transportConfigurationContainer = getTransportConfigurationContainer(deviceProfile);
  201 + CoapTransportAdaptor coapTransportAdaptor = getCoapTransportAdaptor(transportConfigurationContainer.isJsonPayload());
171 202 switch (type) {
172 203 case POST_ATTRIBUTES_REQUEST:
173 204 transportService.process(sessionInfo,
174   - transportContext.getAdaptor().convertToPostAttributes(sessionId, request),
175   - new CoapOkCallback(exchange));
176   - reportActivity(sessionId, sessionInfo);
  205 + coapTransportAdaptor.convertToPostAttributes(sessionId, request,
  206 + transportConfigurationContainer.getAttributesMsgDescriptor()),
  207 + new CoapOkCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR));
  208 + reportActivity(sessionInfo, attributeSubscriptions.contains(sessionId), rpcSubscriptions.contains(sessionId));
177 209 break;
178 210 case POST_TELEMETRY_REQUEST:
179 211 transportService.process(sessionInfo,
180   - transportContext.getAdaptor().convertToPostTelemetry(sessionId, request),
181   - new CoapOkCallback(exchange));
182   - reportActivity(sessionId, sessionInfo);
  212 + coapTransportAdaptor.convertToPostTelemetry(sessionId, request,
  213 + transportConfigurationContainer.getTelemetryMsgDescriptor()),
  214 + new CoapOkCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR));
  215 + reportActivity(sessionInfo, attributeSubscriptions.contains(sessionId), rpcSubscriptions.contains(sessionId));
183 216 break;
184 217 case CLAIM_REQUEST:
185 218 transportService.process(sessionInfo,
186   - transportContext.getAdaptor().convertToClaimDevice(sessionId, request, sessionInfo),
187   - new CoapOkCallback(exchange));
  219 + coapTransportAdaptor.convertToClaimDevice(sessionId, request, sessionInfo),
  220 + new CoapOkCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR));
188 221 break;
189 222 case SUBSCRIBE_ATTRIBUTES_REQUEST:
190   - attributeSubscriptions.add(sessionId);
191   - advanced.setObserver(new CoapExchangeObserverProxy((ExchangeObserver) observerField.get(advanced),
192   - registerAsyncCoapSession(exchange, request, sessionInfo, sessionId)));
193   - transportService.process(sessionInfo,
194   - TransportProtos.SubscribeToAttributeUpdatesMsg.getDefaultInstance(),
195   - new CoapNoOpCallback(exchange));
  223 + TransportProtos.SessionInfoProto currentAttrSession = tokenToSessionIdMap.get(getTokenFromRequest(request));
  224 + if (currentAttrSession == null) {
  225 + attributeSubscriptions.add(sessionId);
  226 + registerAsyncCoapSession(exchange, sessionInfo, coapTransportAdaptor, getTokenFromRequest(request));
  227 + transportService.process(sessionInfo,
  228 + TransportProtos.SubscribeToAttributeUpdatesMsg.getDefaultInstance(), new CoapNoOpCallback(exchange));
  229 + }
196 230 break;
197 231 case UNSUBSCRIBE_ATTRIBUTES_REQUEST:
198   - attributeSubscriptions.remove(sessionId);
199   - TransportProtos.SessionInfoProto attrSession = lookupAsyncSessionInfo(request);
  232 + TransportProtos.SessionInfoProto attrSession = lookupAsyncSessionInfo(getTokenFromRequest(request));
200 233 if (attrSession != null) {
  234 + UUID attrSessionId = new UUID(attrSession.getSessionIdMSB(), attrSession.getSessionIdLSB());
  235 + attributeSubscriptions.remove(attrSessionId);
201 236 transportService.process(attrSession,
202 237 TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().setUnsubscribe(true).build(),
203   - new CoapOkCallback(exchange));
204   - closeAndDeregister(sessionInfo);
  238 + new CoapOkCallback(exchange, CoAP.ResponseCode.DELETED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR));
  239 + closeAndDeregister(sessionInfo, sessionId);
205 240 }
206 241 break;
207 242 case SUBSCRIBE_RPC_COMMANDS_REQUEST:
208   - rpcSubscriptions.add(sessionId);
209   - advanced.setObserver(new CoapExchangeObserverProxy((ExchangeObserver) observerField.get(advanced),
210   - registerAsyncCoapSession(exchange, request, sessionInfo, sessionId)));
211   - transportService.process(sessionInfo,
212   - TransportProtos.SubscribeToRPCMsg.getDefaultInstance(),
213   - new CoapNoOpCallback(exchange));
  243 + TransportProtos.SessionInfoProto currentRpcSession = tokenToSessionIdMap.get(getTokenFromRequest(request));
  244 + if (currentRpcSession == null) {
  245 + rpcSubscriptions.add(sessionId);
  246 + registerAsyncCoapSession(exchange, sessionInfo, coapTransportAdaptor, getTokenFromRequest(request));
  247 + transportService.process(sessionInfo,
  248 + TransportProtos.SubscribeToRPCMsg.getDefaultInstance(),
  249 + new CoapNoOpCallback(exchange));
  250 + } else {
  251 + UUID rpcSessionId = new UUID(currentRpcSession.getSessionIdMSB(), currentRpcSession.getSessionIdLSB());
  252 + reportActivity(currentRpcSession, attributeSubscriptions.contains(rpcSessionId), rpcSubscriptions.contains(rpcSessionId));
  253 + }
214 254 break;
215 255 case UNSUBSCRIBE_RPC_COMMANDS_REQUEST:
216   - rpcSubscriptions.remove(sessionId);
217   - TransportProtos.SessionInfoProto rpcSession = lookupAsyncSessionInfo(request);
  256 + TransportProtos.SessionInfoProto rpcSession = lookupAsyncSessionInfo(getTokenFromRequest(request));
218 257 if (rpcSession != null) {
  258 + UUID rpcSessionId = new UUID(rpcSession.getSessionIdMSB(), rpcSession.getSessionIdLSB());
  259 + rpcSubscriptions.remove(rpcSessionId);
219 260 transportService.process(rpcSession,
220 261 TransportProtos.SubscribeToRPCMsg.newBuilder().setUnsubscribe(true).build(),
221   - new CoapOkCallback(exchange));
222   - closeAndDeregister(sessionInfo);
  262 + new CoapOkCallback(exchange, CoAP.ResponseCode.DELETED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR));
  263 + closeAndDeregister(sessionInfo, sessionId);
223 264 }
224 265 break;
225 266 case TO_DEVICE_RPC_RESPONSE:
226 267 transportService.process(sessionInfo,
227   - transportContext.getAdaptor().convertToDeviceRpcResponse(sessionId, request),
228   - new CoapOkCallback(exchange));
  268 + coapTransportAdaptor.convertToDeviceRpcResponse(sessionId, request),
  269 + new CoapOkCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR));
229 270 break;
230 271 case TO_SERVER_RPC_REQUEST:
231   - transportService.registerSyncSession(sessionInfo, new CoapSessionListener(sessionId, exchange), transportContext.getTimeout());
  272 + transportService.registerSyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor), transportContext.getTimeout());
232 273 transportService.process(sessionInfo,
233   - transportContext.getAdaptor().convertToServerRpcRequest(sessionId, request),
  274 + coapTransportAdaptor.convertToServerRpcRequest(sessionId, request),
234 275 new CoapNoOpCallback(exchange));
235 276 break;
236 277 case GET_ATTRIBUTES_REQUEST:
237   - transportService.registerSyncSession(sessionInfo, new CoapSessionListener(sessionId, exchange), transportContext.getTimeout());
  278 + transportService.registerSyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor), transportContext.getTimeout());
238 279 transportService.process(sessionInfo,
239   - transportContext.getAdaptor().convertToGetAttributes(sessionId, request),
  280 + coapTransportAdaptor.convertToGetAttributes(sessionId, request),
240 281 new CoapNoOpCallback(exchange));
241 282 break;
242 283 }
243 284 } catch (AdaptorException e) {
244 285 log.trace("[{}] Failed to decode message: ", sessionId, e);
245   - exchange.respond(ResponseCode.BAD_REQUEST);
246   - } catch (IllegalAccessException e) {
247   - log.trace("[{}] Failed to process message: ", sessionId, e);
248   - exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR);
  286 + exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
249 287 }
250 288 }));
251 289 }
252 290
253   - private void reportActivity(UUID sessionId, TransportProtos.SessionInfoProto sessionInfo) {
254   - transportContext.getTransportService().process(sessionInfo, TransportProtos.SubscriptionInfoProto.newBuilder()
255   - .setAttributeSubscription(attributeSubscriptions.contains(sessionId))
256   - .setRpcSubscription(rpcSubscriptions.contains(sessionId))
257   - .setLastActivityTime(System.currentTimeMillis())
258   - .build(), TransportServiceCallback.EMPTY);
259   - }
260   -
261   - private TransportProtos.SessionInfoProto lookupAsyncSessionInfo(Request request) {
262   - String token = request.getSource().getHostAddress() + ":" + request.getSourcePort() + ":" + request.getTokenString();
  291 + private TransportProtos.SessionInfoProto lookupAsyncSessionInfo(String token) {
  292 + tokenToNotificationCounterMap.remove(token);
263 293 return tokenToSessionIdMap.remove(token);
264 294 }
265 295
266   - private String registerAsyncCoapSession(CoapExchange exchange, Request request, TransportProtos.SessionInfoProto sessionInfo, UUID sessionId) {
267   - String token = request.getSource().getHostAddress() + ":" + request.getSourcePort() + ":" + request.getTokenString();
  296 + private void registerAsyncCoapSession(CoapExchange exchange, TransportProtos.SessionInfoProto sessionInfo, CoapTransportAdaptor coapTransportAdaptor, String token) {
268 297 tokenToSessionIdMap.putIfAbsent(token, sessionInfo);
269   - CoapSessionListener attrListener = new CoapSessionListener(sessionId, exchange);
270   - transportService.registerAsyncSession(sessionInfo, attrListener);
  298 + transportService.registerAsyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor));
271 299 transportService.process(sessionInfo, getSessionEventMsg(TransportProtos.SessionEvent.OPEN), null);
272   - return token;
273 300 }
274 301
275   - private static TransportProtos.SessionEventMsg getSessionEventMsg(TransportProtos.SessionEvent event) {
276   - return TransportProtos.SessionEventMsg.newBuilder()
277   - .setSessionType(TransportProtos.SessionType.ASYNC)
278   - .setEvent(event).build();
  302 + private CoapSessionListener getCoapSessionListener(CoapExchange exchange, CoapTransportAdaptor coapTransportAdaptor) {
  303 + return new CoapSessionListener(exchange, coapTransportAdaptor);
  304 + }
  305 +
  306 + private String getTokenFromRequest(Request request) {
  307 + return request.getSource().getHostAddress() + ":" + request.getSourcePort() + ":" + request.getTokenString();
279 308 }
280 309
281 310 private Optional<DeviceTokenCredentials> decodeCredentials(Request request) {
... ... @@ -318,174 +347,192 @@ public class CoapTransportResource extends CoapResource {
318 347 return this;
319 348 }
320 349
321   - private static class DeviceAuthCallback implements TransportServiceCallback<ValidateDeviceCredentialsResponse> {
322   - private final TransportContext transportContext;
  350 + private static class DeviceProvisionCallback implements TransportServiceCallback<TransportProtos.ProvisionDeviceResponseMsg> {
323 351 private final CoapExchange exchange;
324   - private final Consumer<TransportProtos.SessionInfoProto> onSuccess;
  352 + private final TransportPayloadType payloadType;
325 353
326   - DeviceAuthCallback(TransportContext transportContext, CoapExchange exchange, Consumer<TransportProtos.SessionInfoProto> onSuccess) {
327   - this.transportContext = transportContext;
  354 + DeviceProvisionCallback(CoapExchange exchange, TransportPayloadType payloadType) {
328 355 this.exchange = exchange;
329   - this.onSuccess = onSuccess;
  356 + this.payloadType = payloadType;
330 357 }
331 358
332 359 @Override
333   - public void onSuccess(ValidateDeviceCredentialsResponse msg) {
334   - if (msg.hasDeviceInfo()) {
335   - onSuccess.accept(SessionInfoCreator.create(msg, transportContext, UUID.randomUUID()));
  360 + public void onSuccess(TransportProtos.ProvisionDeviceResponseMsg msg) {
  361 + CoAP.ResponseCode responseCode = CoAP.ResponseCode.CREATED;
  362 + if (!msg.getStatus().equals(TransportProtos.ProvisionResponseStatus.SUCCESS)) {
  363 + responseCode = CoAP.ResponseCode.BAD_REQUEST;
  364 + }
  365 + if (payloadType.equals(TransportPayloadType.JSON)) {
  366 + exchange.respond(responseCode, JsonConverter.toJson(msg).toString());
336 367 } else {
337   - exchange.respond(ResponseCode.UNAUTHORIZED);
  368 + exchange.respond(responseCode, msg.toByteArray());
338 369 }
339 370 }
340 371
341 372 @Override
342 373 public void onError(Throwable e) {
343 374 log.warn("Failed to process request", e);
344   - exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR);
  375 + exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR);
345 376 }
346 377 }
347 378
348   - private static class DeviceProvisionCallback implements TransportServiceCallback<ProvisionDeviceResponseMsg> {
349   - private final CoapExchange exchange;
  379 + private static class CoapSessionListener implements SessionMsgListener {
350 380
351   - DeviceProvisionCallback(CoapExchange exchange) {
352   - this.exchange = exchange;
353   - }
354   -
355   - @Override
356   - public void onSuccess(TransportProtos.ProvisionDeviceResponseMsg msg) {
357   - exchange.respond(JsonConverter.toJson(msg).toString());
358   - }
359   -
360   - @Override
361   - public void onError(Throwable e) {
362   - log.warn("Failed to process request", e);
363   - exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR);
364   - }
365   - }
366   -
367   - private static class CoapOkCallback implements TransportServiceCallback<Void> {
368 381 private final CoapExchange exchange;
  382 + private final CoapTransportAdaptor coapTransportAdaptor;
369 383
370   - CoapOkCallback(CoapExchange exchange) {
371   - this.exchange = exchange;
372   - }
373   -
374   - @Override
375   - public void onSuccess(Void msg) {
376   - exchange.respond(ResponseCode.VALID);
377   - }
378   -
379   - @Override
380   - public void onError(Throwable e) {
381   - exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR);
382   - }
383   - }
384   -
385   - private static class CoapNoOpCallback implements TransportServiceCallback<Void> {
386   - private final CoapExchange exchange;
387   -
388   - CoapNoOpCallback(CoapExchange exchange) {
389   - this.exchange = exchange;
390   - }
391   -
392   - @Override
393   - public void onSuccess(Void msg) {
394   -
395   - }
396   -
397   - @Override
398   - public void onError(Throwable e) {
399   - exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR);
400   - }
401   - }
402   -
403   - public class CoapSessionListener implements SessionMsgListener {
404   -
405   - private final CoapExchange exchange;
406   - private final AtomicInteger seqNumber = new AtomicInteger(2);
407   -
408   - CoapSessionListener(UUID sessionId, CoapExchange exchange) {
  384 + CoapSessionListener(CoapExchange exchange, CoapTransportAdaptor coapTransportAdaptor) {
409 385 this.exchange = exchange;
  386 + this.coapTransportAdaptor = coapTransportAdaptor;
410 387 }
411 388
412 389 @Override
413 390 public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg msg) {
414 391 try {
415   - exchange.respond(transportContext.getAdaptor().convertToPublish(this, msg));
  392 + exchange.respond(coapTransportAdaptor.convertToPublish(msg));
416 393 } catch (AdaptorException e) {
417 394 log.trace("Failed to reply due to error", e);
418   - exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR);
  395 + exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR);
419 396 }
420 397 }
421 398
422 399 @Override
423 400 public void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg) {
424 401 try {
425   - exchange.respond(transportContext.getAdaptor().convertToPublish(this, msg));
  402 + exchange.respond(coapTransportAdaptor.convertToPublish(isConRequest(), msg));
426 403 } catch (AdaptorException e) {
427 404 log.trace("Failed to reply due to error", e);
428   - exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR);
  405 + exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR);
429 406 }
430 407 }
431 408
432 409 @Override
433 410 public void onRemoteSessionCloseCommand(TransportProtos.SessionCloseNotificationProto sessionCloseNotification) {
434   - exchange.respond(ResponseCode.SERVICE_UNAVAILABLE);
  411 + exchange.respond(CoAP.ResponseCode.SERVICE_UNAVAILABLE);
435 412 }
436 413
437 414 @Override
438 415 public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg msg) {
439 416 try {
440   - exchange.respond(transportContext.getAdaptor().convertToPublish(this, msg));
  417 + exchange.respond(coapTransportAdaptor.convertToPublish(isConRequest(), msg));
441 418 } catch (AdaptorException e) {
442 419 log.trace("Failed to reply due to error", e);
443   - exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR);
  420 + exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR);
444 421 }
445 422 }
446 423
447 424 @Override
448 425 public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg msg) {
449 426 try {
450   - exchange.respond(transportContext.getAdaptor().convertToPublish(this, msg));
  427 + exchange.respond(coapTransportAdaptor.convertToPublish(msg));
451 428 } catch (AdaptorException e) {
452 429 log.trace("Failed to reply due to error", e);
453   - exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR);
  430 + exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR);
454 431 }
455 432 }
456 433
457   - public int getNextSeqNumber() {
458   - return seqNumber.getAndIncrement();
  434 + private boolean isConRequest() {
  435 + return exchange.advanced().getRequest().isConfirmable();
459 436 }
460 437 }
461 438
462   - public class CoapExchangeObserverProxy implements ExchangeObserver {
  439 + public class CoapResourceObserver implements ResourceObserver {
  440 +
  441 + @Override
  442 + public void changedName(String old) {
  443 + }
  444 +
  445 + @Override
  446 + public void changedPath(String old) {
  447 + }
  448 +
  449 + @Override
  450 + public void addedChild(Resource child) {
  451 + }
463 452
464   - private final ExchangeObserver proxy;
465   - private final String token;
  453 + @Override
  454 + public void removedChild(Resource child) {
  455 + }
466 456
467   - CoapExchangeObserverProxy(ExchangeObserver proxy, String token) {
468   - super();
469   - this.proxy = proxy;
470   - this.token = token;
  457 + @Override
  458 + public void addedObserveRelation(ObserveRelation relation) {
  459 + if (log.isTraceEnabled()) {
  460 + Request request = relation.getExchange().getRequest();
  461 + log.trace("Added Observe relation for token: {}", getTokenFromRequest(request));
  462 + }
471 463 }
472 464
473 465 @Override
474   - public void completed(Exchange exchange) {
475   - proxy.completed(exchange);
476   - TransportProtos.SessionInfoProto session = tokenToSessionIdMap.remove(token);
477   - if (session != null) {
478   - closeAndDeregister(session);
  466 + public void removedObserveRelation(ObserveRelation relation) {
  467 + Request request = relation.getExchange().getRequest();
  468 + String tokenFromRequest = getTokenFromRequest(request);
  469 + log.trace("Relation removed for token: {}", tokenFromRequest);
  470 + TransportProtos.SessionInfoProto sessionInfoToRemove = lookupAsyncSessionInfo(tokenFromRequest);
  471 + if (sessionInfoToRemove != null) {
  472 + closeAndDeregister(sessionInfoToRemove, new UUID(sessionInfoToRemove.getSessionIdMSB(), sessionInfoToRemove.getDeviceIdLSB()));
479 473 }
480 474 }
481 475 }
482 476
483   - private void closeAndDeregister(TransportProtos.SessionInfoProto session) {
  477 + private void closeAndDeregister(TransportProtos.SessionInfoProto session, UUID sessionId) {
484 478 transportService.process(session, getSessionEventMsg(TransportProtos.SessionEvent.CLOSED), null);
485 479 transportService.deregisterSession(session);
486   - UUID sessionId = new UUID(session.getSessionIdMSB(), session.getSessionIdLSB());
487 480 rpcSubscriptions.remove(sessionId);
488 481 attributeSubscriptions.remove(sessionId);
489 482 }
490 483
  484 + private TransportConfigurationContainer getTransportConfigurationContainer(DeviceProfile deviceProfile) throws AdaptorException {
  485 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  486 + if (transportConfiguration instanceof DefaultDeviceProfileTransportConfiguration) {
  487 + return new TransportConfigurationContainer(true);
  488 + } else if (transportConfiguration instanceof CoapDeviceProfileTransportConfiguration) {
  489 + CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration =
  490 + (CoapDeviceProfileTransportConfiguration) transportConfiguration;
  491 + CoapDeviceTypeConfiguration coapDeviceTypeConfiguration =
  492 + coapDeviceProfileTransportConfiguration.getCoapDeviceTypeConfiguration();
  493 + if (coapDeviceTypeConfiguration instanceof DefaultCoapDeviceTypeConfiguration) {
  494 + DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration =
  495 + (DefaultCoapDeviceTypeConfiguration) coapDeviceTypeConfiguration;
  496 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration =
  497 + defaultCoapDeviceTypeConfiguration.getTransportPayloadTypeConfiguration();
  498 + if (transportPayloadTypeConfiguration instanceof JsonTransportPayloadConfiguration) {
  499 + return new TransportConfigurationContainer(true);
  500 + } else {
  501 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration =
  502 + (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  503 + String deviceTelemetryProtoSchema = protoTransportPayloadConfiguration.getDeviceTelemetryProtoSchema();
  504 + String deviceAttributesProtoSchema = protoTransportPayloadConfiguration.getDeviceAttributesProtoSchema();
  505 + return new TransportConfigurationContainer(false,
  506 + protoTransportPayloadConfiguration.getTelemetryDynamicMessageDescriptor(deviceTelemetryProtoSchema),
  507 + protoTransportPayloadConfiguration.getAttributesDynamicMessageDescriptor(deviceAttributesProtoSchema));
  508 + }
  509 + } else {
  510 + throw new AdaptorException("Invalid CoapDeviceTypeConfiguration type: " + coapDeviceTypeConfiguration.getClass().getSimpleName() + "!");
  511 + }
  512 + } else {
  513 + throw new AdaptorException("Invalid DeviceProfileTransportConfiguration type" + transportConfiguration.getClass().getSimpleName() + "!");
  514 + }
  515 + }
  516 +
  517 + private CoapTransportAdaptor getCoapTransportAdaptor(boolean jsonPayloadType) {
  518 + return jsonPayloadType ? transportContext.getJsonCoapAdaptor() : transportContext.getProtoCoapAdaptor();
  519 + }
  520 +
  521 + @Data
  522 + private static class TransportConfigurationContainer {
  523 +
  524 + private boolean jsonPayload;
  525 + private Descriptors.Descriptor telemetryMsgDescriptor;
  526 + private Descriptors.Descriptor attributesMsgDescriptor;
  527 +
  528 + public TransportConfigurationContainer(boolean jsonPayload, Descriptors.Descriptor telemetryMsgDescriptor, Descriptors.Descriptor attributesMsgDescriptor) {
  529 + this.jsonPayload = jsonPayload;
  530 + this.telemetryMsgDescriptor = telemetryMsgDescriptor;
  531 + this.attributesMsgDescriptor = attributesMsgDescriptor;
  532 + }
  533 +
  534 + public TransportConfigurationContainer(boolean jsonPayload) {
  535 + this.jsonPayload = jsonPayload;
  536 + }
  537 + }
491 538 }
... ...
... ... @@ -19,10 +19,11 @@ import lombok.extern.slf4j.Slf4j;
19 19 import org.eclipse.californium.core.CoapResource;
20 20 import org.eclipse.californium.core.CoapServer;
21 21 import org.eclipse.californium.core.network.CoapEndpoint;
22   -import org.eclipse.californium.core.network.config.NetworkConfig;
  22 +import org.eclipse.californium.core.server.resources.Resource;
23 23 import org.springframework.beans.factory.annotation.Autowired;
24 24 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
25 25 import org.springframework.stereotype.Service;
  26 +import org.thingsboard.server.transport.coap.efento.CoapEfentoTransportResource;
26 27
27 28 import javax.annotation.PostConstruct;
28 29 import javax.annotation.PreDestroy;
... ... @@ -37,6 +38,8 @@ public class CoapTransportService {
37 38
38 39 private static final String V1 = "v1";
39 40 private static final String API = "api";
  41 + private static final String EFENTO = "efento";
  42 + private static final String MEASUREMENTS = "m";
40 43
41 44 @Autowired
42 45 private CoapTransportContext coapTransportContext;
... ... @@ -47,11 +50,21 @@ public class CoapTransportService {
47 50 public void init() throws UnknownHostException {
48 51 log.info("Starting CoAP transport...");
49 52 log.info("Starting CoAP transport server");
50   - this.server = new CoapServer(NetworkConfig.createStandardWithoutFile());
  53 +
  54 + this.server = new CoapServer();
51 55 createResources();
  56 + Resource root = this.server.getRoot();
  57 + TbCoapServerMessageDeliverer messageDeliverer = new TbCoapServerMessageDeliverer(root);
  58 + this.server.setMessageDeliverer(messageDeliverer);
  59 +
52 60 InetAddress addr = InetAddress.getByName(coapTransportContext.getHost());
53 61 InetSocketAddress sockAddr = new InetSocketAddress(addr, coapTransportContext.getPort());
54   - server.addEndpoint(new CoapEndpoint(sockAddr));
  62 +
  63 + CoapEndpoint.Builder coapEndpoitBuilder = new CoapEndpoint.Builder();
  64 + coapEndpoitBuilder.setInetSocketAddress(sockAddr);
  65 + CoapEndpoint coapEndpoint = coapEndpoitBuilder.build();
  66 +
  67 + server.addEndpoint(coapEndpoint);
55 68 server.start();
56 69 log.info("CoAP transport started!");
57 70 }
... ... @@ -59,7 +72,13 @@ public class CoapTransportService {
59 72 private void createResources() {
60 73 CoapResource api = new CoapResource(API);
61 74 api.add(new CoapTransportResource(coapTransportContext, V1));
  75 +
  76 + CoapResource efento = new CoapResource(EFENTO);
  77 + CoapEfentoTransportResource efentoMeasurementsTransportResource = new CoapEfentoTransportResource(coapTransportContext, MEASUREMENTS);
  78 + efento.add(efentoMeasurementsTransportResource);
  79 +
62 80 server.add(api);
  81 + server.add(efento);
63 82 }
64 83
65 84 @PreDestroy
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.eclipse.californium.core.coap.OptionSet;
  20 +import org.eclipse.californium.core.network.Exchange;
  21 +import org.eclipse.californium.core.server.ServerMessageDeliverer;
  22 +import org.eclipse.californium.core.server.resources.Resource;
  23 +import org.springframework.util.CollectionUtils;
  24 +
  25 +import java.util.List;
  26 +
  27 +@Slf4j
  28 +public class TbCoapServerMessageDeliverer extends ServerMessageDeliverer {
  29 +
  30 + public TbCoapServerMessageDeliverer(Resource root) {
  31 + super(root);
  32 + }
  33 +
  34 + @Override
  35 + protected Resource findResource(Exchange exchange) {
  36 + validateUriPath(exchange);
  37 + return findResource(exchange.getRequest().getOptions().getUriPath());
  38 + }
  39 +
  40 + private void validateUriPath(Exchange exchange) {
  41 + OptionSet options = exchange.getRequest().getOptions();
  42 + List<String> uriPathList = options.getUriPath();
  43 + String path = toPath(uriPathList);
  44 + if (path != null) {
  45 + options.setUriPath(path);
  46 + exchange.getRequest().setOptions(options);
  47 + }
  48 + }
  49 +
  50 + private String toPath(List<String> list) {
  51 + if (!CollectionUtils.isEmpty(list) && list.size() == 1) {
  52 + final String slash = "/";
  53 + String path = list.get(0);
  54 + if (path.startsWith(slash)) {
  55 + path = path.substring(slash.length());
  56 + }
  57 + return path;
  58 + }
  59 + return null;
  60 + }
  61 +
  62 +}
\ No newline at end of file
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.adaptors;
  17 +
  18 +import org.eclipse.californium.core.coap.Request;
  19 +import org.springframework.util.StringUtils;
  20 +import org.thingsboard.server.common.transport.adaptor.AdaptorException;
  21 +import org.thingsboard.server.gen.transport.TransportProtos;
  22 +
  23 +import java.util.Arrays;
  24 +import java.util.HashSet;
  25 +import java.util.List;
  26 +import java.util.Set;
  27 +
  28 +public class CoapAdaptorUtils {
  29 +
  30 + public static TransportProtos.GetAttributeRequestMsg toGetAttributeRequestMsg(Request inbound) throws AdaptorException {
  31 + List<String> queryElements = inbound.getOptions().getUriQuery();
  32 + TransportProtos.GetAttributeRequestMsg.Builder result = TransportProtos.GetAttributeRequestMsg.newBuilder();
  33 + if (queryElements != null && queryElements.size() > 0) {
  34 + Set<String> clientKeys = toKeys(queryElements, "clientKeys");
  35 + Set<String> sharedKeys = toKeys(queryElements, "sharedKeys");
  36 + if (clientKeys != null) {
  37 + result.addAllClientAttributeNames(clientKeys);
  38 + }
  39 + if (sharedKeys != null) {
  40 + result.addAllSharedAttributeNames(sharedKeys);
  41 + }
  42 + }
  43 + return result.build();
  44 + }
  45 +
  46 + private static Set<String> toKeys(List<String> queryElements, String attributeName) throws AdaptorException {
  47 + String keys = null;
  48 + for (String queryElement : queryElements) {
  49 + String[] queryItem = queryElement.split("=");
  50 + if (queryItem.length == 2 && queryItem[0].equals(attributeName)) {
  51 + keys = queryItem[1];
  52 + }
  53 + }
  54 + if (keys != null && !StringUtils.isEmpty(keys)) {
  55 + return new HashSet<>(Arrays.asList(keys.split(",")));
  56 + } else {
  57 + return null;
  58 + }
  59 + }
  60 +}
... ...
... ... @@ -15,20 +15,20 @@
15 15 */
16 16 package org.thingsboard.server.transport.coap.adaptors;
17 17
  18 +import com.google.protobuf.Descriptors;
18 19 import org.eclipse.californium.core.coap.Request;
19 20 import org.eclipse.californium.core.coap.Response;
20 21 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
21 22 import org.thingsboard.server.gen.transport.TransportProtos;
22 23 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
23   -import org.thingsboard.server.transport.coap.CoapTransportResource;
24 24
25 25 import java.util.UUID;
26 26
27 27 public interface CoapTransportAdaptor {
28 28
29   - TransportProtos.PostTelemetryMsg convertToPostTelemetry(UUID sessionId, Request inbound) throws AdaptorException;
  29 + TransportProtos.PostTelemetryMsg convertToPostTelemetry(UUID sessionId, Request inbound, Descriptors.Descriptor telemetryMsgDescriptor) throws AdaptorException;
30 30
31   - TransportProtos.PostAttributeMsg convertToPostAttributes(UUID sessionId, Request inbound) throws AdaptorException;
  31 + TransportProtos.PostAttributeMsg convertToPostAttributes(UUID sessionId, Request inbound, Descriptors.Descriptor attributesMsgDescriptor) throws AdaptorException;
32 32
33 33 TransportProtos.GetAttributeRequestMsg convertToGetAttributes(UUID sessionId, Request inbound) throws AdaptorException;
34 34
... ... @@ -38,13 +38,13 @@ public interface CoapTransportAdaptor {
38 38
39 39 TransportProtos.ClaimDeviceMsg convertToClaimDevice(UUID sessionId, Request inbound, TransportProtos.SessionInfoProto sessionInfo) throws AdaptorException;
40 40
41   - Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException;
  41 + Response convertToPublish(TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException;
42 42
43   - Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException;
  43 + Response convertToPublish(boolean isConfirmable, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException;
44 44
45   - Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException;
  45 + Response convertToPublish(boolean isConfirmable, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException;
46 46
47   - Response convertToPublish(CoapTransportResource.CoapSessionListener coapSessionListener, TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException;
  47 + Response convertToPublish(TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException;
48 48
49 49 ProvisionDeviceRequestMsg convertToProvisionRequestMsg(UUID sessionId, Request inbound) throws AdaptorException;
50 50
... ...
... ... @@ -19,31 +19,27 @@ import com.google.gson.JsonElement;
19 19 import com.google.gson.JsonObject;
20 20 import com.google.gson.JsonParser;
21 21 import com.google.gson.JsonSyntaxException;
  22 +import com.google.protobuf.Descriptors;
22 23 import lombok.extern.slf4j.Slf4j;
23 24 import org.eclipse.californium.core.coap.CoAP;
24 25 import org.eclipse.californium.core.coap.Request;
25 26 import org.eclipse.californium.core.coap.Response;
26 27 import org.springframework.stereotype.Component;
27   -import org.springframework.util.StringUtils;
28 28 import org.thingsboard.server.common.data.id.DeviceId;
29 29 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
30 30 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
31 31 import org.thingsboard.server.gen.transport.TransportProtos;
32 32 import org.thingsboard.server.transport.coap.CoapTransportResource;
33 33
34   -import java.util.Arrays;
35   -import java.util.HashSet;
36   -import java.util.List;
37 34 import java.util.Optional;
38   -import java.util.Set;
39 35 import java.util.UUID;
40 36
41   -@Component("JsonCoapAdaptor")
  37 +@Component
42 38 @Slf4j
43 39 public class JsonCoapAdaptor implements CoapTransportAdaptor {
44 40
45 41 @Override
46   - public TransportProtos.PostTelemetryMsg convertToPostTelemetry(UUID sessionId, Request inbound) throws AdaptorException {
  42 + public TransportProtos.PostTelemetryMsg convertToPostTelemetry(UUID sessionId, Request inbound, Descriptors.Descriptor telemetryMsgDescriptor) throws AdaptorException {
47 43 String payload = validatePayload(sessionId, inbound, false);
48 44 try {
49 45 return JsonConverter.convertToTelemetryProto(new JsonParser().parse(payload));
... ... @@ -53,7 +49,7 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor {
53 49 }
54 50
55 51 @Override
56   - public TransportProtos.PostAttributeMsg convertToPostAttributes(UUID sessionId, Request inbound) throws AdaptorException {
  52 + public TransportProtos.PostAttributeMsg convertToPostAttributes(UUID sessionId, Request inbound, Descriptors.Descriptor attributesMsgDescriptor) throws AdaptorException {
57 53 String payload = validatePayload(sessionId, inbound, false);
58 54 try {
59 55 return JsonConverter.convertToAttributesProto(new JsonParser().parse(payload));
... ... @@ -64,19 +60,7 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor {
64 60
65 61 @Override
66 62 public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(UUID sessionId, Request inbound) throws AdaptorException {
67   - List<String> queryElements = inbound.getOptions().getUriQuery();
68   - TransportProtos.GetAttributeRequestMsg.Builder result = TransportProtos.GetAttributeRequestMsg.newBuilder();
69   - if (queryElements != null && queryElements.size() > 0) {
70   - Set<String> clientKeys = toKeys(queryElements, "clientKeys");
71   - Set<String> sharedKeys = toKeys(queryElements, "sharedKeys");
72   - if (clientKeys != null) {
73   - result.addAllClientAttributeNames(clientKeys);
74   - }
75   - if (sharedKeys != null) {
76   - result.addAllSharedAttributeNames(sharedKeys);
77   - }
78   - }
79   - return result.build();
  63 + return CoapAdaptorUtils.toGetAttributeRequestMsg(inbound);
80 64 }
81 65
82 66 @Override
... ... @@ -106,17 +90,17 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor {
106 90 }
107 91
108 92 @Override
109   - public Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.AttributeUpdateNotificationMsg msg) throws AdaptorException {
110   - return getObserveNotification(session.getNextSeqNumber(), JsonConverter.toJson(msg));
  93 + public Response convertToPublish(boolean isConfirmable, TransportProtos.AttributeUpdateNotificationMsg msg) throws AdaptorException {
  94 + return getObserveNotification(isConfirmable, JsonConverter.toJson(msg));
111 95 }
112 96
113 97 @Override
114   - public Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.ToDeviceRpcRequestMsg msg) throws AdaptorException {
115   - return getObserveNotification(session.getNextSeqNumber(), JsonConverter.toJson(msg, true));
  98 + public Response convertToPublish(boolean isConfirmable, TransportProtos.ToDeviceRpcRequestMsg msg) throws AdaptorException {
  99 + return getObserveNotification(isConfirmable, JsonConverter.toJson(msg, true));
116 100 }
117 101
118 102 @Override
119   - public Response convertToPublish(CoapTransportResource.CoapSessionListener coapSessionListener, TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException {
  103 + public Response convertToPublish(TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException {
120 104 Response response = new Response(CoAP.ResponseCode.CONTENT);
121 105 JsonElement result = JsonConverter.toJson(msg);
122 106 response.setPayload(result.toString());
... ... @@ -134,7 +118,7 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor {
134 118 }
135 119
136 120 @Override
137   - public Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.GetAttributeResponseMsg msg) throws AdaptorException {
  121 + public Response convertToPublish(TransportProtos.GetAttributeResponseMsg msg) throws AdaptorException {
138 122 if (msg.getClientAttributeListCount() == 0 && msg.getSharedAttributeListCount() == 0) {
139 123 return new Response(CoAP.ResponseCode.NOT_FOUND);
140 124 } else {
... ... @@ -145,10 +129,10 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor {
145 129 }
146 130 }
147 131
148   - private Response getObserveNotification(int seqNumber, JsonElement json) {
  132 + private Response getObserveNotification(boolean confirmable, JsonElement json) {
149 133 Response response = new Response(CoAP.ResponseCode.CONTENT);
150   - response.getOptions().setObserve(seqNumber);
151 134 response.setPayload(json.toString());
  135 + response.setConfirmable(confirmable);
152 136 return response;
153 137 }
154 138
... ... @@ -163,19 +147,4 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor {
163 147 return payload;
164 148 }
165 149
166   - private Set<String> toKeys(List<String> queryElements, String attributeName) throws AdaptorException {
167   - String keys = null;
168   - for (String queryElement : queryElements) {
169   - String[] queryItem = queryElement.split("=");
170   - if (queryItem.length == 2 && queryItem[0].equals(attributeName)) {
171   - keys = queryItem[1];
172   - }
173   - }
174   - if (keys != null && !StringUtils.isEmpty(keys)) {
175   - return new HashSet<>(Arrays.asList(keys.split(",")));
176   - } else {
177   - return null;
178   - }
179   - }
180   -
181 150 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.adaptors;
  17 +
  18 +import com.google.gson.JsonParser;
  19 +import com.google.protobuf.Descriptors;
  20 +import com.google.protobuf.DynamicMessage;
  21 +import com.google.protobuf.InvalidProtocolBufferException;
  22 +import com.google.protobuf.util.JsonFormat;
  23 +import lombok.extern.slf4j.Slf4j;
  24 +import org.eclipse.californium.core.coap.CoAP;
  25 +import org.eclipse.californium.core.coap.Request;
  26 +import org.eclipse.californium.core.coap.Response;
  27 +import org.springframework.stereotype.Component;
  28 +import org.thingsboard.server.common.data.id.DeviceId;
  29 +import org.thingsboard.server.common.transport.adaptor.AdaptorException;
  30 +import org.thingsboard.server.common.transport.adaptor.JsonConverter;
  31 +import org.thingsboard.server.common.transport.adaptor.ProtoConverter;
  32 +import org.thingsboard.server.gen.transport.TransportProtos;
  33 +import org.thingsboard.server.transport.coap.CoapTransportResource;
  34 +
  35 +import java.util.Optional;
  36 +import java.util.UUID;
  37 +
  38 +@Component
  39 +@Slf4j
  40 +public class ProtoCoapAdaptor implements CoapTransportAdaptor {
  41 +
  42 + @Override
  43 + public TransportProtos.PostTelemetryMsg convertToPostTelemetry(UUID sessionId, Request inbound, Descriptors.Descriptor telemetryMsgDescriptor) throws AdaptorException {
  44 + try {
  45 + return JsonConverter.convertToTelemetryProto(new JsonParser().parse(dynamicMsgToJson(inbound.getPayload(), telemetryMsgDescriptor)));
  46 + } catch (Exception e) {
  47 + throw new AdaptorException(e);
  48 + }
  49 + }
  50 +
  51 + @Override
  52 + public TransportProtos.PostAttributeMsg convertToPostAttributes(UUID sessionId, Request inbound, Descriptors.Descriptor attributesMsgDescriptor) throws AdaptorException {
  53 + try {
  54 + return JsonConverter.convertToAttributesProto(new JsonParser().parse(dynamicMsgToJson(inbound.getPayload(), attributesMsgDescriptor)));
  55 + } catch (Exception e) {
  56 + throw new AdaptorException(e);
  57 + }
  58 + }
  59 +
  60 + @Override
  61 + public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(UUID sessionId, Request inbound) throws AdaptorException {
  62 + return CoapAdaptorUtils.toGetAttributeRequestMsg(inbound);
  63 + }
  64 +
  65 + @Override
  66 + public TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(UUID sessionId, Request inbound) throws AdaptorException {
  67 + Optional<Integer> requestId = CoapTransportResource.getRequestId(inbound);
  68 + if (requestId.isEmpty()) {
  69 + throw new AdaptorException("Request id is missing!");
  70 + } else {
  71 + try {
  72 + String payload = TransportProtos.ToDeviceRpcResponseMsg.parseFrom(inbound.getPayload()).getPayload();
  73 + return TransportProtos.ToDeviceRpcResponseMsg.newBuilder().setRequestId(requestId.get())
  74 + .setPayload(payload).build();
  75 + } catch (InvalidProtocolBufferException e) {
  76 + throw new AdaptorException(e);
  77 + }
  78 + }
  79 + }
  80 +
  81 + @Override
  82 + public TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(UUID sessionId, Request inbound) throws AdaptorException {
  83 + try {
  84 + return ProtoConverter.convertToServerRpcRequest(inbound.getPayload(), 0);
  85 + } catch (InvalidProtocolBufferException ex) {
  86 + throw new AdaptorException(ex);
  87 + }
  88 + }
  89 +
  90 + @Override
  91 + public TransportProtos.ClaimDeviceMsg convertToClaimDevice(UUID sessionId, Request inbound, TransportProtos.SessionInfoProto sessionInfo) throws AdaptorException {
  92 + DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB()));
  93 + try {
  94 + return ProtoConverter.convertToClaimDeviceProto(deviceId, inbound.getPayload());
  95 + } catch (InvalidProtocolBufferException ex) {
  96 + throw new AdaptorException(ex);
  97 + }
  98 + }
  99 +
  100 + @Override
  101 + public TransportProtos.ProvisionDeviceRequestMsg convertToProvisionRequestMsg(UUID sessionId, Request inbound) throws AdaptorException {
  102 + try {
  103 + return ProtoConverter.convertToProvisionRequestMsg(inbound.getPayload());
  104 + } catch (InvalidProtocolBufferException ex) {
  105 + throw new AdaptorException(ex);
  106 + }
  107 + }
  108 +
  109 + @Override
  110 + public Response convertToPublish(boolean isConfirmable, TransportProtos.AttributeUpdateNotificationMsg msg) throws AdaptorException {
  111 + return getObserveNotification(isConfirmable, msg.toByteArray());
  112 + }
  113 +
  114 + @Override
  115 + public Response convertToPublish(boolean isConfirmable, TransportProtos.ToDeviceRpcRequestMsg msg) throws AdaptorException {
  116 + return getObserveNotification(isConfirmable, msg.toByteArray());
  117 + }
  118 +
  119 + @Override
  120 + public Response convertToPublish(TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException {
  121 + Response response = new Response(CoAP.ResponseCode.CONTENT);
  122 + response.setPayload(msg.toByteArray());
  123 + return response;
  124 + }
  125 +
  126 + @Override
  127 + public Response convertToPublish(TransportProtos.GetAttributeResponseMsg msg) throws AdaptorException {
  128 + if (msg.getClientAttributeListCount() == 0 && msg.getSharedAttributeListCount() == 0) {
  129 + return new Response(CoAP.ResponseCode.NOT_FOUND);
  130 + } else {
  131 + Response response = new Response(CoAP.ResponseCode.CONTENT);
  132 + response.setPayload(msg.toByteArray());
  133 + return response;
  134 + }
  135 + }
  136 +
  137 + private Response getObserveNotification(boolean confirmable, byte[] notification) {
  138 + Response response = new Response(CoAP.ResponseCode.CONTENT);
  139 + response.setPayload(notification);
  140 + response.setConfirmable(confirmable);
  141 + return response;
  142 + }
  143 +
  144 + private String dynamicMsgToJson(byte[] bytes, Descriptors.Descriptor descriptor) throws InvalidProtocolBufferException {
  145 + DynamicMessage dynamicMessage = DynamicMessage.parseFrom(descriptor, bytes);
  146 + return JsonFormat.printer().includingDefaultValueFields().print(dynamicMessage);
  147 + }
  148 +
  149 +}
... ...
1   -/**
2   - * Copyright © 2016-2021 The Thingsboard Authors
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   -package org.thingsboard.server.transport.coap.client;
17   -
18   -import java.io.IOException;
19   -import java.util.Random;
20   -import java.util.concurrent.ExecutorService;
21   -import java.util.concurrent.Executors;
22   -import java.util.concurrent.atomic.AtomicInteger;
23   -
24   -import com.fasterxml.jackson.core.JsonProcessingException;
25   -import com.fasterxml.jackson.databind.JsonNode;
26   -import lombok.extern.slf4j.Slf4j;
27   -import org.eclipse.californium.core.CoapClient;
28   -import org.eclipse.californium.core.CoapHandler;
29   -import org.eclipse.californium.core.CoapResponse;
30   -import org.eclipse.californium.core.coap.MediaTypeRegistry;
31   -import org.thingsboard.server.common.msg.session.FeatureType;
32   -import org.slf4j.Logger;
33   -import org.slf4j.LoggerFactory;
34   -
35   -import com.fasterxml.jackson.databind.ObjectMapper;
36   -import com.fasterxml.jackson.databind.node.ArrayNode;
37   -import com.fasterxml.jackson.databind.node.ObjectNode;
38   -
39   -@Slf4j
40   -public class DeviceEmulator {
41   -
42   - public static final String SN = "SN-" + new Random().nextInt(1000);
43   - public static final String MODEL = "Model " + new Random().nextInt(1000);
44   - private static final ObjectMapper mapper = new ObjectMapper();
45   -
46   - private final String host;
47   - private final int port;
48   - private final String token;
49   -
50   - private CoapClient attributesClient;
51   - private CoapClient telemetryClient;
52   - private CoapClient rpcClient;
53   - private String[] keys;
54   - private ExecutorService executor = Executors.newFixedThreadPool(1);
55   - private AtomicInteger seq = new AtomicInteger(100);
56   -
57   - private DeviceEmulator(String host, int port, String token, String keys) {
58   - this.host = host;
59   - this.port = port;
60   - this.token = token;
61   - this.attributesClient = new CoapClient(getFeatureTokenUrl(host, port, token, FeatureType.ATTRIBUTES));
62   - this.telemetryClient = new CoapClient(getFeatureTokenUrl(host, port, token, FeatureType.TELEMETRY));
63   - this.rpcClient = new CoapClient(getFeatureTokenUrl(host, port, token, FeatureType.RPC));
64   - this.keys = keys.split(",");
65   - }
66   -
67   - public void start() {
68   - executor.submit(new Runnable() {
69   -
70   - @Override
71   - public void run() {
72   - try {
73   - sendObserveRequest(rpcClient);
74   - while (!Thread.interrupted()) {
75   -
76   -
77   - sendRequest(attributesClient, createAttributesRequest());
78   - sendRequest(telemetryClient, createTelemetryRequest());
79   -
80   - Thread.sleep(1000);
81   - }
82   - } catch (Exception e) {
83   - log.error("Error occurred while sending COAP requests", e);
84   - }
85   - }
86   -
87   - private void sendRequest(CoapClient client, JsonNode request) throws JsonProcessingException {
88   - CoapResponse telemetryResponse = client.setTimeout(60000).post(mapper.writeValueAsString(request),
89   - MediaTypeRegistry.APPLICATION_JSON);
90   - log.info("Response: {}, {}", telemetryResponse.getCode(), telemetryResponse.getResponseText());
91   - }
92   -
93   - private void sendObserveRequest(CoapClient client) throws JsonProcessingException {
94   - client.observe(new CoapHandler() {
95   - @Override
96   - public void onLoad(CoapResponse coapResponse) {
97   - log.info("Command: {}, {}", coapResponse.getCode(), coapResponse.getResponseText());
98   - try {
99   - JsonNode node = mapper.readTree(coapResponse.getResponseText());
100   - int requestId = node.get("id").asInt();
101   - String method = node.get("method").asText();
102   - ObjectNode params = (ObjectNode) node.get("params");
103   - ObjectNode response = mapper.createObjectNode();
104   - response.put("id", requestId);
105   - response.set("response", params);
106   - log.info("Command Response: {}, {}", requestId, mapper.writeValueAsString(response));
107   - CoapClient commandResponseClient = new CoapClient(getFeatureTokenUrl(host, port, token, FeatureType.RPC));
108   - commandResponseClient.post(new CoapHandler() {
109   - @Override
110   - public void onLoad(CoapResponse response) {
111   - log.info("Command Response Ack: {}, {}", response.getCode(), response.getResponseText());
112   - }
113   -
114   - @Override
115   - public void onError() {
116   - //Do nothing
117   - }
118   - }, mapper.writeValueAsString(response), MediaTypeRegistry.APPLICATION_JSON);
119   -
120   - } catch (IOException e) {
121   - log.error("Error occurred while processing COAP response", e);
122   - }
123   - }
124   -
125   - @Override
126   - public void onError() {
127   - //Do nothing
128   - }
129   - });
130   - }
131   -
132   - });
133   - }
134   -
135   - private ObjectNode createAttributesRequest() {
136   - ObjectNode element = mapper.createObjectNode();
137   - element.put("serialNumber", SN);
138   - element.put("model", MODEL);
139   - return element;
140   - }
141   -
142   - private ArrayNode createTelemetryRequest() {
143   - ArrayNode rootNode = mapper.createArrayNode();
144   - for (String key : keys) {
145   - ObjectNode element = mapper.createObjectNode();
146   - element.put(key, seq.incrementAndGet());
147   - rootNode.add(element);
148   - }
149   - return rootNode;
150   - }
151   -
152   - protected void stop() {
153   - executor.shutdownNow();
154   - }
155   -
156   - public static void main(String args[]) {
157   - if (args.length != 4) {
158   - System.out.println("Usage: java -jar " + DeviceEmulator.class.getSimpleName() + ".jar host port device_token keys");
159   - }
160   - final DeviceEmulator emulator = new DeviceEmulator(args[0], Integer.parseInt(args[1]), args[2], args[3]);
161   - emulator.start();
162   - Runtime.getRuntime().addShutdownHook(new Thread() {
163   - @Override
164   - public void run() {
165   - emulator.stop();
166   - }
167   - });
168   - }
169   -
170   -
171   - private String getFeatureTokenUrl(String host, int port, String token, FeatureType featureType) {
172   - return getBaseUrl(host, port) + token + "/" + featureType.name().toLowerCase();
173   - }
174   -
175   - private String getBaseUrl(String host, int port) {
176   - return "coap://" + host + ":" + port + "/api/v1/";
177   - }
178   -
179   -}
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.efento;
  17 +
  18 +import com.google.gson.JsonObject;
  19 +import lombok.AllArgsConstructor;
  20 +import lombok.Data;
  21 +import lombok.extern.slf4j.Slf4j;
  22 +import org.eclipse.californium.core.coap.CoAP;
  23 +import org.eclipse.californium.core.coap.Request;
  24 +import org.eclipse.californium.core.network.Exchange;
  25 +import org.eclipse.californium.core.server.resources.CoapExchange;
  26 +import org.eclipse.californium.core.server.resources.Resource;
  27 +import org.springframework.util.CollectionUtils;
  28 +import org.thingsboard.server.common.data.DeviceProfile;
  29 +import org.thingsboard.server.common.data.DeviceTransportType;
  30 +import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
  31 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  32 +import org.thingsboard.server.common.data.device.profile.EfentoCoapDeviceTypeConfiguration;
  33 +import org.thingsboard.server.common.transport.adaptor.AdaptorException;
  34 +import org.thingsboard.server.gen.transport.TransportProtos;
  35 +import org.thingsboard.server.gen.transport.coap.MeasurementTypeProtos;
  36 +import org.thingsboard.server.gen.transport.coap.MeasurementsProtos;
  37 +import org.thingsboard.server.transport.coap.AbstractCoapTransportResource;
  38 +import org.thingsboard.server.transport.coap.CoapTransportContext;
  39 +import org.thingsboard.server.transport.coap.efento.utils.CoapEfentoUtils;
  40 +
  41 +import java.util.ArrayList;
  42 +import java.util.List;
  43 +import java.util.Map;
  44 +import java.util.TreeMap;
  45 +import java.util.UUID;
  46 +import java.util.concurrent.TimeUnit;
  47 +
  48 +@Slf4j
  49 +public class CoapEfentoTransportResource extends AbstractCoapTransportResource {
  50 +
  51 + private static final int MEASUREMENTS_POSITION = 2;
  52 + private static final String MEASUREMENTS = "m";
  53 +
  54 + public CoapEfentoTransportResource(CoapTransportContext context, String name) {
  55 + super(context, name);
  56 + this.setObservable(true); // enable observing
  57 + this.setObserveType(CoAP.Type.CON); // configure the notification type to CONs
  58 +// this.getAttributes().setObservable(); // mark observable in the Link-Format
  59 + }
  60 +
  61 + @Override
  62 + protected void processHandleGet(CoapExchange exchange) {
  63 + exchange.respond(CoAP.ResponseCode.METHOD_NOT_ALLOWED);
  64 + }
  65 +
  66 + @Override
  67 + protected void processHandlePost(CoapExchange exchange) {
  68 + Exchange advanced = exchange.advanced();
  69 + Request request = advanced.getRequest();
  70 + List<String> uriPath = request.getOptions().getUriPath();
  71 + boolean validPath = uriPath.size() == MEASUREMENTS_POSITION && uriPath.get(1).equals(MEASUREMENTS);
  72 + if (!validPath) {
  73 + exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
  74 + return;
  75 + }
  76 + byte[] bytes = request.getPayload();
  77 + try {
  78 + MeasurementsProtos.ProtoMeasurements protoMeasurements = MeasurementsProtos.ProtoMeasurements.parseFrom(bytes);
  79 + log.trace("Successfully parsed Efento ProtoMeasurements: [{}]", protoMeasurements.getCloudToken());
  80 + String token = protoMeasurements.getCloudToken();
  81 + transportService.process(DeviceTransportType.COAP, TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(token).build(),
  82 + new CoapDeviceAuthCallback(transportContext, exchange, (sessionInfo, deviceProfile) -> {
  83 + UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB());
  84 + try {
  85 + validateEfentoTransportConfiguration(deviceProfile);
  86 + List<EfentoMeasurements> efentoMeasurements = getEfentoMeasurements(protoMeasurements, sessionId);
  87 + transportService.process(sessionInfo,
  88 + transportContext.getEfentoCoapAdaptor().convertToPostTelemetry(sessionId, efentoMeasurements),
  89 + new CoapOkCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR));
  90 + reportActivity(sessionInfo, false, false);
  91 + } catch (AdaptorException e) {
  92 + log.error("[{}] Failed to decode Efento ProtoMeasurements: ", sessionId, e);
  93 + exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
  94 + }
  95 + }));
  96 + } catch (Exception e) {
  97 + log.error("Failed to decode Efento ProtoMeasurements: ", e);
  98 + exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR);
  99 + }
  100 + }
  101 +
  102 + @Override
  103 + public Resource getChild(String name) {
  104 + return this;
  105 + }
  106 +
  107 + private void validateEfentoTransportConfiguration(DeviceProfile deviceProfile) throws AdaptorException {
  108 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  109 + if (transportConfiguration instanceof CoapDeviceProfileTransportConfiguration) {
  110 + CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration =
  111 + (CoapDeviceProfileTransportConfiguration) transportConfiguration;
  112 + if (!(coapDeviceProfileTransportConfiguration.getCoapDeviceTypeConfiguration() instanceof EfentoCoapDeviceTypeConfiguration)) {
  113 + throw new AdaptorException("Invalid CoapDeviceTypeConfiguration type: " + coapDeviceProfileTransportConfiguration.getCoapDeviceTypeConfiguration().getClass().getSimpleName() + "!");
  114 + }
  115 + } else {
  116 + throw new AdaptorException("Invalid DeviceProfileTransportConfiguration type" + transportConfiguration.getClass().getSimpleName() + "!");
  117 + }
  118 + }
  119 +
  120 + private List<EfentoMeasurements> getEfentoMeasurements(MeasurementsProtos.ProtoMeasurements protoMeasurements, UUID sessionId) {
  121 + String serialNumber = CoapEfentoUtils.convertByteArrayToString(protoMeasurements.getSerialNum().toByteArray());
  122 + boolean batteryStatus = protoMeasurements.getBatteryStatus();
  123 + int measurementPeriodBase = protoMeasurements.getMeasurementPeriodBase();
  124 + int measurementPeriodFactor = protoMeasurements.getMeasurementPeriodFactor();
  125 + int signal = protoMeasurements.getSignal();
  126 + List<MeasurementsProtos.ProtoChannel> channelsList = protoMeasurements.getChannelsList();
  127 + Map<Long, JsonObject> valuesMap = new TreeMap<>();
  128 + if (!CollectionUtils.isEmpty(channelsList)) {
  129 + int channel = 0;
  130 + JsonObject values;
  131 + for (MeasurementsProtos.ProtoChannel protoChannel : channelsList) {
  132 + channel++;
  133 + boolean isBinarySensor = false;
  134 + MeasurementTypeProtos.MeasurementType measurementType = protoChannel.getType();
  135 + String measurementTypeName = measurementType.name();
  136 + if (measurementType.equals(MeasurementTypeProtos.MeasurementType.OK_ALARM)
  137 + || measurementType.equals(MeasurementTypeProtos.MeasurementType.FLOODING)) {
  138 + isBinarySensor = true;
  139 + }
  140 + if (measurementPeriodFactor == 0 && isBinarySensor) {
  141 + measurementPeriodFactor = 14;
  142 + } else {
  143 + measurementPeriodFactor = 1;
  144 + }
  145 + int measurementPeriod = measurementPeriodBase * measurementPeriodFactor;
  146 + long measurementPeriodMillis = TimeUnit.SECONDS.toMillis(measurementPeriod);
  147 + long nextTransmissionAtMillis = TimeUnit.SECONDS.toMillis(protoMeasurements.getNextTransmissionAt());
  148 + int startPoint = protoChannel.getStartPoint();
  149 + int startTimestamp = protoChannel.getTimestamp();
  150 + long startTimestampMillis = TimeUnit.SECONDS.toMillis(startTimestamp);
  151 + List<Integer> sampleOffsetsList = protoChannel.getSampleOffsetsList();
  152 + if (!CollectionUtils.isEmpty(sampleOffsetsList)) {
  153 + int sampleOfssetsListSize = sampleOffsetsList.size();
  154 + for (int i = 0; i < sampleOfssetsListSize; i++) {
  155 + int sampleOffset = sampleOffsetsList.get(i);
  156 + Integer previousSampleOffset = isBinarySensor && i > 0 ? sampleOffsetsList.get(i - 1) : null;
  157 + if (sampleOffset == -32768) {
  158 + log.warn("[{}],[{}] Sensor error value! Ignoring.", sessionId, sampleOffset);
  159 + } else {
  160 + switch (measurementType) {
  161 + case TEMPERATURE:
  162 + values = valuesMap.computeIfAbsent(startTimestampMillis, k ->
  163 + CoapEfentoUtils.setDefaultMeasurements(serialNumber, batteryStatus, measurementPeriod, nextTransmissionAtMillis, signal, k));
  164 + values.addProperty("temperature_" + channel, ((double) (startPoint + sampleOffset)) / 10f);
  165 + startTimestampMillis = startTimestampMillis + measurementPeriodMillis;
  166 + break;
  167 + case HUMIDITY:
  168 + values = valuesMap.computeIfAbsent(startTimestampMillis, k ->
  169 + CoapEfentoUtils.setDefaultMeasurements(serialNumber, batteryStatus, measurementPeriod, nextTransmissionAtMillis, signal, k));
  170 + values.addProperty("humidity_" + channel, (double) (startPoint + sampleOffset));
  171 + startTimestampMillis = startTimestampMillis + measurementPeriodMillis;
  172 + break;
  173 + case ATMOSPHERIC_PRESSURE:
  174 + values = valuesMap.computeIfAbsent(startTimestampMillis, k ->
  175 + CoapEfentoUtils.setDefaultMeasurements(serialNumber, batteryStatus, measurementPeriod, nextTransmissionAtMillis, signal, k));
  176 + values.addProperty("pressure_" + channel, (double) (startPoint + sampleOffset) / 10f);
  177 + startTimestampMillis = startTimestampMillis + measurementPeriodMillis;
  178 + break;
  179 + case DIFFERENTIAL_PRESSURE:
  180 + values = valuesMap.computeIfAbsent(startTimestampMillis, k ->
  181 + CoapEfentoUtils.setDefaultMeasurements(serialNumber, batteryStatus, measurementPeriod, nextTransmissionAtMillis, signal, k));
  182 + values.addProperty("pressure_diff_" + channel, (double) (startPoint + sampleOffset));
  183 + startTimestampMillis = startTimestampMillis + measurementPeriodMillis;
  184 + break;
  185 + case OK_ALARM:
  186 + boolean currentIsOk = sampleOffset < 0;
  187 + if (previousSampleOffset != null) {
  188 + boolean previousIsOk = previousSampleOffset < 0;
  189 + boolean isOk = previousIsOk && currentIsOk;
  190 + boolean isAlarm = !previousIsOk && !currentIsOk;
  191 + if (isOk || isAlarm) {
  192 + break;
  193 + }
  194 + }
  195 + String data = currentIsOk ? "OK" : "ALARM";
  196 + long sampleOffsetMillis = TimeUnit.SECONDS.toMillis(sampleOffset);
  197 + long measurementTimestamp = startTimestampMillis + Math.abs(sampleOffsetMillis);
  198 + values = valuesMap.computeIfAbsent(measurementTimestamp - 1000, k ->
  199 + CoapEfentoUtils.setDefaultMeasurements(serialNumber, batteryStatus, measurementPeriod, nextTransmissionAtMillis, signal, k));
  200 + values.addProperty("ok_alarm_" + channel, data);
  201 + break;
  202 + case NO_SENSOR:
  203 + case UNRECOGNIZED:
  204 + log.trace("[{}][{}] Sensor error value! Ignoring.", sessionId, measurementTypeName);
  205 + break;
  206 + default:
  207 + log.trace("[{}],[{}] Unsupported measurementType! Ignoring.", sessionId, measurementTypeName);
  208 + break;
  209 + }
  210 + }
  211 + }
  212 + } else {
  213 + log.trace("[{}][{}] sampleOffsetsList list is empty!", sessionId, measurementTypeName);
  214 + }
  215 + }
  216 + } else {
  217 + throw new IllegalStateException("[" + sessionId + "]: Failed to get Efento measurements, reason: channels list is empty!");
  218 + }
  219 + if (!CollectionUtils.isEmpty(valuesMap)) {
  220 + List<EfentoMeasurements> efentoMeasurements = new ArrayList<>();
  221 + for (Long ts : valuesMap.keySet()) {
  222 + EfentoMeasurements measurement = new EfentoMeasurements(ts, valuesMap.get(ts));
  223 + efentoMeasurements.add(measurement);
  224 + }
  225 + return efentoMeasurements;
  226 + } else {
  227 + throw new IllegalStateException("[" + sessionId + "]: Failed to collect Efento measurements, reason, values map is empty!");
  228 + }
  229 + }
  230 +
  231 + @Data
  232 + @AllArgsConstructor
  233 + public static class EfentoMeasurements {
  234 +
  235 + private long ts;
  236 + private JsonObject values;
  237 +
  238 + }
  239 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.efento.adaptor;
  17 +
  18 +import com.google.gson.Gson;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.springframework.stereotype.Component;
  21 +import org.thingsboard.server.common.transport.adaptor.AdaptorException;
  22 +import org.thingsboard.server.common.transport.adaptor.JsonConverter;
  23 +import org.thingsboard.server.gen.transport.TransportProtos;
  24 +import org.thingsboard.server.transport.coap.efento.CoapEfentoTransportResource;
  25 +
  26 +import java.util.List;
  27 +import java.util.UUID;
  28 +
  29 +@Component
  30 +@Slf4j
  31 +public class EfentoCoapAdaptor {
  32 +
  33 + private static final Gson gson = new Gson();
  34 +
  35 + public TransportProtos.PostTelemetryMsg convertToPostTelemetry(UUID sessionId, List<CoapEfentoTransportResource.EfentoMeasurements> measurements) throws AdaptorException {
  36 + try {
  37 + return JsonConverter.convertToTelemetryProto(gson.toJsonTree(measurements));
  38 + } catch (Exception ex) {
  39 + log.warn("[{}] Failed to convert EfentoMeasurements to PostTelemetry request!", sessionId);
  40 + throw new AdaptorException(ex);
  41 + }
  42 + }
  43 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +package org.thingsboard.server.transport.coap.efento.utils;
  17 +
  18 +import com.google.gson.JsonObject;
  19 +
  20 +import java.text.SimpleDateFormat;
  21 +import java.util.Date;
  22 +import java.util.TimeZone;
  23 +
  24 +public class CoapEfentoUtils {
  25 +
  26 + public static String convertByteArrayToString(byte[] a) {
  27 + StringBuilder out = new StringBuilder();
  28 + for (byte b : a) {
  29 + out.append(String.format("%02X", b));
  30 + }
  31 + return out.toString();
  32 + }
  33 +
  34 + public static String convertTimestampToUtcString(long timestampInMillis) {
  35 + String dateFormat = "yyyy-MM-dd HH:mm:ss";
  36 + String utcZone = "UTC";
  37 + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
  38 + simpleDateFormat.setTimeZone(TimeZone.getTimeZone(utcZone));
  39 + return String.format("%s UTC", simpleDateFormat.format(new Date(timestampInMillis)));
  40 + }
  41 +
  42 + public static JsonObject setDefaultMeasurements(String serialNumber, boolean batteryStatus, long measurementPeriod, long nextTransmissionAtMillis, long signal, long startTimestampMillis) {
  43 + JsonObject values = new JsonObject();
  44 + values.addProperty("serial", serialNumber);
  45 + values.addProperty("battery", batteryStatus ? "ok" : "low");
  46 + values.addProperty("measured_at", convertTimestampToUtcString(startTimestampMillis));
  47 + values.addProperty("next_transmission_at", convertTimestampToUtcString(nextTransmissionAtMillis));
  48 + values.addProperty("signal", signal);
  49 + values.addProperty("measurement_interval", measurementPeriod);
  50 + return values;
  51 + }
  52 +
  53 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +syntax = "proto3";
  17 +
  18 +option java_package = "org.thingsboard.server.gen.transport.coap";
  19 +option java_outer_classname = "MeasurementTypeProtos";
  20 +
  21 +enum MeasurementType {
  22 + NO_SENSOR = 0;
  23 +
  24 + /* [°C] - Celsius degree. Resolution 0.1°C. Range [-273.2-4000.0]. Type: Continuous */
  25 + TEMPERATURE = 1;
  26 +
  27 + /* [% RH] - Relative humidity. Resolution 1%. Range [0-100]. Type: Continuous */
  28 + HUMIDITY = 2;
  29 +
  30 + /* [hPa] - Hectopascal (1hPa = 100Pa). Resolution 0.1hPa. Range: [1.0-2000.0]. Type: Continuous */
  31 + ATMOSPHERIC_PRESSURE = 3;
  32 +
  33 + /* [Pa] - Pascal. Resolution 1Pa. Range [-10000-10000]Type: Continuous */
  34 + DIFFERENTIAL_PRESSURE = 4;
  35 +
  36 + /* Sign indicates state: (+) ALARM, (-) OK. Type: Binary */
  37 + OK_ALARM = 5;
  38 +
  39 + /* [IAQ] - Iaq index. Resolution 1IAQ. Range [0-500]. Sensor return also calibration status */
  40 + /* as offset to measured value: */
  41 + /* - offset 3000: Sensor not stabilized (always returns 25 IAQ value) */
  42 + /* - offset 2000: Calibration required (sensor returns not accurate values) */
  43 + /* - offset 1000: Calibration on-going (sensor returns not accurate values) */
  44 + /* - offset 0: Calibration done (best accuracy of IAQ sensor) */
  45 + /* Type: Continuous */
  46 + IAQ = 6;
  47 +
  48 + /* Sign indicates water presence: (+) water not detected, (-) water detected. Type: Binary */
  49 + FLOODING = 7;
  50 +
  51 + /* [NB] Number of pulses. Resolution 1 pulse. Range [0-16711679]. Type: Continuous */
  52 + PULSE_CNT = 8;
  53 +
  54 + /* [Wh] - Watthour; Resolution 1Wh. Range [0-16711679]. Number of Watthours in a single period. Type: Continuous */
  55 + ELECTRICITY_METER = 9;
  56 +
  57 + /* [l] - Liter. Resolution 1l. Range [0-16711679]. Number of litres in a single period. Type: Continuous */
  58 + WATER_METER = 10;
  59 +
  60 + /* [kPa] - Kilopascal (1kPa = 1000Pa); Resolution 1kPa. Range [-1000-0]. Soil moisture (tension). Type: Continuous */
  61 + SOIL_MOISTURE = 11;
  62 +
  63 + /* [ppm] - Parts per million. Resolution 1ppm. Range [0-1000000]. Carbon monoxide concentration. Type: Continuous */
  64 + CO_GAS = 12;
  65 +
  66 + /* [ppm] - Parts per million. Resolution 0.01ppm. Range [0-1000000.00]. Nitrogen dioxide concentration. Type: Continuous*/
  67 + NO2_GAS = 13;
  68 +
  69 + /* [ppm] - Parts per million. Resolution 1ppm. Range [0-1000000]. Hydrogen sulfide concentration. Type: Continuous */
  70 + H2S_GAS = 14;
  71 +
  72 + /* [lx] - Illuminance. Resolution 0.1lx. Range [0-100000.0]. Type: Continuous */
  73 + AMBIENT_LIGHT = 15;
  74 +
  75 + /* [µg/m^3] - Micro gram per cubic meter. Resolution 1µg/m^3 Range [0-1000]. */
  76 + /* particles with an aerodynamic diameter less than 1 micrometer. Type: Continuous */
  77 + PM_1_0 = 16; // µg/m^3
  78 +
  79 + /* [µg/m^3] - Micro gram per cubic meter. Resolution 1µg/m^3 Range [0-1000]. */
  80 + /* particles with an aerodynamic diameter less than 2.5 micrometers. Type: Continuous */
  81 + PM_2_5 = 17; // µg/m^3
  82 +
  83 + /* [µg/m^3] - Micro gram per cubic meter. Resolution 1µg/m^3 Range [0-1000]. */
  84 + /* particles with an aerodynamic diameter less than 10 micrometers. Type: Continuous */
  85 + PM_10_0 = 18; // µg/m^3
  86 +
  87 + /* [dB] - Decibels. Resolution 0.1 dB. Range: [0-130.0]. Noise level. Type: Continuous */
  88 + NOISE_LEVEL = 19; // 0.1 dB
  89 +
  90 + /* [ppm] - Parts per million. Resolution 1ppm. Range [0-1000000]. Ammonia concentration. Type: Continuous */
  91 + NH3_GAS = 20;
  92 +
  93 + /* [ppm] - Parts per million. Resolution 1ppm. Range [0-1000000]. Methane concentration. Type: Continuous */
  94 + CH4_GAS = 21;
  95 +}
  96 +
  97 +
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +syntax = "proto3";
  17 +import "proto_measurement_types.proto";
  18 +
  19 +option java_package = "org.thingsboard.server.gen.transport.coap";
  20 +option java_outer_classname = "MeasurementsProtos";
  21 +
  22 +message ProtoChannel{
  23 + /* Type of channel */
  24 + MeasurementType type = 1;
  25 +
  26 + /* Timestamp of the first sample (the oldest one) in seconds since UNIX EPOCH 01-01-1970 */
  27 + int32 timestamp = 2;
  28 +
  29 + /* Only used for 'Continuous' sensor types. Value used as the starting point for calculating the values of all */
  30 + /* measurements in the package. */
  31 + /* Format defined by 'MeasurementType' field */
  32 + sint32 start_point = 4;
  33 +
  34 + /* 'Continuous' sensor types */
  35 + /* Value of the offset from the 'start_point' for each measurement in the package. The oldest sample first ([0]). */
  36 + /* 'sample_offsets' format defined by 'MeasurementType' field. */
  37 + /* Example: MeasurementType = 1 (temperature), start_point = 100, sample_offsets[0] = 15, sample_offsets[1] = 20 */
  38 + /* 1st sample in the package temperature value = 11.5 °C, 2nd sample in the package temperature value = 12 °C */
  39 + /* Calculating timestamps of the measurements: timestamp = 1606391700, measurement_period_base = 60, */
  40 + /* measurement_period_factor = 1. Timestamp of the 1st sample = 1606391700, timestamp of the 2nd sample = 1606391760 */
  41 + /* 'Binary' sensor types: */
  42 + /* Absolute value of the 'sample_offsets' field indicates the offset in seconds from 'timestamp' field. */
  43 + /* Sign (- or +) indicates the state of measurements depend of sensor type. */
  44 + /* Value of this field equals to '1' or '-1' indicates the state at the 'timestamp'. Other values */
  45 + /* indicate the state of the relay at the time (in seconds) equal to 'timestamp' + value. */
  46 + /* Values of this field are incremented starting from 1 (1->0: state at the time */
  47 + /* of 'timestamp', 2->1: state at the time equal to 'timestamp' + 1 s, 3->2 : */
  48 + /* state at the time equal to 'timestamp' + 2 s, etc.). The first and the last sample define the time range of the */
  49 + /* measurements. Only state changes in the time range are included in the 'sample_offsets' field */
  50 + /* Examples: if 'timestamp' value is 1553518060 and 'sample_offsets' equals '1', it means that at 1553518060 the state */
  51 + /* was high, if 'timestamp' value is 1553518060 and 'sample_offsets' equals '-9', it means at 1553518068 the state was low */
  52 + repeated sint32 sample_offsets = 5 [packed=true];
  53 +
  54 + /* Deprecated - configuration is sent to endpoint 'c' */
  55 + //int32 lo_threshold = 6;
  56 +
  57 + /* Deprecated - configuration is sent to endpoint 'c' */
  58 + //int32 hi_threshold = 7;
  59 +
  60 + /* Deprecated - configurationis sent to endpoint 'c' */
  61 + //int32 diff_threshold = 8;
  62 + }
  63 +
  64 +message ProtoMeasurements {
  65 +
  66 + /* serial number of the device */
  67 + bytes serial_num = 1;
  68 +
  69 + /* true - battery ok, false - battery low */
  70 + bool battery_status = 2;
  71 +
  72 + /* 'Measurement_period_base' and 'measurement_period_factor' define how often the measurements are taken. */
  73 + /* Sensors of 'Continuous' type take measurement each Measurement_period_base * measurement_period_factor. */
  74 + /* Sensors of 'Binary' type take measurement each Measurement_period_base. */
  75 + /* For backward compatibility with versions 5.x in case of binary/mixed sensors, if the 'measurement_period_factor' is */
  76 + /* not sent (equal to 0), then the default value '14' shall be used for period calculation. */
  77 + /* For backward compatibility with versions 5.x in case of continues sensors, if the measurement_period_factor is */
  78 + /* not sent (equal to 0), then the default value '1' shall be used for period calculation. */
  79 + /* measurement period base in seconds */
  80 + uint32 measurement_period_base = 3;
  81 +
  82 + /* Measurement period factor */
  83 + uint32 measurement_period_factor = 8;
  84 +
  85 + repeated ProtoChannel channels = 4;
  86 +
  87 + /* Timestamp of the next scheduled transmission. If the device will not send data until this time, */
  88 + /* it should be considered as 'lost' */
  89 + uint32 next_transmission_at = 5;
  90 +
  91 + /* reason of transmission - unsigned integer where each bit indicates different */
  92 + /* possible communication reason. Can be more than one */
  93 + /* - bit 0: first message after sensor reset */
  94 + /* - bit 1: user button triggered */
  95 + /* - bit 2: user BLE triggered */
  96 + /* - bit 3-7: number of retries -> incremented after each unsuccessful transmission. Max value 4. */
  97 + /* Set to 0 after a successful transmission. */
  98 + /* - bit 8: channel 1 lower threshold exceeded */
  99 + /* - bit 9: channel 1 lower threshold returned */
  100 + /* - bit 10: channel 1 higher threshold exceeded */
  101 + /* - bit 11: channel 1 higher threshold returned */
  102 + /* - bit 12: channel 1 differential threshold crossed */
  103 + /* - bits 13-17: channel 2 thresholds (same as for channel 1) */
  104 + /* - bits 18-22: channel 3 thresholds (same as for channel 1) */
  105 + /* - bits 23-27: channel 4 or 5 or 6 thresholds (same as for channel 1) */
  106 + uint32 transfer_reason = 6;
  107 +
  108 + /* Signal strength level mapped from RSSI */
  109 + /* - 0 : 113 dBm or less */
  110 + /* - 1 : 111 dBm */
  111 + /* - 2...30 : 109...-53 dBm */
  112 + /* - 31 : -51 dBm or greater */
  113 + /* - 99 : Not known or not detectable */
  114 + uint32 signal = 7;
  115 +
  116 + /* Hash of the current configuration. Hash value changes each time a device receives a new configuration */
  117 + uint32 hash = 9;
  118 +
  119 + /* Optional string up to 36 bytes long. Can be set to any user define value or hold device's IMEI */
  120 + string cloud_token = 16;
  121 +}
\ No newline at end of file
... ...
... ... @@ -73,6 +73,9 @@ public class ProtoConverter {
73 73 }
74 74
75 75 public static TransportProtos.ClaimDeviceMsg convertToClaimDeviceProto(DeviceId deviceId, byte[] bytes) throws InvalidProtocolBufferException {
  76 + if (bytes == null) {
  77 + return buildClaimDeviceMsg(deviceId, DataConstants.DEFAULT_SECRET_KEY, 0);
  78 + }
76 79 TransportApiProtos.ClaimDevice proto = TransportApiProtos.ClaimDevice.parseFrom(bytes);
77 80 String secretKey = proto.getSecretKey() != null ? proto.getSecretKey() : DataConstants.DEFAULT_SECRET_KEY;
78 81 long durationMs = proto.getDurationMs();
... ...
... ... @@ -41,6 +41,9 @@ import org.thingsboard.server.common.data.DeviceProfileProvisionType;
41 41 import org.thingsboard.server.common.data.DeviceProfileType;
42 42 import org.thingsboard.server.common.data.DeviceTransportType;
43 43 import org.thingsboard.server.common.data.Tenant;
  44 +import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
  45 +import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration;
  46 +import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration;
44 47 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
45 48 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration;
46 49 import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm;
... ... @@ -49,6 +52,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC
49 52 import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration;
50 53 import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
51 54 import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  55 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
52 56 import org.thingsboard.server.common.data.id.DeviceProfileId;
53 57 import org.thingsboard.server.common.data.id.TenantId;
54 58 import org.thingsboard.server.common.data.page.PageData;
... ... @@ -355,11 +359,17 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
355 359 if (mqttTransportConfiguration.getTransportPayloadTypeConfiguration() instanceof ProtoTransportPayloadConfiguration) {
356 360 ProtoTransportPayloadConfiguration protoTransportPayloadTypeConfiguration =
357 361 (ProtoTransportPayloadConfiguration) mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
358   - try {
359   - validateTransportProtoSchema(protoTransportPayloadTypeConfiguration.getDeviceAttributesProtoSchema(), ATTRIBUTES_PROTO_SCHEMA);
360   - validateTransportProtoSchema(protoTransportPayloadTypeConfiguration.getDeviceTelemetryProtoSchema(), TELEMETRY_PROTO_SCHEMA);
361   - } catch (Exception exception) {
362   - throw new DataValidationException(exception.getMessage());
  362 + validateProtoSchemas(protoTransportPayloadTypeConfiguration);
  363 + }
  364 + } else if (transportConfiguration instanceof CoapDeviceProfileTransportConfiguration) {
  365 + CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration;
  366 + CoapDeviceTypeConfiguration coapDeviceTypeConfiguration = coapDeviceProfileTransportConfiguration.getCoapDeviceTypeConfiguration();
  367 + if (coapDeviceTypeConfiguration instanceof DefaultCoapDeviceTypeConfiguration) {
  368 + DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = (DefaultCoapDeviceTypeConfiguration) coapDeviceTypeConfiguration;
  369 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = defaultCoapDeviceTypeConfiguration.getTransportPayloadTypeConfiguration();
  370 + if (transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration) {
  371 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  372 + validateProtoSchemas(protoTransportPayloadConfiguration);
363 373 }
364 374 }
365 375 }
... ... @@ -403,6 +413,15 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
403 413 }
404 414 }
405 415
  416 + private void validateProtoSchemas(ProtoTransportPayloadConfiguration protoTransportPayloadTypeConfiguration) {
  417 + try {
  418 + validateTransportProtoSchema(protoTransportPayloadTypeConfiguration.getDeviceAttributesProtoSchema(), ATTRIBUTES_PROTO_SCHEMA);
  419 + validateTransportProtoSchema(protoTransportPayloadTypeConfiguration.getDeviceTelemetryProtoSchema(), TELEMETRY_PROTO_SCHEMA);
  420 + } catch (Exception exception) {
  421 + throw new DataValidationException(exception.getMessage());
  422 + }
  423 + }
  424 +
406 425 private void validateTransportProtoSchema(String schema, String schemaName) throws IllegalArgumentException {
407 426 ProtoParser schemaParser = new ProtoParser(LOCATION, schema.toCharArray());
408 427 ProtoFileElement protoFileElement;
... ...
... ... @@ -42,6 +42,7 @@ import org.thingsboard.server.common.data.EntityView;
42 42 import org.thingsboard.server.common.data.Tenant;
43 43 import org.thingsboard.server.common.data.device.DeviceSearchQuery;
44 44 import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
  45 +import org.thingsboard.server.common.data.device.data.CoapDeviceTransportConfiguration;
45 46 import org.thingsboard.server.common.data.device.data.DefaultDeviceConfiguration;
46 47 import org.thingsboard.server.common.data.device.data.DefaultDeviceTransportConfiguration;
47 48 import org.thingsboard.server.common.data.device.data.DeviceData;
... ... @@ -242,6 +243,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
242 243 case LWM2M:
243 244 deviceData.setTransportConfiguration(new Lwm2mDeviceTransportConfiguration());
244 245 break;
  246 + case COAP:
  247 + deviceData.setTransportConfiguration(new CoapDeviceTransportConfiguration());
  248 + break;
245 249 }
246 250 }
247 251 return deviceData;
... ...
... ... @@ -65,7 +65,7 @@
65 65 <jackson-annotations.version>2.12.1</jackson-annotations.version>
66 66 <jackson-core.version>2.12.1</jackson-core.version>
67 67 <json-schema-validator.version>2.2.6</json-schema-validator.version>
68   - <californium.version>1.0.2</californium.version>
  68 + <californium.version>2.6.1</californium.version>
69 69 <gson.version>2.6.2</gson.version>
70 70 <freemarker.version>2.3.30</freemarker.version>
71 71 <mail.version>1.6.2</mail.version>
... ...
... ... @@ -97,6 +97,7 @@ import { DeviceProfileDialogComponent } from '@home/components/profile/device-pr
97 97 import { DeviceProfileAutocompleteComponent } from '@home/components/profile/device-profile-autocomplete.component';
98 98 import { MqttDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/mqtt-device-profile-transport-configuration.component';
99 99 import { Lwm2mDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/lwm2m-device-profile-transport-configuration.component';
  100 +import {CoapDeviceProfileTransportConfigurationComponent} from '@home/components/profile/device/coap-device-profile-transport-configuration.component';
100 101 import { DeviceProfileAlarmsComponent } from '@home/components/profile/alarm/device-profile-alarms.component';
101 102 import { DeviceProfileAlarmComponent } from '@home/components/profile/alarm/device-profile-alarm.component';
102 103 import { CreateAlarmRulesComponent } from '@home/components/profile/alarm/create-alarm-rules.component';
... ... @@ -213,6 +214,7 @@ import { DisplayWidgetTypesPanelComponent } from '@home/components/dashboard-pag
213 214 DefaultDeviceProfileTransportConfigurationComponent,
214 215 MqttDeviceProfileTransportConfigurationComponent,
215 216 Lwm2mDeviceProfileTransportConfigurationComponent,
  217 + CoapDeviceProfileTransportConfigurationComponent,
216 218 DeviceProfileTransportConfigurationComponent,
217 219 CreateAlarmRulesComponent,
218 220 AlarmRuleComponent,
... ... @@ -315,6 +317,7 @@ import { DisplayWidgetTypesPanelComponent } from '@home/components/dashboard-pag
315 317 DefaultDeviceProfileTransportConfigurationComponent,
316 318 MqttDeviceProfileTransportConfigurationComponent,
317 319 Lwm2mDeviceProfileTransportConfigurationComponent,
  320 + CoapDeviceProfileTransportConfigurationComponent,
318 321 DeviceProfileTransportConfigurationComponent,
319 322 CreateAlarmRulesComponent,
320 323 AlarmRuleComponent,
... ...
  1 +<!--
  2 +
  3 + Copyright © 2016-2021 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<form [formGroup]="coapDeviceProfileTransportConfigurationFormGroup" style="padding-bottom: 16px;">
  19 + <section formGroupName="coapDeviceTypeConfiguration">
  20 + <fieldset class="fields-group">
  21 + <legend class="group-title" translate>device-profile.coap-device-type</legend>
  22 + <div fxLayoutGap="8px" fxLayout="column">
  23 + <mat-form-field class="mat-block">
  24 + <mat-select formControlName="coapDeviceType" required>
  25 + <mat-option *ngFor="let type of coapTransportDeviceTypes" [value]="type">
  26 + {{coapTransportDeviceTypeTranslations.get(type) | translate}}
  27 + </mat-option>
  28 + </mat-select>
  29 + <mat-error *ngIf="coapDeviceProfileTransportConfigurationFormGroup.get('coapDeviceTypeConfiguration.coapDeviceType').hasError('required')">
  30 + {{ 'device-profile.coap-device-type-required' | translate }}
  31 + </mat-error>
  32 + </mat-form-field>
  33 + </div>
  34 + </fieldset>
  35 + <div *ngIf="coapDeviceTypeDefault" formGroupName="transportPayloadTypeConfiguration">
  36 + <fieldset class="fields-group">
  37 + <legend class="group-title" translate>device-profile.coap-device-payload-type</legend>
  38 + <div fxLayoutGap="8px" fxLayout="column">
  39 + <mat-form-field class="mat-block">
  40 + <mat-select formControlName="transportPayloadType" required>
  41 + <mat-option *ngFor="let type of transportPayloadTypes" [value]="type">
  42 + {{transportPayloadTypeTranslations.get(type) | translate}}
  43 + </mat-option>
  44 + </mat-select>
  45 + <mat-error *ngIf="coapDeviceProfileTransportConfigurationFormGroup.get('coapDeviceTypeConfiguration.transportPayloadTypeConfiguration.transportPayloadType').hasError('required')">
  46 + {{ 'device-profile.mqtt-payload-type-required' | translate }}
  47 + </mat-error>
  48 + </mat-form-field>
  49 + <div *ngIf="protoPayloadType" fxLayout="column">
  50 + <mat-form-field fxFlex>
  51 + <mat-label translate>device-profile.telemetry-proto-schema</mat-label>
  52 + <textarea matInput required formControlName="deviceTelemetryProtoSchema" rows="5"></textarea>
  53 + <mat-error *ngIf="coapDeviceProfileTransportConfigurationFormGroup.get('coapDeviceTypeConfiguration.transportPayloadTypeConfiguration.deviceTelemetryProtoSchema').hasError('required')">
  54 + {{ 'device-profile.telemetry-proto-schema-required' | translate}}
  55 + </mat-error>
  56 + </mat-form-field>
  57 + <mat-form-field fxFlex>
  58 + <mat-label translate>device-profile.attributes-proto-schema</mat-label>
  59 + <textarea matInput required formControlName="deviceAttributesProtoSchema" rows="5"></textarea>
  60 + <mat-error *ngIf="coapDeviceProfileTransportConfigurationFormGroup.get('coapDeviceTypeConfiguration.transportPayloadTypeConfiguration.deviceAttributesProtoSchema').hasError('required')">
  61 + {{ 'device-profile.attributes-proto-schema-required' | translate}}
  62 + </mat-error>
  63 + </mat-form-field>
  64 + </div>
  65 + </div>
  66 + </fieldset>
  67 + </div>
  68 + </section>
  69 +</form>
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  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 +:host{
  17 + .fields-group {
  18 + padding: 8px;
  19 + margin: 10px 0;
  20 + border: 1px groove rgba(0, 0, 0, .25);
  21 + border-radius: 4px;
  22 +
  23 + legend {
  24 + color: rgba(0, 0, 0, .7);
  25 + }
  26 +
  27 + .tb-hint{
  28 + padding: 0;
  29 + }
  30 + }
  31 +}
... ...
  1 +///
  2 +/// Copyright © 2016-2021 The Thingsboard Authors
  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 +import { Component, forwardRef, Input, OnInit } from '@angular/core';
  18 +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
  19 +import { Store } from '@ngrx/store';
  20 +import { AppState } from '@app/core/core.state';
  21 +import { coerceBooleanProperty } from '@angular/cdk/coercion';
  22 +import {
  23 + CoapDeviceProfileTransportConfiguration,
  24 + coapDeviceTypeTranslationMap,
  25 + CoapTransportDeviceType,
  26 + defaultAttributesSchema,
  27 + defaultTelemetrySchema,
  28 + DeviceProfileTransportConfiguration,
  29 + DeviceTransportType,
  30 + TransportPayloadType,
  31 + transportPayloadTypeTranslationMap,
  32 +} from '@shared/models/device.models';
  33 +import { isDefinedAndNotNull } from '@core/utils';
  34 +
  35 +@Component({
  36 + selector: 'tb-coap-device-profile-transport-configuration',
  37 + templateUrl: './coap-device-profile-transport-configuration.component.html',
  38 + styleUrls: ['./coap-device-profile-transport-configuration.component.scss'],
  39 + providers: [{
  40 + provide: NG_VALUE_ACCESSOR,
  41 + useExisting: forwardRef(() => CoapDeviceProfileTransportConfigurationComponent),
  42 + multi: true
  43 + }]
  44 +})
  45 +export class CoapDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit {
  46 +
  47 + coapTransportDeviceTypes = Object.keys(CoapTransportDeviceType);
  48 +
  49 + coapTransportDeviceTypeTranslations = coapDeviceTypeTranslationMap;
  50 +
  51 + transportPayloadTypes = Object.keys(TransportPayloadType);
  52 +
  53 + transportPayloadTypeTranslations = transportPayloadTypeTranslationMap;
  54 +
  55 + coapDeviceProfileTransportConfigurationFormGroup: FormGroup;
  56 +
  57 + private requiredValue: boolean;
  58 +
  59 + private transportPayloadTypeConfiguration = this.fb.group({
  60 + transportPayloadType: [TransportPayloadType.JSON, Validators.required],
  61 + deviceTelemetryProtoSchema: [defaultTelemetrySchema, Validators.required],
  62 + deviceAttributesProtoSchema: [defaultAttributesSchema, Validators.required]
  63 + });
  64 +
  65 + get required(): boolean {
  66 + return this.requiredValue;
  67 + }
  68 +
  69 + @Input()
  70 + set required(value: boolean) {
  71 + this.requiredValue = coerceBooleanProperty(value);
  72 + }
  73 +
  74 + @Input()
  75 + disabled: boolean;
  76 +
  77 + private propagateChange = (v: any) => { };
  78 +
  79 + constructor(private store: Store<AppState>,
  80 + private fb: FormBuilder) {
  81 + }
  82 +
  83 + registerOnChange(fn: any): void {
  84 + this.propagateChange = fn;
  85 + }
  86 +
  87 + registerOnTouched(fn: any): void {
  88 + }
  89 +
  90 + ngOnInit() {
  91 + this.coapDeviceProfileTransportConfigurationFormGroup = this.fb.group({
  92 + coapDeviceTypeConfiguration: this.fb.group({
  93 + coapDeviceType: [CoapTransportDeviceType.DEFAULT, Validators.required],
  94 + transportPayloadTypeConfiguration: this.transportPayloadTypeConfiguration
  95 + })
  96 + }
  97 + );
  98 + this.coapDeviceProfileTransportConfigurationFormGroup.get('coapDeviceTypeConfiguration.coapDeviceType')
  99 + .valueChanges.subscribe(coapDeviceType => {
  100 + this.updateCoapDeviceTypeBasedControls(coapDeviceType, true);
  101 + });
  102 + this.coapDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => {
  103 + this.updateModel();
  104 + });
  105 + }
  106 +
  107 + get coapDeviceTypeDefault(): boolean {
  108 + const coapDeviceType = this.coapDeviceProfileTransportConfigurationFormGroup.get('coapDeviceTypeConfiguration.coapDeviceType').value;
  109 + return coapDeviceType === CoapTransportDeviceType.DEFAULT;
  110 + }
  111 +
  112 + get protoPayloadType(): boolean {
  113 + const transportPayloadTypePath = 'coapDeviceTypeConfiguration.transportPayloadTypeConfiguration.transportPayloadType';
  114 + const transportPayloadType = this.coapDeviceProfileTransportConfigurationFormGroup.get(transportPayloadTypePath).value;
  115 + return transportPayloadType === TransportPayloadType.PROTOBUF;
  116 + }
  117 +
  118 +
  119 + private updateCoapDeviceTypeBasedControls(type: CoapTransportDeviceType, forceUpdated = false) {
  120 + const coapDeviceTypeConfigurationFormGroup = this.coapDeviceProfileTransportConfigurationFormGroup
  121 + .get('coapDeviceTypeConfiguration') as FormGroup;
  122 + if (forceUpdated) {
  123 + coapDeviceTypeConfigurationFormGroup.patchValue({
  124 + transportPayloadTypeConfiguration: this.transportPayloadTypeConfiguration
  125 + }, {emitEvent: false});
  126 + }
  127 + if (type === CoapTransportDeviceType.DEFAULT && !this.disabled) {
  128 + coapDeviceTypeConfigurationFormGroup.get('transportPayloadTypeConfiguration').enable({emitEvent: false});
  129 + } else {
  130 + coapDeviceTypeConfigurationFormGroup.get('transportPayloadTypeConfiguration').disable({emitEvent: false});
  131 + }
  132 + }
  133 +
  134 + setDisabledState(isDisabled: boolean): void {
  135 + this.disabled = isDisabled;
  136 + if (this.disabled) {
  137 + this.coapDeviceProfileTransportConfigurationFormGroup.disable({emitEvent: false});
  138 + } else {
  139 + this.coapDeviceProfileTransportConfigurationFormGroup.enable({emitEvent: false});
  140 + }
  141 + }
  142 +
  143 + writeValue(value: CoapDeviceProfileTransportConfiguration | null): void {
  144 + if (isDefinedAndNotNull(value)) {
  145 + this.coapDeviceProfileTransportConfigurationFormGroup.patchValue(value, {emitEvent: false});
  146 + this.updateCoapDeviceTypeBasedControls(value.coapDeviceTypeConfiguration?.coapDeviceType);
  147 + }
  148 + }
  149 +
  150 + private updateModel() {
  151 + let configuration: DeviceProfileTransportConfiguration = null;
  152 + if (this.coapDeviceProfileTransportConfigurationFormGroup.valid) {
  153 + configuration = this.coapDeviceProfileTransportConfigurationFormGroup.value;
  154 + configuration.type = DeviceTransportType.COAP;
  155 + }
  156 + this.propagateChange(configuration);
  157 + }
  158 +
  159 +}
... ...
... ... @@ -35,5 +35,11 @@
35 35 formControlName="configuration">
36 36 </tb-lwm2m-device-profile-transport-configuration>
37 37 </ng-template-->
  38 + <ng-template [ngSwitchCase]="deviceTransportType.COAP">
  39 + <tb-coap-device-profile-transport-configuration
  40 + [required]="required"
  41 + formControlName="configuration">
  42 + </tb-coap-device-profile-transport-configuration>
  43 + </ng-template>
38 44 </div>
39 45 </div>
... ...
... ... @@ -65,8 +65,8 @@
65 65 <div fxLayoutGap="8px" fxLayout="column">
66 66 <mat-form-field class="mat-block">
67 67 <mat-select formControlName="transportPayloadType" required>
68   - <mat-option *ngFor="let type of mqttTransportPayloadTypes" [value]="type">
69   - {{mqttTransportPayloadTypeTranslations.get(type) | translate}}
  68 + <mat-option *ngFor="let type of transportPayloadTypes" [value]="type">
  69 + {{transportPayloadTypeTranslations.get(type) | translate}}
70 70 </mat-option>
71 71 </mat-select>
72 72 <mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('transportPayloadTypeConfiguration.transportPayloadType').hasError('required')">
... ...
... ... @@ -28,11 +28,13 @@ import { Store } from '@ngrx/store';
28 28 import { AppState } from '@app/core/core.state';
29 29 import { coerceBooleanProperty } from '@angular/cdk/coercion';
30 30 import {
  31 + defaultAttributesSchema,
  32 + defaultTelemetrySchema,
31 33 DeviceProfileTransportConfiguration,
32 34 DeviceTransportType,
33 35 MqttDeviceProfileTransportConfiguration,
34   - MqttTransportPayloadType,
35   - mqttTransportPayloadTypeTranslationMap
  36 + TransportPayloadType,
  37 + transportPayloadTypeTranslationMap
36 38 } from '@shared/models/device.models';
37 39 import { isDefinedAndNotNull } from '@core/utils';
38 40
... ... @@ -48,40 +50,12 @@ import { isDefinedAndNotNull } from '@core/utils';
48 50 })
49 51 export class MqttDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit {
50 52
51   - mqttTransportPayloadTypes = Object.keys(MqttTransportPayloadType);
  53 + transportPayloadTypes = Object.keys(TransportPayloadType);
52 54
53   - mqttTransportPayloadTypeTranslations = mqttTransportPayloadTypeTranslationMap;
  55 + transportPayloadTypeTranslations = transportPayloadTypeTranslationMap;
54 56
55 57 mqttDeviceProfileTransportConfigurationFormGroup: FormGroup;
56 58
57   - private defaultTelemetrySchema =
58   - 'syntax ="proto3";\n' +
59   - 'package telemetry;\n' +
60   - '\n' +
61   - 'message SensorDataReading {\n' +
62   - '\n' +
63   - ' double temperature = 1;\n' +
64   - ' double humidity = 2;\n' +
65   - ' InnerObject innerObject = 3;\n' +
66   - '\n' +
67   - ' message InnerObject {\n' +
68   - ' string key1 = 1;\n' +
69   - ' bool key2 = 2;\n' +
70   - ' double key3 = 3;\n' +
71   - ' int32 key4 = 4;\n' +
72   - ' string key5 = 5;\n' +
73   - ' }\n' +
74   - '}\n';
75   -
76   - private defaultAttributesSchema =
77   - 'syntax ="proto3";\n' +
78   - 'package attributes;\n' +
79   - '\n' +
80   - 'message SensorConfiguration {\n' +
81   - ' string firmwareVersion = 1;\n' +
82   - ' string serialNumber = 2;\n' +
83   - '}';
84   -
85 59 private requiredValue: boolean;
86 60
87 61 get required(): boolean {
... ... @@ -114,9 +88,9 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
114 88 deviceAttributesTopic: [null, [Validators.required, this.validationMQTTTopic()]],
115 89 deviceTelemetryTopic: [null, [Validators.required, this.validationMQTTTopic()]],
116 90 transportPayloadTypeConfiguration: this.fb.group({
117   - transportPayloadType: [MqttTransportPayloadType.JSON, Validators.required],
118   - deviceTelemetryProtoSchema: [this.defaultTelemetrySchema, Validators.required],
119   - deviceAttributesProtoSchema: [this.defaultAttributesSchema, Validators.required]
  91 + transportPayloadType: [TransportPayloadType.JSON, Validators.required],
  92 + deviceTelemetryProtoSchema: [defaultTelemetrySchema, Validators.required],
  93 + deviceAttributesProtoSchema: [defaultAttributesSchema, Validators.required]
120 94 })
121 95 }, {validator: this.uniqueDeviceTopicValidator}
122 96 );
... ... @@ -140,7 +114,7 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
140 114
141 115 get protoPayloadType(): boolean {
142 116 const transportPayloadType = this.mqttDeviceProfileTransportConfigurationFormGroup.get('transportPayloadTypeConfiguration.transportPayloadType').value;
143   - return transportPayloadType === MqttTransportPayloadType.PROTOBUF;
  117 + return transportPayloadType === TransportPayloadType.PROTOBUF;
144 118 }
145 119
146 120 writeValue(value: MqttDeviceProfileTransportConfiguration | null): void {
... ... @@ -159,16 +133,16 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
159 133 this.propagateChange(configuration);
160 134 }
161 135
162   - private updateTransportPayloadBasedControls(type: MqttTransportPayloadType, forceUpdated = false) {
  136 + private updateTransportPayloadBasedControls(type: TransportPayloadType, forceUpdated = false) {
163 137 const transportPayloadTypeForm = this.mqttDeviceProfileTransportConfigurationFormGroup
164 138 .get('transportPayloadTypeConfiguration') as FormGroup;
165 139 if (forceUpdated) {
166 140 transportPayloadTypeForm.patchValue({
167   - deviceTelemetryProtoSchema: this.defaultTelemetrySchema,
168   - deviceAttributesProtoSchema: this.defaultAttributesSchema
  141 + deviceTelemetryProtoSchema: defaultTelemetrySchema,
  142 + deviceAttributesProtoSchema: defaultAttributesSchema
169 143 }, {emitEvent: false});
170 144 }
171   - if (type === MqttTransportPayloadType.PROTOBUF && !this.disabled) {
  145 + if (type === TransportPayloadType.PROTOBUF && !this.disabled) {
172 146 transportPayloadTypeForm.get('deviceTelemetryProtoSchema').enable({emitEvent: false});
173 147 transportPayloadTypeForm.get('deviceAttributesProtoSchema').enable({emitEvent: false});
174 148 } else {
... ...
  1 +<!--
  2 +
  3 + Copyright © 2016-2021 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<form [formGroup]="coapDeviceTransportConfigurationFormGroup" style="padding-bottom: 16px;">
  19 + <!--tb-json-object-edit
  20 + [required]="required"
  21 + label="{{ 'device-profile.transport-type-coap' | translate }}"
  22 + formControlName="configuration">
  23 + </tb-json-object-edit-->
  24 +</form>
... ...
  1 +///
  2 +/// Copyright © 2016-2021 The Thingsboard Authors
  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 +import { Component, forwardRef, Input, OnInit } from '@angular/core';
  18 +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
  19 +import { Store } from '@ngrx/store';
  20 +import { AppState } from '@app/core/core.state';
  21 +import { coerceBooleanProperty } from '@angular/cdk/coercion';
  22 +import {
  23 + CoapDeviceTransportConfiguration,
  24 + DeviceTransportConfiguration,
  25 + DeviceTransportType
  26 +} from '@shared/models/device.models';
  27 +
  28 +@Component({
  29 + selector: 'tb-coap-device-transport-configuration',
  30 + templateUrl: './coap-device-transport-configuration.component.html',
  31 + styleUrls: [],
  32 + providers: [{
  33 + provide: NG_VALUE_ACCESSOR,
  34 + useExisting: forwardRef(() => CoapDeviceTransportConfigurationComponent),
  35 + multi: true
  36 + }]
  37 +})
  38 +export class CoapDeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit {
  39 +
  40 + coapDeviceTransportConfigurationFormGroup: FormGroup;
  41 +
  42 + private requiredValue: boolean;
  43 + get required(): boolean {
  44 + return this.requiredValue;
  45 + }
  46 + @Input()
  47 + set required(value: boolean) {
  48 + this.requiredValue = coerceBooleanProperty(value);
  49 + }
  50 +
  51 + @Input()
  52 + disabled: boolean;
  53 +
  54 + private propagateChange = (v: any) => { };
  55 +
  56 + constructor(private store: Store<AppState>,
  57 + private fb: FormBuilder) {
  58 + }
  59 +
  60 + registerOnChange(fn: any): void {
  61 + this.propagateChange = fn;
  62 + }
  63 +
  64 + registerOnTouched(fn: any): void {
  65 + }
  66 +
  67 + ngOnInit() {
  68 + this.coapDeviceTransportConfigurationFormGroup = this.fb.group({
  69 + configuration: [null, Validators.required]
  70 + });
  71 + this.coapDeviceTransportConfigurationFormGroup.valueChanges.subscribe(() => {
  72 + this.updateModel();
  73 + });
  74 + }
  75 +
  76 + setDisabledState(isDisabled: boolean): void {
  77 + this.disabled = isDisabled;
  78 + if (this.disabled) {
  79 + this.coapDeviceTransportConfigurationFormGroup.disable({emitEvent: false});
  80 + } else {
  81 + this.coapDeviceTransportConfigurationFormGroup.enable({emitEvent: false});
  82 + }
  83 + }
  84 +
  85 + writeValue(value: CoapDeviceTransportConfiguration | null): void {
  86 + this.coapDeviceTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false});
  87 + }
  88 +
  89 + private updateModel() {
  90 + let configuration: DeviceTransportConfiguration = null;
  91 + if (this.coapDeviceTransportConfigurationFormGroup.valid) {
  92 + configuration = this.coapDeviceTransportConfigurationFormGroup.getRawValue().configuration;
  93 + configuration.type = DeviceTransportType.COAP;
  94 + }
  95 + this.propagateChange(configuration);
  96 + }
  97 +}
... ...
... ... @@ -35,5 +35,11 @@
35 35 formControlName="configuration">
36 36 </tb-lwm2m-device-transport-configuration>
37 37 </ng-template-->
  38 + <ng-template [ngSwitchCase]="deviceTransportType.COAP">
  39 + <tb-coap-device-transport-configuration
  40 + [required]="required"
  41 + formControlName="configuration">
  42 + </tb-coap-device-transport-configuration>
  43 + </ng-template>
38 44 </div>
39 45 </div>
... ...
... ... @@ -31,6 +31,7 @@ import { DefaultDeviceTransportConfigurationComponent } from './data/default-dev
31 31 import { DeviceTransportConfigurationComponent } from './data/device-transport-configuration.component';
32 32 import { MqttDeviceTransportConfigurationComponent } from './data/mqtt-device-transport-configuration.component';
33 33 import { Lwm2mDeviceTransportConfigurationComponent } from './data/lwm2m-device-transport-configuration.component';
  34 +import { CoapDeviceTransportConfigurationComponent } from './data/coap-device-transport-configuration.component';
34 35
35 36 @NgModule({
36 37 declarations: [
... ... @@ -39,6 +40,7 @@ import { Lwm2mDeviceTransportConfigurationComponent } from './data/lwm2m-device-
39 40 DefaultDeviceTransportConfigurationComponent,
40 41 MqttDeviceTransportConfigurationComponent,
41 42 Lwm2mDeviceTransportConfigurationComponent,
  43 + CoapDeviceTransportConfigurationComponent,
42 44 DeviceTransportConfigurationComponent,
43 45 DeviceDataComponent,
44 46 DeviceComponent,
... ...
... ... @@ -36,13 +36,19 @@ export enum DeviceTransportType {
36 36 DEFAULT = 'DEFAULT',
37 37 MQTT = 'MQTT',
38 38 // LWM2M = 'LWM2M'
  39 + COAP = 'COAP'
39 40 }
40 41
41   -export enum MqttTransportPayloadType {
  42 +export enum TransportPayloadType {
42 43 JSON = 'JSON',
43 44 PROTOBUF = 'PROTOBUF'
44 45 }
45 46
  47 +export enum CoapTransportDeviceType {
  48 + DEFAULT = 'DEFAULT',
  49 + EFENTO = 'EFENTO'
  50 +}
  51 +
46 52 export enum DeviceProvisionType {
47 53 DISABLED = 'DISABLED',
48 54 ALLOW_CREATE_NEW_DEVICES = 'ALLOW_CREATE_NEW_DEVICES',
... ... @@ -77,6 +83,7 @@ export const deviceTransportTypeTranslationMap = new Map<DeviceTransportType, st
77 83 [DeviceTransportType.DEFAULT, 'device-profile.transport-type-default'],
78 84 [DeviceTransportType.MQTT, 'device-profile.transport-type-mqtt'],
79 85 // [DeviceTransportType.LWM2M, 'device-profile.transport-type-lwm2m']
  86 + [DeviceTransportType.COAP, 'device-profile.transport-type-coap']
80 87 ]
81 88 );
82 89
... ... @@ -94,13 +101,49 @@ export const deviceTransportTypeHintMap = new Map<DeviceTransportType, string>(
94 101 [DeviceTransportType.DEFAULT, 'device-profile.transport-type-default-hint'],
95 102 [DeviceTransportType.MQTT, 'device-profile.transport-type-mqtt-hint'],
96 103 // [DeviceTransportType.LWM2M, 'device-profile.transport-type-lwm2m-hint']
  104 + [DeviceTransportType.COAP, 'device-profile.transport-type-coap-hint']
97 105 ]
98 106 );
99 107
100   -export const mqttTransportPayloadTypeTranslationMap = new Map<MqttTransportPayloadType, string>(
  108 +export const transportPayloadTypeTranslationMap = new Map<TransportPayloadType, string>(
101 109 [
102   - [MqttTransportPayloadType.JSON, 'device-profile.mqtt-device-payload-type-json'],
103   - [MqttTransportPayloadType.PROTOBUF, 'device-profile.mqtt-device-payload-type-proto']
  110 + [TransportPayloadType.JSON, 'device-profile.transport-device-payload-type-json'],
  111 + [TransportPayloadType.PROTOBUF, 'device-profile.transport-device-payload-type-proto']
  112 + ]
  113 +);
  114 +
  115 +export const defaultTelemetrySchema =
  116 + 'syntax ="proto3";\n' +
  117 + 'package telemetry;\n' +
  118 + '\n' +
  119 + 'message SensorDataReading {\n' +
  120 + '\n' +
  121 + ' double temperature = 1;\n' +
  122 + ' double humidity = 2;\n' +
  123 + ' InnerObject innerObject = 3;\n' +
  124 + '\n' +
  125 + ' message InnerObject {\n' +
  126 + ' string key1 = 1;\n' +
  127 + ' bool key2 = 2;\n' +
  128 + ' double key3 = 3;\n' +
  129 + ' int32 key4 = 4;\n' +
  130 + ' string key5 = 5;\n' +
  131 + ' }\n' +
  132 + '}\n';
  133 +
  134 +export const defaultAttributesSchema =
  135 + 'syntax ="proto3";\n' +
  136 + 'package attributes;\n' +
  137 + '\n' +
  138 + 'message SensorConfiguration {\n' +
  139 + ' string firmwareVersion = 1;\n' +
  140 + ' string serialNumber = 2;\n' +
  141 + '}';
  142 +
  143 +export const coapDeviceTypeTranslationMap = new Map<CoapTransportDeviceType, string>(
  144 + [
  145 + [CoapTransportDeviceType.DEFAULT, 'device-profile.coap-device-type-default'],
  146 + [CoapTransportDeviceType.EFENTO, 'device-profile.coap-device-type-efento']
104 147 ]
105 148 );
106 149
... ... @@ -128,6 +171,13 @@ export const deviceTransportTypeConfigurationInfoMap = new Map<DeviceTransportTy
128 171 hasDeviceConfiguration: false,
129 172 }
130 173 ]*/
  174 + [
  175 + DeviceTransportType.COAP,
  176 + {
  177 + hasProfileConfiguration: true,
  178 + hasDeviceConfiguration: false,
  179 + }
  180 + ]
131 181 ]
132 182 );
133 183
... ... @@ -149,17 +199,28 @@ export interface MqttDeviceProfileTransportConfiguration {
149 199 deviceTelemetryTopic?: string;
150 200 deviceAttributesTopic?: string;
151 201 transportPayloadTypeConfiguration?: {
152   - transportPayloadType?: MqttTransportPayloadType;
  202 + transportPayloadType?: TransportPayloadType;
153 203 };
154 204 [key: string]: any;
155 205 }
156 206
  207 +export interface CoapDeviceProfileTransportConfiguration {
  208 + coapDeviceTypeConfiguration?: {
  209 + coapDeviceType?: CoapTransportDeviceType;
  210 + transportPayloadTypeConfiguration?: {
  211 + transportPayloadType?: TransportPayloadType;
  212 + [key: string]: any;
  213 + };
  214 + };
  215 +}
  216 +
157 217 export interface Lwm2mDeviceProfileTransportConfiguration {
158 218 [key: string]: any;
159 219 }
160 220
161 221 export type DeviceProfileTransportConfigurations = DefaultDeviceProfileTransportConfiguration &
162 222 MqttDeviceProfileTransportConfiguration &
  223 + CoapDeviceProfileTransportConfiguration &
163 224 Lwm2mDeviceProfileTransportConfiguration;
164 225
165 226 export interface DeviceProfileTransportConfiguration extends DeviceProfileTransportConfigurations {
... ... @@ -210,7 +271,7 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT
210 271 const mqttTransportConfiguration: MqttDeviceProfileTransportConfiguration = {
211 272 deviceTelemetryTopic: 'v1/devices/me/telemetry',
212 273 deviceAttributesTopic: 'v1/devices/me/attributes',
213   - transportPayloadTypeConfiguration: {transportPayloadType: MqttTransportPayloadType.JSON}
  274 + transportPayloadTypeConfiguration: {transportPayloadType: TransportPayloadType.JSON}
214 275 };
215 276 transportConfiguration = {...mqttTransportConfiguration, type: DeviceTransportType.MQTT};
216 277 break;
... ... @@ -218,6 +279,12 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT
218 279 const lwm2mTransportConfiguration: Lwm2mDeviceProfileTransportConfiguration = {};
219 280 transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M};
220 281 break;*/
  282 + case DeviceTransportType.COAP:
  283 + const coapTransportConfiguration: CoapDeviceProfileTransportConfiguration = {
  284 + coapDeviceTypeConfiguration: {coapDeviceType: CoapTransportDeviceType.DEFAULT, transportPayloadTypeConfiguration: {transportPayloadType: TransportPayloadType.JSON}}
  285 + };
  286 + transportConfiguration = {...coapTransportConfiguration, type: DeviceTransportType.COAP};
  287 + break;
221 288 }
222 289 }
223 290 return transportConfiguration;
... ... @@ -239,6 +306,10 @@ export function createDeviceTransportConfiguration(type: DeviceTransportType): D
239 306 const lwm2mTransportConfiguration: Lwm2mDeviceTransportConfiguration = {};
240 307 transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M};
241 308 break;*/
  309 + case DeviceTransportType.COAP:
  310 + const coapTransportConfiguration: CoapDeviceTransportConfiguration = {};
  311 + transportConfiguration = {...coapTransportConfiguration, type: DeviceTransportType.COAP};
  312 + break;
242 313 }
243 314 }
244 315 return transportConfiguration;
... ... @@ -399,12 +470,17 @@ export interface MqttDeviceTransportConfiguration {
399 470 [key: string]: any;
400 471 }
401 472
  473 +export interface CoapDeviceTransportConfiguration {
  474 + [key: string]: any;
  475 +}
  476 +
402 477 export interface Lwm2mDeviceTransportConfiguration {
403 478 [key: string]: any;
404 479 }
405 480
406 481 export type DeviceTransportConfigurations = DefaultDeviceTransportConfiguration &
407 482 MqttDeviceTransportConfiguration &
  483 + CoapDeviceTransportConfiguration &
408 484 Lwm2mDeviceTransportConfiguration;
409 485
410 486 export interface DeviceTransportConfiguration extends DeviceTransportConfigurations {
... ...
... ... @@ -967,6 +967,8 @@
967 967 "transport-type-mqtt-hint": "Enables advanced MQTT transport settings",
968 968 "transport-type-lwm2m": "LWM2M",
969 969 "transport-type-lwm2m-hint": "LWM2M transport type",
  970 + "transport-type-coap": "CoAP",
  971 + "transport-type-coap-hint": "Enables advanced CoAP transport settings",
970 972 "description": "Description",
971 973 "default": "Default",
972 974 "profile-configuration": "Profile configuration",
... ... @@ -984,9 +986,14 @@
984 986 "mqtt-device-topic-filters": "MQTT device topic filters",
985 987 "mqtt-device-topic-filters-unique": "MQTT device topic filters need to be unique.",
986 988 "mqtt-device-payload-type": "MQTT device payload",
987   - "mqtt-device-payload-type-json": "JSON",
988   - "mqtt-device-payload-type-proto": "Protobuf",
  989 + "transport-device-payload-type-json": "JSON",
  990 + "transport-device-payload-type-proto": "Protobuf",
989 991 "mqtt-payload-type-required": "Payload type is required.",
  992 + "coap-device-type": "CoAP device type",
  993 + "coap-device-payload-type": "CoAP device payload",
  994 + "coap-device-type-required": "CoAP device type is required.",
  995 + "coap-device-type-default": "Default",
  996 + "coap-device-type-efento": "Efento NB-IoT",
990 997 "support-level-wildcards": "Single <code>[+]</code> and multi-level <code>[#]</code> wildcards supported.",
991 998 "telemetry-topic-filter": "Telemetry topic filter",
992 999 "telemetry-topic-filter-required": "Telemetry topic filter is required.",
... ...