Commit 6b55f3308455dfb7d69a6f60f0310693d6be6778

Authored by Andrew Shvayka
Committed by GitHub
2 parents 3c5bce7d 0ea4723e

Merge pull request #3740 from thingsboard/feature/device-profile-telemetry-proto-schema

Support of Custom Protobuf payloads
Showing 50 changed files with 1324 additions and 225 deletions
@@ -15,7 +15,6 @@ @@ -15,7 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.controller; 16 package org.thingsboard.server.controller;
17 17
18 -import com.datastax.oss.driver.api.core.uuid.Uuids;  
19 import com.fasterxml.jackson.core.type.TypeReference; 18 import com.fasterxml.jackson.core.type.TypeReference;
20 import com.fasterxml.jackson.databind.JsonNode; 19 import com.fasterxml.jackson.databind.JsonNode;
21 import com.fasterxml.jackson.databind.ObjectMapper; 20 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -33,12 +32,7 @@ import org.junit.Rule; @@ -33,12 +32,7 @@ import org.junit.Rule;
33 import org.junit.rules.TestRule; 32 import org.junit.rules.TestRule;
34 import org.junit.rules.TestWatcher; 33 import org.junit.rules.TestWatcher;
35 import org.junit.runner.Description; 34 import org.junit.runner.Description;
36 -import org.junit.runner.RunWith;  
37 import org.springframework.beans.factory.annotation.Autowired; 35 import org.springframework.beans.factory.annotation.Autowired;
38 -import org.springframework.boot.test.context.SpringBootContextLoader;  
39 -import org.springframework.boot.test.context.SpringBootTest;  
40 -import org.springframework.context.annotation.ComponentScan;  
41 -import org.springframework.context.annotation.Configuration;  
42 import org.springframework.http.HttpHeaders; 36 import org.springframework.http.HttpHeaders;
43 import org.springframework.http.MediaType; 37 import org.springframework.http.MediaType;
44 import org.springframework.http.converter.HttpMessageConverter; 38 import org.springframework.http.converter.HttpMessageConverter;
@@ -46,10 +40,6 @@ import org.springframework.http.converter.StringHttpMessageConverter; @@ -46,10 +40,6 @@ import org.springframework.http.converter.StringHttpMessageConverter;
46 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 40 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
47 import org.springframework.mock.http.MockHttpInputMessage; 41 import org.springframework.mock.http.MockHttpInputMessage;
48 import org.springframework.mock.http.MockHttpOutputMessage; 42 import org.springframework.mock.http.MockHttpOutputMessage;
49 -import org.springframework.test.annotation.DirtiesContext;  
50 -import org.springframework.test.context.ActiveProfiles;  
51 -import org.springframework.test.context.ContextConfiguration;  
52 -import org.springframework.test.context.junit4.SpringRunner;  
53 import org.springframework.test.web.servlet.MockMvc; 43 import org.springframework.test.web.servlet.MockMvc;
54 import org.springframework.test.web.servlet.MvcResult; 44 import org.springframework.test.web.servlet.MvcResult;
55 import org.springframework.test.web.servlet.ResultActions; 45 import org.springframework.test.web.servlet.ResultActions;
@@ -58,7 +48,6 @@ import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilde @@ -58,7 +48,6 @@ import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilde
58 import org.springframework.util.LinkedMultiValueMap; 48 import org.springframework.util.LinkedMultiValueMap;
59 import org.springframework.util.MultiValueMap; 49 import org.springframework.util.MultiValueMap;
60 import org.springframework.web.context.WebApplicationContext; 50 import org.springframework.web.context.WebApplicationContext;
61 -import org.thingsboard.server.common.data.BaseData;  
62 import org.thingsboard.server.common.data.Customer; 51 import org.thingsboard.server.common.data.Customer;
63 import org.thingsboard.server.common.data.DeviceProfile; 52 import org.thingsboard.server.common.data.DeviceProfile;
64 import org.thingsboard.server.common.data.DeviceProfileType; 53 import org.thingsboard.server.common.data.DeviceProfileType;
@@ -68,11 +57,13 @@ import org.thingsboard.server.common.data.User; @@ -68,11 +57,13 @@ import org.thingsboard.server.common.data.User;
68 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; 57 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
69 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration; 58 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration;
70 import org.thingsboard.server.common.data.device.profile.DeviceProfileData; 59 import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
71 -import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileCredentials; 60 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  61 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  62 +import org.thingsboard.server.common.data.device.profile.MqttTopics;
  63 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  64 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
72 import org.thingsboard.server.common.data.id.HasId; 65 import org.thingsboard.server.common.data.id.HasId;
73 -import org.thingsboard.server.common.data.id.RuleChainId;  
74 import org.thingsboard.server.common.data.id.TenantId; 66 import org.thingsboard.server.common.data.id.TenantId;
75 -import org.thingsboard.server.common.data.id.UUIDBased;  
76 import org.thingsboard.server.common.data.page.PageLink; 67 import org.thingsboard.server.common.data.page.PageLink;
77 import org.thingsboard.server.common.data.page.TimePageLink; 68 import org.thingsboard.server.common.data.page.TimePageLink;
78 import org.thingsboard.server.common.data.security.Authority; 69 import org.thingsboard.server.common.data.security.Authority;
@@ -330,7 +321,7 @@ public abstract class AbstractWebTest { @@ -330,7 +321,7 @@ public abstract class AbstractWebTest {
330 } 321 }
331 } 322 }
332 323
333 - protected DeviceProfile createDeviceProfile(String name) { 324 + protected DeviceProfile createDeviceProfile(String name, DeviceProfileTransportConfiguration deviceProfileTransportConfiguration) {
334 DeviceProfile deviceProfile = new DeviceProfile(); 325 DeviceProfile deviceProfile = new DeviceProfile();
335 deviceProfile.setName(name); 326 deviceProfile.setName(name);
336 deviceProfile.setType(DeviceProfileType.DEFAULT); 327 deviceProfile.setType(DeviceProfileType.DEFAULT);
@@ -338,15 +329,34 @@ public abstract class AbstractWebTest { @@ -338,15 +329,34 @@ public abstract class AbstractWebTest {
338 deviceProfile.setDescription(name + " Test"); 329 deviceProfile.setDescription(name + " Test");
339 DeviceProfileData deviceProfileData = new DeviceProfileData(); 330 DeviceProfileData deviceProfileData = new DeviceProfileData();
340 DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration(); 331 DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
341 - DefaultDeviceProfileTransportConfiguration transportConfiguration = new DefaultDeviceProfileTransportConfiguration();  
342 deviceProfileData.setConfiguration(configuration); 332 deviceProfileData.setConfiguration(configuration);
343 - deviceProfileData.setTransportConfiguration(transportConfiguration); 333 + if (deviceProfileTransportConfiguration != null) {
  334 + deviceProfileData.setTransportConfiguration(deviceProfileTransportConfiguration);
  335 + } else {
  336 + deviceProfileData.setTransportConfiguration(new DefaultDeviceProfileTransportConfiguration());
  337 + }
344 deviceProfile.setProfileData(deviceProfileData); 338 deviceProfile.setProfileData(deviceProfileData);
345 deviceProfile.setDefault(false); 339 deviceProfile.setDefault(false);
346 deviceProfile.setDefaultRuleChainId(null); 340 deviceProfile.setDefaultRuleChainId(null);
347 return deviceProfile; 341 return deviceProfile;
348 } 342 }
349 343
  344 + protected MqttDeviceProfileTransportConfiguration createMqttDeviceProfileTransportConfiguration(TransportPayloadTypeConfiguration transportPayloadTypeConfiguration) {
  345 + MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = new MqttDeviceProfileTransportConfiguration();
  346 + mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(MqttTopics.DEVICE_TELEMETRY_TOPIC);
  347 + mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
  348 + mqttDeviceProfileTransportConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration);
  349 + return mqttDeviceProfileTransportConfiguration;
  350 + }
  351 +
  352 + protected ProtoTransportPayloadConfiguration createProtoTransportPayloadConfiguration(String deviceAttributesProtoSchema, String deviceTelemetryProtoSchema) {
  353 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = new ProtoTransportPayloadConfiguration();
  354 + protoTransportPayloadConfiguration.setDeviceAttributesProtoSchema(deviceAttributesProtoSchema);
  355 + protoTransportPayloadConfiguration.setDeviceTelemetryProtoSchema(deviceTelemetryProtoSchema);
  356 + return protoTransportPayloadConfiguration;
  357 + }
  358 +
  359 +
350 protected ResultActions doGet(String urlTemplate, Object... urlVariables) throws Exception { 360 protected ResultActions doGet(String urlTemplate, Object... urlVariables) throws Exception {
351 MockHttpServletRequestBuilder getRequest = get(urlTemplate, urlVariables); 361 MockHttpServletRequestBuilder getRequest = get(urlTemplate, urlVariables);
352 setJwtToken(getRequest); 362 setJwtToken(getRequest);
@@ -16,6 +16,12 @@ @@ -16,6 +16,12 @@
16 package org.thingsboard.server.controller; 16 package org.thingsboard.server.controller;
17 17
18 import com.fasterxml.jackson.core.type.TypeReference; 18 import com.fasterxml.jackson.core.type.TypeReference;
  19 +import com.github.os72.protobuf.dynamic.DynamicSchema;
  20 +import com.google.protobuf.Descriptors;
  21 +import com.google.protobuf.DynamicMessage;
  22 +import com.google.protobuf.InvalidProtocolBufferException;
  23 +import com.google.protobuf.util.JsonFormat;
  24 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
19 import org.junit.After; 25 import org.junit.After;
20 import org.junit.Assert; 26 import org.junit.Assert;
21 import org.junit.Before; 27 import org.junit.Before;
@@ -28,7 +34,10 @@ import org.thingsboard.server.common.data.DeviceProfileType; @@ -28,7 +34,10 @@ import org.thingsboard.server.common.data.DeviceProfileType;
28 import org.thingsboard.server.common.data.DeviceTransportType; 34 import org.thingsboard.server.common.data.DeviceTransportType;
29 import org.thingsboard.server.common.data.Tenant; 35 import org.thingsboard.server.common.data.Tenant;
30 import org.thingsboard.server.common.data.User; 36 import org.thingsboard.server.common.data.User;
31 -import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileCredentials; 37 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  38 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  39 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  40 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
32 import org.thingsboard.server.common.data.page.PageData; 41 import org.thingsboard.server.common.data.page.PageData;
33 import org.thingsboard.server.common.data.page.PageLink; 42 import org.thingsboard.server.common.data.page.PageLink;
34 import org.thingsboard.server.common.data.security.Authority; 43 import org.thingsboard.server.common.data.security.Authority;
@@ -36,9 +45,13 @@ import org.thingsboard.server.common.data.security.Authority; @@ -36,9 +45,13 @@ import org.thingsboard.server.common.data.security.Authority;
36 import java.util.ArrayList; 45 import java.util.ArrayList;
37 import java.util.Collections; 46 import java.util.Collections;
38 import java.util.List; 47 import java.util.List;
  48 +import java.util.Set;
39 import java.util.stream.Collectors; 49 import java.util.stream.Collectors;
40 50
41 import static org.hamcrest.Matchers.containsString; 51 import static org.hamcrest.Matchers.containsString;
  52 +import static org.junit.Assert.assertEquals;
  53 +import static org.junit.Assert.assertNotNull;
  54 +import static org.junit.Assert.assertTrue;
42 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 55 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
43 56
44 public abstract class BaseDeviceProfileControllerTest extends AbstractControllerTest { 57 public abstract class BaseDeviceProfileControllerTest extends AbstractControllerTest {
@@ -78,7 +91,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -78,7 +91,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
78 91
79 @Test 92 @Test
80 public void testSaveDeviceProfile() throws Exception { 93 public void testSaveDeviceProfile() throws Exception {
81 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 94 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
82 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 95 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
83 Assert.assertNotNull(savedDeviceProfile); 96 Assert.assertNotNull(savedDeviceProfile);
84 Assert.assertNotNull(savedDeviceProfile.getId()); 97 Assert.assertNotNull(savedDeviceProfile.getId());
@@ -96,7 +109,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -96,7 +109,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
96 109
97 @Test 110 @Test
98 public void testFindDeviceProfileById() throws Exception { 111 public void testFindDeviceProfileById() throws Exception {
99 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 112 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
100 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 113 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
101 DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString(), DeviceProfile.class); 114 DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString(), DeviceProfile.class);
102 Assert.assertNotNull(foundDeviceProfile); 115 Assert.assertNotNull(foundDeviceProfile);
@@ -105,7 +118,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -105,7 +118,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
105 118
106 @Test 119 @Test
107 public void testFindDeviceProfileInfoById() throws Exception { 120 public void testFindDeviceProfileInfoById() throws Exception {
108 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 121 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
109 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 122 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
110 DeviceProfileInfo foundDeviceProfileInfo = doGet("/api/deviceProfileInfo/"+savedDeviceProfile.getId().getId().toString(), DeviceProfileInfo.class); 123 DeviceProfileInfo foundDeviceProfileInfo = doGet("/api/deviceProfileInfo/"+savedDeviceProfile.getId().getId().toString(), DeviceProfileInfo.class);
111 Assert.assertNotNull(foundDeviceProfileInfo); 124 Assert.assertNotNull(foundDeviceProfileInfo);
@@ -127,7 +140,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -127,7 +140,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
127 140
128 @Test 141 @Test
129 public void testSetDefaultDeviceProfile() throws Exception { 142 public void testSetDefaultDeviceProfile() throws Exception {
130 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile 1"); 143 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile 1", null);
131 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 144 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
132 DeviceProfile defaultDeviceProfile = doPost("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString()+"/default", null, DeviceProfile.class); 145 DeviceProfile defaultDeviceProfile = doPost("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString()+"/default", null, DeviceProfile.class);
133 Assert.assertNotNull(defaultDeviceProfile); 146 Assert.assertNotNull(defaultDeviceProfile);
@@ -147,19 +160,19 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -147,19 +160,19 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
147 160
148 @Test 161 @Test
149 public void testSaveDeviceProfileWithSameName() throws Exception { 162 public void testSaveDeviceProfileWithSameName() throws Exception {
150 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 163 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
151 doPost("/api/deviceProfile", deviceProfile).andExpect(status().isOk()); 164 doPost("/api/deviceProfile", deviceProfile).andExpect(status().isOk());
152 - DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile"); 165 + DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile", null);
153 doPost("/api/deviceProfile", deviceProfile2).andExpect(status().isBadRequest()) 166 doPost("/api/deviceProfile", deviceProfile2).andExpect(status().isBadRequest())
154 .andExpect(statusReason(containsString("Device profile with such name already exists"))); 167 .andExpect(statusReason(containsString("Device profile with such name already exists")));
155 } 168 }
156 169
157 @Test 170 @Test
158 public void testSaveDeviceProfileWithSameProvisionDeviceKey() throws Exception { 171 public void testSaveDeviceProfileWithSameProvisionDeviceKey() throws Exception {
159 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 172 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
160 deviceProfile.setProvisionDeviceKey("testProvisionDeviceKey"); 173 deviceProfile.setProvisionDeviceKey("testProvisionDeviceKey");
161 doPost("/api/deviceProfile", deviceProfile).andExpect(status().isOk()); 174 doPost("/api/deviceProfile", deviceProfile).andExpect(status().isOk());
162 - DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile 2"); 175 + DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile 2", null);
163 deviceProfile2.setProvisionDeviceKey("testProvisionDeviceKey"); 176 deviceProfile2.setProvisionDeviceKey("testProvisionDeviceKey");
164 doPost("/api/deviceProfile", deviceProfile2).andExpect(status().isBadRequest()) 177 doPost("/api/deviceProfile", deviceProfile2).andExpect(status().isBadRequest())
165 .andExpect(statusReason(containsString("Device profile with such provision device key already exists"))); 178 .andExpect(statusReason(containsString("Device profile with such provision device key already exists")));
@@ -168,7 +181,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -168,7 +181,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
168 @Ignore 181 @Ignore
169 @Test 182 @Test
170 public void testChangeDeviceProfileTypeWithExistingDevices() throws Exception { 183 public void testChangeDeviceProfileTypeWithExistingDevices() throws Exception {
171 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 184 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
172 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 185 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
173 Device device = new Device(); 186 Device device = new Device();
174 device.setName("Test device"); 187 device.setName("Test device");
@@ -183,7 +196,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -183,7 +196,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
183 196
184 @Test 197 @Test
185 public void testChangeDeviceProfileTransportTypeWithExistingDevices() throws Exception { 198 public void testChangeDeviceProfileTransportTypeWithExistingDevices() throws Exception {
186 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 199 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
187 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 200 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
188 Device device = new Device(); 201 Device device = new Device();
189 device.setName("Test device"); 202 device.setName("Test device");
@@ -197,7 +210,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -197,7 +210,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
197 210
198 @Test 211 @Test
199 public void testDeleteDeviceProfileWithExistingDevice() throws Exception { 212 public void testDeleteDeviceProfileWithExistingDevice() throws Exception {
200 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 213 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
201 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 214 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
202 215
203 Device device = new Device(); 216 Device device = new Device();
@@ -214,7 +227,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -214,7 +227,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
214 227
215 @Test 228 @Test
216 public void testDeleteDeviceProfile() throws Exception { 229 public void testDeleteDeviceProfile() throws Exception {
217 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 230 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
218 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 231 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
219 232
220 doDelete("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString()) 233 doDelete("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString())
@@ -235,7 +248,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -235,7 +248,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
235 deviceProfiles.addAll(pageData.getData()); 248 deviceProfiles.addAll(pageData.getData());
236 249
237 for (int i=0;i<28;i++) { 250 for (int i=0;i<28;i++) {
238 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i); 251 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i, null);
239 deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class)); 252 deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class));
240 } 253 }
241 254
@@ -280,7 +293,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -280,7 +293,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
280 deviceProfiles.addAll(deviceProfilePageData.getData()); 293 deviceProfiles.addAll(deviceProfilePageData.getData());
281 294
282 for (int i=0;i<28;i++) { 295 for (int i=0;i<28;i++) {
283 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i); 296 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i, null);
284 deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class)); 297 deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class));
285 } 298 }
286 299
@@ -318,4 +331,341 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -318,4 +331,341 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
318 Assert.assertEquals(1, pageData.getTotalElements()); 331 Assert.assertEquals(1, pageData.getTotalElements());
319 } 332 }
320 333
  334 + @Test
  335 + public void testSaveProtoDeviceProfileWithInvalidProtoFile() throws Exception {
  336 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  337 + "\n" +
  338 + "package schemavalidation;\n" +
  339 + "\n" +
  340 + "message SchemaValidationTest {\n" +
  341 + " required int32 parameter = 1;\n" +
  342 + "}", "[Transport Configuration] failed to parse attributes proto schema due to: Syntax error in :6:4: 'required' label forbidden in proto3 field declarations");
  343 + }
  344 +
  345 + @Test
  346 + public void testSaveProtoDeviceProfileWithInvalidProtoSyntax() throws Exception {
  347 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto2\";\n" +
  348 + "\n" +
  349 + "package schemavalidation;\n" +
  350 + "\n" +
  351 + "message SchemaValidationTest {\n" +
  352 + " required int32 parameter = 1;\n" +
  353 + "}", "[Transport Configuration] invalid schema syntax: proto2 for attributes proto schema provided! Only proto3 allowed!");
  354 + }
  355 +
  356 + @Test
  357 + public void testSaveProtoDeviceProfileOptionsNotSupported() throws Exception {
  358 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  359 + "\n" +
  360 + "option java_package = \"com.test.schemavalidation\";\n" +
  361 + "option java_multiple_files = true;\n" +
  362 + "\n" +
  363 + "package schemavalidation;\n" +
  364 + "\n" +
  365 + "message SchemaValidationTest {\n" +
  366 + " int32 parameter = 1;\n" +
  367 + "}", "[Transport Configuration] invalid attributes proto schema provided! Schema options don't support!");
  368 + }
  369 +
  370 + @Test
  371 + public void testSaveProtoDeviceProfilePublicImportsNotSupported() throws Exception {
  372 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  373 + "\n" +
  374 + "import public \"oldschema.proto\";\n" +
  375 + "\n" +
  376 + "package schemavalidation;\n" +
  377 + "\n" +
  378 + "message SchemaValidationTest {\n" +
  379 + " int32 parameter = 1;\n" +
  380 + "}", "[Transport Configuration] invalid attributes proto schema provided! Schema public imports don't support!");
  381 + }
  382 +
  383 + @Test
  384 + public void testSaveProtoDeviceProfileImportsNotSupported() throws Exception {
  385 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  386 + "\n" +
  387 + "import \"oldschema.proto\";\n" +
  388 + "\n" +
  389 + "package schemavalidation;\n" +
  390 + "\n" +
  391 + "message SchemaValidationTest {\n" +
  392 + " int32 parameter = 1;\n" +
  393 + "}", "[Transport Configuration] invalid attributes proto schema provided! Schema imports don't support!");
  394 + }
  395 +
  396 + @Test
  397 + public void testSaveProtoDeviceProfileExtendDeclarationsNotSupported() throws Exception {
  398 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  399 + "\n" +
  400 + "package schemavalidation;\n" +
  401 + "\n" +
  402 + "extend google.protobuf.MethodOptions {\n" +
  403 + " MyMessage my_method_option = 50007;\n" +
  404 + "}", "[Transport Configuration] invalid attributes proto schema provided! Schema extend declarations don't support!");
  405 + }
  406 +
  407 + @Test
  408 + public void testSaveProtoDeviceProfileEnumOptionsNotSupported() throws Exception {
  409 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  410 + "\n" +
  411 + "package schemavalidation;\n" +
  412 + "\n" +
  413 + "enum testEnum {\n" +
  414 + " option allow_alias = true;\n" +
  415 + " DEFAULT = 0;\n" +
  416 + " STARTED = 1;\n" +
  417 + " RUNNING = 2;\n" +
  418 + "}\n" +
  419 + "\n" +
  420 + "message testMessage {\n" +
  421 + " int32 parameter = 1;\n" +
  422 + "}", "[Transport Configuration] invalid attributes proto schema provided! Enum definitions options are not supported!");
  423 + }
  424 +
  425 + @Test
  426 + public void testSaveProtoDeviceProfileNoOneMessageTypeExists() throws Exception {
  427 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  428 + "\n" +
  429 + "package schemavalidation;\n" +
  430 + "\n" +
  431 + "enum testEnum {\n" +
  432 + " DEFAULT = 0;\n" +
  433 + " STARTED = 1;\n" +
  434 + " RUNNING = 2;\n" +
  435 + "}", "[Transport Configuration] invalid attributes proto schema provided! At least one Message definition should exists!");
  436 + }
  437 +
  438 + @Test
  439 + public void testSaveProtoDeviceProfileMessageTypeOptionsNotSupported() throws Exception {
  440 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  441 + "\n" +
  442 + "package schemavalidation;\n" +
  443 + "\n" +
  444 + "message testMessage {\n" +
  445 + " option allow_alias = true;\n" +
  446 + " int32 parameter = 1;\n" +
  447 + "}", "[Transport Configuration] invalid attributes proto schema provided! Message definition options don't support!");
  448 + }
  449 +
  450 + @Test
  451 + public void testSaveProtoDeviceProfileMessageTypeExtensionsNotSupported() throws Exception {
  452 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  453 + "\n" +
  454 + "package schemavalidation;\n" +
  455 + "\n" +
  456 + "message TestMessage {\n" +
  457 + " extensions 100 to 199;\n" +
  458 + "}", "[Transport Configuration] invalid attributes proto schema provided! Message definition extensions don't support!");
  459 + }
  460 +
  461 + @Test
  462 + public void testSaveProtoDeviceProfileMessageTypeReservedElementsNotSupported() throws Exception {
  463 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  464 + "\n" +
  465 + "package schemavalidation;\n" +
  466 + "\n" +
  467 + "message Foo {\n" +
  468 + " reserved 2, 15, 9 to 11;\n" +
  469 + " reserved \"foo\", \"bar\";\n" +
  470 + "}", "[Transport Configuration] invalid attributes proto schema provided! Message definition reserved elements don't support!");
  471 + }
  472 +
  473 + @Test
  474 + public void testSaveProtoDeviceProfileMessageTypeGroupsElementsNotSupported() throws Exception {
  475 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  476 + "\n" +
  477 + "package schemavalidation;\n" +
  478 + "\n" +
  479 + "message TestMessage {\n" +
  480 + " repeated group Result = 1 {\n" +
  481 + " string url = 2;\n" +
  482 + " string title = 3;\n" +
  483 + " repeated string snippets = 4;\n" +
  484 + " }\n" +
  485 + "}", "[Transport Configuration] invalid attributes proto schema provided! Message definition groups don't support!");
  486 + }
  487 +
  488 + @Test
  489 + public void testSaveProtoDeviceProfileOneOfsGroupsElementsNotSupported() throws Exception {
  490 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  491 + "\n" +
  492 + "package schemavalidation;\n" +
  493 + "\n" +
  494 + "message SampleMessage {\n" +
  495 + " oneof test_oneof {\n" +
  496 + " string name = 1;\n" +
  497 + " group Result = 2 {\n" +
  498 + " \tstring url = 3;\n" +
  499 + " \tstring title = 4;\n" +
  500 + " \trepeated string snippets = 5;\n" +
  501 + " }\n" +
  502 + " }" +
  503 + "}", "[Transport Configuration] invalid attributes proto schema provided! OneOf definition groups don't support!");
  504 + }
  505 +
  506 + @Test
  507 + public void testSaveProtoDeviceProfileWithMessageNestedTypes() throws Exception {
  508 + String schema = "syntax = \"proto3\";\n" +
  509 + "\n" +
  510 + "package testnested;\n" +
  511 + "\n" +
  512 + "message Outer {\n" +
  513 + " message MiddleAA {\n" +
  514 + " message Inner {\n" +
  515 + " int64 ival = 1;\n" +
  516 + " bool booly = 2;\n" +
  517 + " }\n" +
  518 + " Inner inner = 1;\n" +
  519 + " }\n" +
  520 + " message MiddleBB {\n" +
  521 + " message Inner {\n" +
  522 + " int32 ival = 1;\n" +
  523 + " bool booly = 2;\n" +
  524 + " }\n" +
  525 + " Inner inner = 1;\n" +
  526 + " }\n" +
  527 + " MiddleAA middleAA = 1;\n" +
  528 + " MiddleBB middleBB = 2;\n" +
  529 + "}";
  530 + DynamicSchema dynamicSchema = getDynamicSchema(schema);
  531 + assertNotNull(dynamicSchema);
  532 + Set<String> messageTypes = dynamicSchema.getMessageTypes();
  533 + assertEquals(5, messageTypes.size());
  534 + assertTrue(messageTypes.contains("testnested.Outer"));
  535 + assertTrue(messageTypes.contains("testnested.Outer.MiddleAA"));
  536 + assertTrue(messageTypes.contains("testnested.Outer.MiddleAA.Inner"));
  537 + assertTrue(messageTypes.contains("testnested.Outer.MiddleBB"));
  538 + assertTrue(messageTypes.contains("testnested.Outer.MiddleBB.Inner"));
  539 +
  540 + DynamicMessage.Builder middleAAInnerMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer.MiddleAA.Inner");
  541 + Descriptors.Descriptor middleAAInnerMsgDescriptor = middleAAInnerMsgBuilder.getDescriptorForType();
  542 + DynamicMessage middleAAInnerMsg = middleAAInnerMsgBuilder
  543 + .setField(middleAAInnerMsgDescriptor.findFieldByName("ival"), 1L)
  544 + .setField(middleAAInnerMsgDescriptor.findFieldByName("booly"), true)
  545 + .build();
  546 +
  547 + DynamicMessage.Builder middleAAMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer.MiddleAA");
  548 + Descriptors.Descriptor middleAAMsgDescriptor = middleAAMsgBuilder.getDescriptorForType();
  549 + DynamicMessage middleAAMsg = middleAAMsgBuilder
  550 + .setField(middleAAMsgDescriptor.findFieldByName("inner"), middleAAInnerMsg)
  551 + .build();
  552 +
  553 + DynamicMessage.Builder middleBBInnerMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer.MiddleAA.Inner");
  554 + Descriptors.Descriptor middleBBInnerMsgDescriptor = middleBBInnerMsgBuilder.getDescriptorForType();
  555 + DynamicMessage middleBBInnerMsg = middleBBInnerMsgBuilder
  556 + .setField(middleBBInnerMsgDescriptor.findFieldByName("ival"), 0L)
  557 + .setField(middleBBInnerMsgDescriptor.findFieldByName("booly"), false)
  558 + .build();
  559 +
  560 + DynamicMessage.Builder middleBBMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer.MiddleBB");
  561 + Descriptors.Descriptor middleBBMsgDescriptor = middleBBMsgBuilder.getDescriptorForType();
  562 + DynamicMessage middleBBMsg = middleBBMsgBuilder
  563 + .setField(middleBBMsgDescriptor.findFieldByName("inner"), middleBBInnerMsg)
  564 + .build();
  565 +
  566 +
  567 + DynamicMessage.Builder outerMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer");
  568 + Descriptors.Descriptor outerMsgBuilderDescriptor = outerMsgBuilder.getDescriptorForType();
  569 + DynamicMessage outerMsg = outerMsgBuilder
  570 + .setField(outerMsgBuilderDescriptor.findFieldByName("middleAA"), middleAAMsg)
  571 + .setField(outerMsgBuilderDescriptor.findFieldByName("middleBB"), middleBBMsg)
  572 + .build();
  573 +
  574 + assertEquals("{\n" +
  575 + " \"middleAA\": {\n" +
  576 + " \"inner\": {\n" +
  577 + " \"ival\": \"1\",\n" +
  578 + " \"booly\": true\n" +
  579 + " }\n" +
  580 + " },\n" +
  581 + " \"middleBB\": {\n" +
  582 + " \"inner\": {\n" +
  583 + " \"ival\": 0,\n" +
  584 + " \"booly\": false\n" +
  585 + " }\n" +
  586 + " }\n" +
  587 + "}", dynamicMsgToJson(outerMsgBuilderDescriptor, outerMsg.toByteArray()));
  588 + }
  589 +
  590 + @Test
  591 + public void testSaveProtoDeviceProfileWithMessageOneOfs() throws Exception {
  592 + String schema = "syntax = \"proto3\";\n" +
  593 + "\n" +
  594 + "package testoneofs;\n" +
  595 + "\n" +
  596 + "message SubMessage {\n" +
  597 + " repeated string name = 1;\n" +
  598 + "}\n" +
  599 + "\n" +
  600 + "message SampleMessage {\n" +
  601 + " oneof testOneOf {\n" +
  602 + " string name = 4;\n" +
  603 + " SubMessage subMessage = 9;\n" +
  604 + " }\n" +
  605 + "}";
  606 + DynamicSchema dynamicSchema = getDynamicSchema(schema);
  607 + assertNotNull(dynamicSchema);
  608 + Set<String> messageTypes = dynamicSchema.getMessageTypes();
  609 + assertEquals(2, messageTypes.size());
  610 + assertTrue(messageTypes.contains("testoneofs.SubMessage"));
  611 + assertTrue(messageTypes.contains("testoneofs.SampleMessage"));
  612 +
  613 + DynamicMessage.Builder sampleMsgBuilder = dynamicSchema.newMessageBuilder("testoneofs.SampleMessage");
  614 + Descriptors.Descriptor sampleMsgDescriptor = sampleMsgBuilder.getDescriptorForType();
  615 + assertNotNull(sampleMsgDescriptor);
  616 +
  617 + List<Descriptors.FieldDescriptor> fields = sampleMsgDescriptor.getFields();
  618 + assertEquals(2, fields.size());
  619 + DynamicMessage sampleMsg = sampleMsgBuilder
  620 + .setField(sampleMsgDescriptor.findFieldByName("name"), "Bob")
  621 + .build();
  622 + assertEquals("{\n" + " \"name\": \"Bob\"\n" + "}", dynamicMsgToJson(sampleMsgDescriptor, sampleMsg.toByteArray()));
  623 +
  624 + DynamicMessage.Builder subMsgBuilder = dynamicSchema.newMessageBuilder("testoneofs.SubMessage");
  625 + Descriptors.Descriptor subMsgDescriptor = subMsgBuilder.getDescriptorForType();
  626 + DynamicMessage subMsg = subMsgBuilder
  627 + .addRepeatedField(subMsgDescriptor.findFieldByName("name"), "Alice")
  628 + .addRepeatedField(subMsgDescriptor.findFieldByName("name"), "John")
  629 + .build();
  630 +
  631 + DynamicMessage sampleMsgWithOneOfSubMessage = sampleMsgBuilder.setField(sampleMsgDescriptor.findFieldByName("subMessage"), subMsg).build();
  632 + assertEquals("{\n" + " \"subMessage\": {\n" + " \"name\": [\"Alice\", \"John\"]\n" + " }\n" + "}",
  633 + dynamicMsgToJson(sampleMsgDescriptor, sampleMsgWithOneOfSubMessage.toByteArray()));
  634 + }
  635 +
  636 + private DeviceProfile testSaveDeviceProfileWithProtoPayloadType(String schema) throws Exception {
  637 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema);
  638 + MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration);
  639 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration);
  640 + DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
  641 + DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString(), DeviceProfile.class);
  642 + Assert.assertEquals(savedDeviceProfile.getName(), foundDeviceProfile.getName());
  643 + return savedDeviceProfile;
  644 + }
  645 +
  646 + private void testSaveDeviceProfileWithInvalidProtoSchema(String schema, String errorMsg) throws Exception {
  647 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema);
  648 + MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration);
  649 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration);
  650 + doPost("/api/deviceProfile", deviceProfile).andExpect(status().isBadRequest())
  651 + .andExpect(statusReason(containsString(errorMsg)));
  652 + }
  653 +
  654 + private DynamicSchema getDynamicSchema(String schema) throws Exception {
  655 + DeviceProfile deviceProfile = testSaveDeviceProfileWithProtoPayloadType(schema);
  656 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  657 + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
  658 + MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
  659 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttDeviceProfileTransportConfiguration.getTransportPayloadTypeConfiguration();
  660 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  661 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  662 + ProtoFileElement protoFile = protoTransportPayloadConfiguration.getTransportProtoSchema(schema);
  663 + return protoTransportPayloadConfiguration.getDynamicSchema(protoFile, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA);
  664 + }
  665 +
  666 + private String dynamicMsgToJson(Descriptors.Descriptor descriptor, byte[] payload) throws InvalidProtocolBufferException {
  667 + DynamicMessage dynamicMessage = DynamicMessage.parseFrom(descriptor, payload);
  668 + return JsonFormat.printer().includingDefaultValueFields().print(dynamicMessage);
  669 + }
  670 +
321 } 671 }
@@ -38,7 +38,10 @@ import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileCon @@ -38,7 +38,10 @@ import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileCon
38 import org.thingsboard.server.common.data.device.profile.DeviceProfileData; 38 import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
39 import org.thingsboard.server.common.data.device.profile.DeviceProfileProvisionConfiguration; 39 import org.thingsboard.server.common.data.device.profile.DeviceProfileProvisionConfiguration;
40 import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration; 40 import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration;
  41 +import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration;
41 import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; 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;
42 import org.thingsboard.server.common.data.security.Authority; 45 import org.thingsboard.server.common.data.security.Authority;
43 import org.thingsboard.server.common.data.security.DeviceCredentials; 46 import org.thingsboard.server.common.data.security.DeviceCredentials;
44 import org.thingsboard.server.controller.AbstractControllerTest; 47 import org.thingsboard.server.controller.AbstractControllerTest;
@@ -47,7 +50,6 @@ import org.thingsboard.server.gen.transport.TransportProtos; @@ -47,7 +50,6 @@ import org.thingsboard.server.gen.transport.TransportProtos;
47 import java.util.ArrayList; 50 import java.util.ArrayList;
48 import java.util.List; 51 import java.util.List;
49 import java.util.concurrent.atomic.AtomicInteger; 52 import java.util.concurrent.atomic.AtomicInteger;
50 -import java.util.function.Supplier;  
51 53
52 import static org.junit.Assert.assertEquals; 54 import static org.junit.Assert.assertEquals;
53 import static org.junit.Assert.assertNotNull; 55 import static org.junit.Assert.assertNotNull;
@@ -60,6 +62,48 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest @@ -60,6 +62,48 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
60 62
61 private static final AtomicInteger atomicInteger = new AtomicInteger(2); 63 private static final AtomicInteger atomicInteger = new AtomicInteger(2);
62 64
  65 + public static final String DEVICE_TELEMETRY_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
  66 + "\n" +
  67 + "package test;\n" +
  68 + "\n" +
  69 + "message PostTelemetry {\n" +
  70 + " string key1 = 1;\n" +
  71 + " bool key2 = 2;\n" +
  72 + " double key3 = 3;\n" +
  73 + " int32 key4 = 4;\n" +
  74 + " JsonObject key5 = 5;\n" +
  75 + "\n" +
  76 + " message JsonObject {\n" +
  77 + " int32 someNumber = 6;\n" +
  78 + " repeated int32 someArray = 7;\n" +
  79 + " NestedJsonObject someNestedObject = 8;\n" +
  80 + " message NestedJsonObject {\n" +
  81 + " string key = 9;\n" +
  82 + " }\n" +
  83 + " }\n" +
  84 + "}";
  85 +
  86 + public static final String DEVICE_ATTRIBUTES_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
  87 + "\n" +
  88 + "package test;\n" +
  89 + "\n" +
  90 + "message PostAttributes {\n" +
  91 + " string key1 = 1;\n" +
  92 + " bool key2 = 2;\n" +
  93 + " double key3 = 3;\n" +
  94 + " int32 key4 = 4;\n" +
  95 + " JsonObject key5 = 5;\n" +
  96 + "\n" +
  97 + " message JsonObject {\n" +
  98 + " int32 someNumber = 6;\n" +
  99 + " repeated int32 someArray = 7;\n" +
  100 + " NestedJsonObject someNestedObject = 8;\n" +
  101 + " message NestedJsonObject {\n" +
  102 + " string key = 9;\n" +
  103 + " }\n" +
  104 + " }\n" +
  105 + "}";
  106 +
63 protected Tenant savedTenant; 107 protected Tenant savedTenant;
64 protected User tenantAdmin; 108 protected User tenantAdmin;
65 109
@@ -69,8 +113,10 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest @@ -69,8 +113,10 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
69 protected Device savedGateway; 113 protected Device savedGateway;
70 protected String gatewayAccessToken; 114 protected String gatewayAccessToken;
71 115
  116 + protected DeviceProfile deviceProfile;
  117 +
72 protected void processBeforeTest (String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception { 118 protected void processBeforeTest (String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception {
73 - this.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic, DeviceProfileProvisionType.DISABLED, null, null); 119 + this.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic, null, null, DeviceProfileProvisionType.DISABLED, null, null);
74 } 120 }
75 121
76 protected void processBeforeTest(String deviceName, 122 protected void processBeforeTest(String deviceName,
@@ -78,6 +124,8 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest @@ -78,6 +124,8 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
78 TransportPayloadType payloadType, 124 TransportPayloadType payloadType,
79 String telemetryTopic, 125 String telemetryTopic,
80 String attributesTopic, 126 String attributesTopic,
  127 + String telemetryProtoSchema,
  128 + String attributesProtoSchema,
81 DeviceProfileProvisionType provisionType, 129 DeviceProfileProvisionType provisionType,
82 String provisionKey, String provisionSecret 130 String provisionKey, String provisionSecret
83 ) throws Exception { 131 ) throws Exception {
@@ -109,12 +157,12 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest @@ -109,12 +157,12 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
109 gateway.setAdditionalInfo(additionalInfo); 157 gateway.setAdditionalInfo(additionalInfo);
110 158
111 if (payloadType != null) { 159 if (payloadType != null) {
112 - DeviceProfile mqttDeviceProfile = createMqttDeviceProfile(payloadType, telemetryTopic, attributesTopic, provisionType, provisionKey, provisionSecret);  
113 - DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", mqttDeviceProfile, DeviceProfile.class);  
114 - device.setType(savedDeviceProfile.getName());  
115 - device.setDeviceProfileId(savedDeviceProfile.getId());  
116 - gateway.setType(savedDeviceProfile.getName());  
117 - gateway.setDeviceProfileId(savedDeviceProfile.getId()); 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());
118 } 166 }
119 167
120 savedDevice = doPost("/api/device", device, Device.class); 168 savedDevice = doPost("/api/device", device, Device.class);
@@ -201,9 +249,9 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest @@ -201,9 +249,9 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
201 249
202 protected DeviceProfile createMqttDeviceProfile(TransportPayloadType transportPayloadType, 250 protected DeviceProfile createMqttDeviceProfile(TransportPayloadType transportPayloadType,
203 String telemetryTopic, String attributesTopic, 251 String telemetryTopic, String attributesTopic,
  252 + String telemetryProtoSchema, String attributesProtoSchema,
204 DeviceProfileProvisionType provisionType, 253 DeviceProfileProvisionType provisionType,
205 - String provisionKey, String provisionSecret  
206 - ) { 254 + String provisionKey, String provisionSecret) {
207 DeviceProfile deviceProfile = new DeviceProfile(); 255 DeviceProfile deviceProfile = new DeviceProfile();
208 deviceProfile.setName(transportPayloadType.name()); 256 deviceProfile.setName(transportPayloadType.name());
209 deviceProfile.setType(DeviceProfileType.DEFAULT); 257 deviceProfile.setType(DeviceProfileType.DEFAULT);
@@ -213,15 +261,30 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest @@ -213,15 +261,30 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
213 deviceProfile.setDescription(transportPayloadType.name() + " Test"); 261 deviceProfile.setDescription(transportPayloadType.name() + " Test");
214 DeviceProfileData deviceProfileData = new DeviceProfileData(); 262 DeviceProfileData deviceProfileData = new DeviceProfileData();
215 DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration(); 263 DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
216 - MqttDeviceProfileTransportConfiguration transportConfiguration = new MqttDeviceProfileTransportConfiguration();  
217 - transportConfiguration.setTransportPayloadType(transportPayloadType); 264 + MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = new MqttDeviceProfileTransportConfiguration();
218 if (!StringUtils.isEmpty(telemetryTopic)) { 265 if (!StringUtils.isEmpty(telemetryTopic)) {
219 - transportConfiguration.setDeviceTelemetryTopic(telemetryTopic); 266 + mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(telemetryTopic);
220 } 267 }
221 if (!StringUtils.isEmpty(attributesTopic)) { 268 if (!StringUtils.isEmpty(attributesTopic)) {
222 - transportConfiguration.setDeviceAttributesTopic(attributesTopic); 269 + mqttDeviceProfileTransportConfiguration.setDeviceAttributesTopic(attributesTopic);
223 } 270 }
224 - deviceProfileData.setTransportConfiguration(transportConfiguration); 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);
225 DeviceProfileProvisionConfiguration provisionConfiguration; 288 DeviceProfileProvisionConfiguration provisionConfiguration;
226 switch (provisionType) { 289 switch (provisionType) {
227 case ALLOW_CREATE_NEW_DEVICES: 290 case ALLOW_CREATE_NEW_DEVICES:
@@ -233,6 +296,7 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest @@ -233,6 +296,7 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
233 case DISABLED: 296 case DISABLED:
234 default: 297 default:
235 provisionConfiguration = new DisabledDeviceProfileProvisionConfiguration(provisionSecret); 298 provisionConfiguration = new DisabledDeviceProfileProvisionConfiguration(provisionSecret);
  299 + break;
236 } 300 }
237 deviceProfileData.setProvisionConfiguration(provisionConfiguration); 301 deviceProfileData.setProvisionConfiguration(provisionConfiguration);
238 deviceProfileData.setConfiguration(configuration); 302 deviceProfileData.setConfiguration(configuration);
@@ -56,7 +56,6 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt @@ -56,7 +56,6 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt
56 return tsKvProtoList; 56 return tsKvProtoList;
57 } 57 }
58 58
59 -  
60 protected TransportProtos.TsKvProto getTsKvProto(String key, String value, TransportProtos.KeyValueType keyValueType) { 59 protected TransportProtos.TsKvProto getTsKvProto(String key, String value, TransportProtos.KeyValueType keyValueType) {
61 TransportProtos.TsKvProto.Builder tsKvProtoBuilder = TransportProtos.TsKvProto.newBuilder(); 60 TransportProtos.TsKvProto.Builder tsKvProtoBuilder = TransportProtos.TsKvProto.newBuilder();
62 TransportProtos.KeyValueProto keyValueProto = getKeyValueProto(key, value, keyValueType); 61 TransportProtos.KeyValueProto keyValueProto = getKeyValueProto(key, value, keyValueType);
@@ -18,9 +18,7 @@ package org.thingsboard.server.mqtt.attributes.request; @@ -18,9 +18,7 @@ package org.thingsboard.server.mqtt.attributes.request;
18 import com.google.protobuf.InvalidProtocolBufferException; 18 import com.google.protobuf.InvalidProtocolBufferException;
19 import io.netty.handler.codec.mqtt.MqttQoS; 19 import io.netty.handler.codec.mqtt.MqttQoS;
20 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
21 -import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;  
22 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 21 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
23 -import org.eclipse.paho.client.mqttv3.MqttCallback;  
24 import org.eclipse.paho.client.mqttv3.MqttException; 22 import org.eclipse.paho.client.mqttv3.MqttException;
25 import org.eclipse.paho.client.mqttv3.MqttMessage; 23 import org.eclipse.paho.client.mqttv3.MqttMessage;
26 import org.junit.After; 24 import org.junit.After;
@@ -36,9 +34,7 @@ import java.util.concurrent.CountDownLatch; @@ -36,9 +34,7 @@ import java.util.concurrent.CountDownLatch;
36 import java.util.concurrent.TimeUnit; 34 import java.util.concurrent.TimeUnit;
37 35
38 import static org.junit.Assert.assertEquals; 36 import static org.junit.Assert.assertEquals;
39 -import static org.junit.Assert.assertFalse;  
40 import static org.junit.Assert.assertNotNull; 37 import static org.junit.Assert.assertNotNull;
41 -import static org.junit.Assert.assertTrue;  
42 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 38 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
43 39
44 @Slf4j 40 @Slf4j
@@ -18,14 +18,9 @@ package org.thingsboard.server.mqtt.attributes.request; @@ -18,14 +18,9 @@ package org.thingsboard.server.mqtt.attributes.request;
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
19 import org.junit.After; 19 import org.junit.After;
20 import org.junit.Before; 20 import org.junit.Before;
21 -import org.junit.Ignore;  
22 import org.junit.Test; 21 import org.junit.Test;
23 import org.thingsboard.server.common.data.TransportPayloadType; 22 import org.thingsboard.server.common.data.TransportPayloadType;
24 23
25 -import static org.junit.Assert.assertEquals;  
26 -import static org.junit.Assert.assertNotNull;  
27 -import static org.junit.Assert.assertTrue;  
28 -  
29 @Slf4j 24 @Slf4j
30 public abstract class AbstractMqttAttributesRequestJsonIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest { 25 public abstract class AbstractMqttAttributesRequestJsonIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest {
31 26
@@ -15,18 +15,26 @@ @@ -15,18 +15,26 @@
15 */ 15 */
16 package org.thingsboard.server.mqtt.attributes.request; 16 package org.thingsboard.server.mqtt.attributes.request;
17 17
  18 +import com.github.os72.protobuf.dynamic.DynamicSchema;
  19 +import com.google.protobuf.Descriptors;
  20 +import com.google.protobuf.DynamicMessage;
18 import com.google.protobuf.InvalidProtocolBufferException; 21 import com.google.protobuf.InvalidProtocolBufferException;
  22 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
19 import io.netty.handler.codec.mqtt.MqttQoS; 23 import io.netty.handler.codec.mqtt.MqttQoS;
20 import lombok.extern.slf4j.Slf4j; 24 import lombok.extern.slf4j.Slf4j;
21 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 25 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
22 import org.eclipse.paho.client.mqttv3.MqttException; 26 import org.eclipse.paho.client.mqttv3.MqttException;
23 import org.eclipse.paho.client.mqttv3.MqttMessage; 27 import org.eclipse.paho.client.mqttv3.MqttMessage;
24 import org.junit.After; 28 import org.junit.After;
25 -import org.junit.Before;  
26 import org.junit.Test; 29 import org.junit.Test;
27 import org.thingsboard.server.common.data.Device; 30 import org.thingsboard.server.common.data.Device;
  31 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
28 import org.thingsboard.server.common.data.TransportPayloadType; 32 import org.thingsboard.server.common.data.TransportPayloadType;
  33 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  34 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  35 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
29 import org.thingsboard.server.common.data.device.profile.MqttTopics; 36 import org.thingsboard.server.common.data.device.profile.MqttTopics;
  37 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
30 import org.thingsboard.server.gen.transport.TransportApiProtos; 38 import org.thingsboard.server.gen.transport.TransportApiProtos;
31 import org.thingsboard.server.gen.transport.TransportProtos; 39 import org.thingsboard.server.gen.transport.TransportProtos;
32 40
@@ -38,16 +46,33 @@ import java.util.concurrent.TimeUnit; @@ -38,16 +46,33 @@ import java.util.concurrent.TimeUnit;
38 import java.util.stream.Collectors; 46 import java.util.stream.Collectors;
39 47
40 import static org.junit.Assert.assertEquals; 48 import static org.junit.Assert.assertEquals;
  49 +import static org.junit.Assert.assertNotNull;
41 import static org.junit.Assert.assertTrue; 50 import static org.junit.Assert.assertTrue;
42 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 51 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
43 52
44 @Slf4j 53 @Slf4j
45 public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest { 54 public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest {
46 55
47 - @Before  
48 - public void beforeTest() throws Exception {  
49 - processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", TransportPayloadType.PROTOBUF, null, null);  
50 - } 56 + public static final String ATTRIBUTES_SCHEMA_STR = "syntax =\"proto3\";\n" +
  57 + "\n" +
  58 + "package test;\n" +
  59 + "\n" +
  60 + "message PostAttributes {\n" +
  61 + " string attribute1 = 1;\n" +
  62 + " bool attribute2 = 2;\n" +
  63 + " double attribute3 = 3;\n" +
  64 + " int32 attribute4 = 4;\n" +
  65 + " JsonObject attribute5 = 5;\n" +
  66 + "\n" +
  67 + " message JsonObject {\n" +
  68 + " int32 someNumber = 6;\n" +
  69 + " repeated int32 someArray = 7;\n" +
  70 + " NestedJsonObject someNestedObject = 8;\n" +
  71 + " message NestedJsonObject {\n" +
  72 + " string key = 9;\n" +
  73 + " }\n" +
  74 + " }\n" +
  75 + "}";
51 76
52 @After 77 @After
53 public void afterTest() throws Exception { 78 public void afterTest() throws Exception {
@@ -56,21 +81,55 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends @@ -56,21 +81,55 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends
56 81
57 @Test 82 @Test
58 public void testRequestAttributesValuesFromTheServer() throws Exception { 83 public void testRequestAttributesValuesFromTheServer() throws Exception {
  84 + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto",
  85 + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, DeviceProfileProvisionType.DISABLED, null, null);
59 processTestRequestAttributesValuesFromTheServer(); 86 processTestRequestAttributesValuesFromTheServer();
60 } 87 }
61 88
62 -  
63 @Test 89 @Test
64 public void testRequestAttributesValuesFromTheServerGateway() throws Exception { 90 public void testRequestAttributesValuesFromTheServerGateway() throws Exception {
  91 + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", TransportPayloadType.PROTOBUF, null, null);
65 processTestGatewayRequestAttributesValuesFromTheServer(); 92 processTestGatewayRequestAttributesValuesFromTheServer();
66 } 93 }
67 94
68 protected void postAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client) throws Exception { 95 protected void postAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client) throws Exception {
69 doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); 96 doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
70 - String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";  
71 - List<String> expectedKeys = Arrays.asList(keys.split(","));  
72 - TransportProtos.PostAttributeMsg postAttributeMsg = getPostAttributeMsg(expectedKeys);  
73 - byte[] payload = postAttributeMsg.toByteArray(); 97 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  98 + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
  99 + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
  100 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
  101 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  102 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  103 + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(ATTRIBUTES_SCHEMA_STR);
  104 + DynamicSchema attributesSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA);
  105 +
  106 + DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject");
  107 + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
  108 + assertNotNull(nestedJsonObjectBuilderDescriptor);
  109 + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
  110 +
  111 + DynamicMessage.Builder jsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject");
  112 + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
  113 + assertNotNull(jsonObjectBuilderDescriptor);
  114 + DynamicMessage jsonObject = jsonObjectBuilder
  115 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
  116 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
  117 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
  118 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
  119 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
  120 + .build();
  121 +
  122 + DynamicMessage.Builder postAttributesBuilder = attributesSchema.newMessageBuilder("PostAttributes");
  123 + Descriptors.Descriptor postAttributesMsgDescriptor = postAttributesBuilder.getDescriptorForType();
  124 + assertNotNull(postAttributesMsgDescriptor);
  125 + DynamicMessage postAttributesMsg = postAttributesBuilder
  126 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute1"), "value1")
  127 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute2"), true)
  128 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute3"), 42.0)
  129 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute4"), 73)
  130 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute5"), jsonObject)
  131 + .build();
  132 + byte[] payload = postAttributesMsg.toByteArray();
74 client.publish(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, new MqttMessage(payload)); 133 client.publish(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, new MqttMessage(payload));
75 client.subscribe(MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttQoS.AT_MOST_ONCE.value()); 134 client.subscribe(MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttQoS.AT_MOST_ONCE.value());
76 } 135 }
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.attributes.request.sql; 16 package org.thingsboard.server.mqtt.attributes.request.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestIntegrationTest;  
20 import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestJsonIntegrationTest; 19 import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestJsonIntegrationTest;
21 20
22 @DaoSqlTest 21 @DaoSqlTest
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.attributes.request.sql; 16 package org.thingsboard.server.mqtt.attributes.request.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestJsonIntegrationTest;  
20 import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestProtoIntegrationTest; 19 import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestProtoIntegrationTest;
21 20
22 @DaoSqlTest 21 @DaoSqlTest
@@ -18,11 +18,7 @@ package org.thingsboard.server.mqtt.attributes.updates; @@ -18,11 +18,7 @@ package org.thingsboard.server.mqtt.attributes.updates;
18 import com.google.protobuf.InvalidProtocolBufferException; 18 import com.google.protobuf.InvalidProtocolBufferException;
19 import io.netty.handler.codec.mqtt.MqttQoS; 19 import io.netty.handler.codec.mqtt.MqttQoS;
20 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
21 -import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;  
22 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 21 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
23 -import org.eclipse.paho.client.mqttv3.MqttCallback;  
24 -import org.eclipse.paho.client.mqttv3.MqttException;  
25 -import org.eclipse.paho.client.mqttv3.MqttMessage;  
26 import org.junit.After; 22 import org.junit.After;
27 import org.junit.Before; 23 import org.junit.Before;
28 import org.junit.Test; 24 import org.junit.Test;
@@ -33,12 +29,10 @@ import org.thingsboard.server.dao.util.mapping.JacksonUtil; @@ -33,12 +29,10 @@ import org.thingsboard.server.dao.util.mapping.JacksonUtil;
33 import org.thingsboard.server.mqtt.attributes.AbstractMqttAttributesIntegrationTest; 29 import org.thingsboard.server.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
34 30
35 import java.nio.charset.StandardCharsets; 31 import java.nio.charset.StandardCharsets;
36 -import java.util.concurrent.CountDownLatch;  
37 import java.util.concurrent.TimeUnit; 32 import java.util.concurrent.TimeUnit;
38 33
39 import static org.junit.Assert.assertEquals; 34 import static org.junit.Assert.assertEquals;
40 import static org.junit.Assert.assertNotNull; 35 import static org.junit.Assert.assertNotNull;
41 -import static org.junit.Assert.assertTrue;  
42 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 36 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
43 37
44 @Slf4j 38 @Slf4j
@@ -21,11 +21,6 @@ import org.junit.Before; @@ -21,11 +21,6 @@ import org.junit.Before;
21 import org.junit.Test; 21 import org.junit.Test;
22 import org.thingsboard.server.common.data.TransportPayloadType; 22 import org.thingsboard.server.common.data.TransportPayloadType;
23 23
24 -import static org.junit.Assert.assertEquals;  
25 -import static org.junit.Assert.assertFalse;  
26 -import static org.junit.Assert.assertNotNull;  
27 -import static org.junit.Assert.assertTrue;  
28 -  
29 @Slf4j 24 @Slf4j
30 public abstract class AbstractMqttAttributesUpdatesJsonIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest { 25 public abstract class AbstractMqttAttributesUpdatesJsonIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest {
31 26
@@ -21,11 +21,9 @@ import org.junit.After; @@ -21,11 +21,9 @@ import org.junit.After;
21 import org.junit.Before; 21 import org.junit.Before;
22 import org.junit.Test; 22 import org.junit.Test;
23 import org.thingsboard.server.common.data.TransportPayloadType; 23 import org.thingsboard.server.common.data.TransportPayloadType;
24 -import org.thingsboard.server.common.data.device.profile.MqttTopics;  
25 import org.thingsboard.server.gen.transport.TransportApiProtos; 24 import org.thingsboard.server.gen.transport.TransportApiProtos;
26 import org.thingsboard.server.gen.transport.TransportProtos; 25 import org.thingsboard.server.gen.transport.TransportProtos;
27 26
28 -import java.nio.charset.StandardCharsets;  
29 import java.util.List; 27 import java.util.List;
30 import java.util.stream.Collectors; 28 import java.util.stream.Collectors;
31 29
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.attributes.updates.sql; 16 package org.thingsboard.server.mqtt.attributes.updates.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesIntegrationTest;  
20 import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest; 19 import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest;
21 20
22 @DaoSqlTest 21 @DaoSqlTest
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.attributes.updates.sql; 16 package org.thingsboard.server.mqtt.attributes.updates.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest;  
20 import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesProtoIntegrationTest; 19 import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesProtoIntegrationTest;
21 20
22 @DaoSqlTest 21 @DaoSqlTest
@@ -20,7 +20,6 @@ import org.eclipse.paho.client.mqttv3.MqttAsyncClient; @@ -20,7 +20,6 @@ import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
20 import org.eclipse.paho.client.mqttv3.MqttMessage; 20 import org.eclipse.paho.client.mqttv3.MqttMessage;
21 import org.junit.After; 21 import org.junit.After;
22 import org.junit.Before; 22 import org.junit.Before;
23 -import org.junit.Ignore;  
24 import org.junit.Test; 23 import org.junit.Test;
25 import org.thingsboard.server.common.data.ClaimRequest; 24 import org.thingsboard.server.common.data.ClaimRequest;
26 import org.thingsboard.server.common.data.Customer; 25 import org.thingsboard.server.common.data.Customer;
@@ -18,7 +18,6 @@ package org.thingsboard.server.mqtt.claim; @@ -18,7 +18,6 @@ package org.thingsboard.server.mqtt.claim;
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
19 import org.junit.After; 19 import org.junit.After;
20 import org.junit.Before; 20 import org.junit.Before;
21 -import org.junit.Ignore;  
22 import org.junit.Test; 21 import org.junit.Test;
23 import org.thingsboard.server.common.data.TransportPayloadType; 22 import org.thingsboard.server.common.data.TransportPayloadType;
24 23
@@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j; @@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j;
19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
20 import org.junit.After; 20 import org.junit.After;
21 import org.junit.Before; 21 import org.junit.Before;
22 -import org.junit.Ignore;  
23 import org.junit.Test; 22 import org.junit.Test;
24 import org.thingsboard.server.common.data.TransportPayloadType; 23 import org.thingsboard.server.common.data.TransportPayloadType;
25 import org.thingsboard.server.gen.transport.TransportApiProtos; 24 import org.thingsboard.server.gen.transport.TransportApiProtos;
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.claim.sql; 16 package org.thingsboard.server.mqtt.claim.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.claim.AbstractMqttClaimDeviceTest;  
20 import org.thingsboard.server.mqtt.claim.AbstractMqttClaimJsonDeviceTest; 19 import org.thingsboard.server.mqtt.claim.AbstractMqttClaimJsonDeviceTest;
21 20
22 @DaoSqlTest 21 @DaoSqlTest
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.claim.sql; 16 package org.thingsboard.server.mqtt.claim.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.claim.AbstractMqttClaimJsonDeviceTest;  
20 import org.thingsboard.server.mqtt.claim.AbstractMqttClaimProtoDeviceTest; 19 import org.thingsboard.server.mqtt.claim.AbstractMqttClaimProtoDeviceTest;
21 20
22 @DaoSqlTest 21 @DaoSqlTest
@@ -94,7 +94,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn @@ -94,7 +94,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
94 94
95 95
96 protected void processTestProvisioningDisabledDevice() throws Exception { 96 protected void processTestProvisioningDisabledDevice() throws Exception {
97 - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.DISABLED, null, null); 97 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.DISABLED, null, null);
98 byte[] result = createMqttClientAndPublish().getPayloadBytes(); 98 byte[] result = createMqttClientAndPublish().getPayloadBytes();
99 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); 99 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
100 Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString()); 100 Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
@@ -103,7 +103,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn @@ -103,7 +103,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
103 103
104 104
105 protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception { 105 protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
106 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 106 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
107 byte[] result = createMqttClientAndPublish().getPayloadBytes(); 107 byte[] result = createMqttClientAndPublish().getPayloadBytes();
108 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); 108 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
109 109
@@ -121,7 +121,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn @@ -121,7 +121,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
121 121
122 122
123 protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception { 123 protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
124 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 124 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
125 String requestCredentials = ",\"credentialsType\": \"ACCESS_TOKEN\",\"token\": \"test_token\""; 125 String requestCredentials = ",\"credentialsType\": \"ACCESS_TOKEN\",\"token\": \"test_token\"";
126 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes(); 126 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes();
127 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); 127 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
@@ -142,7 +142,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn @@ -142,7 +142,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
142 142
143 143
144 protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception { 144 protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
145 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 145 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
146 String requestCredentials = ",\"credentialsType\": \"X509_CERTIFICATE\",\"hash\": \"testHash\""; 146 String requestCredentials = ",\"credentialsType\": \"X509_CERTIFICATE\",\"hash\": \"testHash\"";
147 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes(); 147 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes();
148 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); 148 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
@@ -169,7 +169,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn @@ -169,7 +169,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
169 169
170 170
171 protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception { 171 protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception {
172 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 172 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
173 String requestCredentials = ",\"credentialsType\": \"MQTT_BASIC\",\"clientId\": \"test_clientId\",\"username\": \"test_username\",\"password\": \"test_password\""; 173 String requestCredentials = ",\"credentialsType\": \"MQTT_BASIC\",\"clientId\": \"test_clientId\",\"username\": \"test_username\",\"password\": \"test_password\"";
174 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes(); 174 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes();
175 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); 175 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
@@ -197,7 +197,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn @@ -197,7 +197,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
197 } 197 }
198 198
199 protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception { 199 protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
200 - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret"); 200 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret");
201 byte[] result = createMqttClientAndPublish().getPayloadBytes(); 201 byte[] result = createMqttClientAndPublish().getPayloadBytes();
202 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); 202 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
203 Assert.assertEquals(savedDevice.getId().toString(), response.get("deviceId").getAsString()); 203 Assert.assertEquals(savedDevice.getId().toString(), response.get("deviceId").getAsString());
@@ -210,7 +210,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn @@ -210,7 +210,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
210 } 210 }
211 211
212 protected void processTestProvisioningWithBadKeyDevice() throws Exception { 212 protected void processTestProvisioningWithBadKeyDevice() throws Exception {
213 - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret"); 213 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret");
214 byte[] result = createMqttClientAndPublish().getPayloadBytes(); 214 byte[] result = createMqttClientAndPublish().getPayloadBytes();
215 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); 215 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
216 Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString()); 216 Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
@@ -102,14 +102,14 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI @@ -102,14 +102,14 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
102 102
103 103
104 protected void processTestProvisioningDisabledDevice() throws Exception { 104 protected void processTestProvisioningDisabledDevice() throws Exception {
105 - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.DISABLED, null, null); 105 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.DISABLED, null, null);
106 ProvisionDeviceResponseMsg result = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); 106 ProvisionDeviceResponseMsg result = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
107 Assert.assertNotNull(result); 107 Assert.assertNotNull(result);
108 Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), result.getProvisionResponseStatus().toString()); 108 Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), result.getProvisionResponseStatus().toString());
109 } 109 }
110 110
111 protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception { 111 protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
112 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 112 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
113 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); 113 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
114 114
115 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); 115 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
@@ -125,7 +125,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI @@ -125,7 +125,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
125 } 125 }
126 126
127 protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception { 127 protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
128 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 128 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null,null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
129 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceTokenRequestMsg(ValidateDeviceTokenRequestMsg.newBuilder().setToken("test_token").build()).build(); 129 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceTokenRequestMsg(ValidateDeviceTokenRequestMsg.newBuilder().setToken("test_token").build()).build();
130 130
131 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.ACCESS_TOKEN, requestCredentials)).getPayloadBytes()); 131 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.ACCESS_TOKEN, requestCredentials)).getPayloadBytes());
@@ -145,7 +145,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI @@ -145,7 +145,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
145 } 145 }
146 146
147 protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception { 147 protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
148 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 148 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
149 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceX509CertRequestMsg(ValidateDeviceX509CertRequestMsg.newBuilder().setHash("testHash").build()).build(); 149 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceX509CertRequestMsg(ValidateDeviceX509CertRequestMsg.newBuilder().setHash("testHash").build()).build();
150 150
151 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.X509_CERTIFICATE, requestCredentials)).getPayloadBytes()); 151 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.X509_CERTIFICATE, requestCredentials)).getPayloadBytes());
@@ -171,7 +171,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI @@ -171,7 +171,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
171 } 171 }
172 172
173 protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception { 173 protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception {
174 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 174 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
175 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateBasicMqttCredRequestMsg( 175 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateBasicMqttCredRequestMsg(
176 ValidateBasicMqttCredRequestMsg.newBuilder() 176 ValidateBasicMqttCredRequestMsg.newBuilder()
177 .setClientId("test_clientId") 177 .setClientId("test_clientId")
@@ -205,7 +205,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI @@ -205,7 +205,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
205 } 205 }
206 206
207 protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception { 207 protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
208 - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret"); 208 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret");
209 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); 209 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
210 Assert.assertEquals(savedDevice.getId().getId(), new UUID(response.getDeviceCredentials().getDeviceIdMSB(), response.getDeviceCredentials().getDeviceIdLSB())); 210 Assert.assertEquals(savedDevice.getId().getId(), new UUID(response.getDeviceCredentials().getDeviceIdMSB(), response.getDeviceCredentials().getDeviceIdLSB()));
211 211
@@ -217,7 +217,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI @@ -217,7 +217,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
217 } 217 }
218 218
219 protected void processTestProvisioningWithBadKeyDevice() throws Exception { 219 protected void processTestProvisioningWithBadKeyDevice() throws Exception {
220 - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret"); 220 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret");
221 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); 221 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
222 Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.getProvisionResponseStatus().toString()); 222 Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.getProvisionResponseStatus().toString());
223 } 223 }
@@ -15,49 +15,14 @@ @@ -15,49 +15,14 @@
15 */ 15 */
16 package org.thingsboard.server.mqtt.rpc; 16 package org.thingsboard.server.mqtt.rpc;
17 17
18 -import com.fasterxml.jackson.databind.JsonNode;  
19 -import com.fasterxml.jackson.databind.node.ObjectNode;  
20 -import com.google.protobuf.InvalidProtocolBufferException;  
21 -import com.nimbusds.jose.util.StandardCharset;  
22 import com.datastax.oss.driver.api.core.uuid.Uuids; 18 import com.datastax.oss.driver.api.core.uuid.Uuids;
23 -import io.netty.handler.codec.mqtt.MqttQoS;  
24 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
25 -import org.apache.commons.lang3.StringUtils;  
26 -import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;  
27 -import org.eclipse.paho.client.mqttv3.MqttAsyncClient;  
28 -import org.eclipse.paho.client.mqttv3.MqttCallback;  
29 -import org.eclipse.paho.client.mqttv3.MqttConnectOptions;  
30 -import org.eclipse.paho.client.mqttv3.MqttException;  
31 -import org.eclipse.paho.client.mqttv3.MqttMessage;  
32 import org.junit.After; 20 import org.junit.After;
33 import org.junit.Assert; 21 import org.junit.Assert;
34 import org.junit.Before; 22 import org.junit.Before;
35 -import org.junit.Ignore;  
36 import org.junit.Test; 23 import org.junit.Test;
37 -import org.thingsboard.server.common.data.Device;  
38 -import org.thingsboard.server.common.data.DeviceProfile;  
39 -import org.thingsboard.server.common.data.DeviceProfileType;  
40 -import org.thingsboard.server.common.data.DeviceTransportType;  
41 -import org.thingsboard.server.common.data.Tenant;  
42 -import org.thingsboard.server.common.data.TransportPayloadType;  
43 -import org.thingsboard.server.common.data.User;  
44 -import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;  
45 -import org.thingsboard.server.common.data.device.profile.DeviceProfileData;  
46 -import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;  
47 -import org.thingsboard.server.common.data.device.profile.MqttTopics;  
48 -import org.thingsboard.server.common.data.security.Authority;  
49 -import org.thingsboard.server.common.data.security.DeviceCredentials;  
50 -import org.thingsboard.server.controller.AbstractControllerTest;  
51 -import org.thingsboard.server.dao.util.mapping.JacksonUtil;  
52 import org.thingsboard.server.service.security.AccessValidator; 24 import org.thingsboard.server.service.security.AccessValidator;
53 25
54 -import java.util.Arrays;  
55 -import java.util.concurrent.CountDownLatch;  
56 -import java.util.concurrent.TimeUnit;  
57 -import java.util.concurrent.atomic.AtomicInteger;  
58 -  
59 -import static org.junit.Assert.assertEquals;  
60 -import static org.junit.Assert.assertNotNull;  
61 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 26 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
62 27
63 /** 28 /**
@@ -15,9 +15,7 @@ @@ -15,9 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.mqtt.rpc; 16 package org.thingsboard.server.mqtt.rpc;
17 17
18 -import com.datastax.oss.driver.api.core.uuid.Uuids;  
19 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
20 -import com.fasterxml.jackson.databind.node.ObjectNode;  
21 import com.google.protobuf.InvalidProtocolBufferException; 19 import com.google.protobuf.InvalidProtocolBufferException;
22 import com.nimbusds.jose.util.StandardCharset; 20 import com.nimbusds.jose.util.StandardCharset;
23 import io.netty.handler.codec.mqtt.MqttQoS; 21 import io.netty.handler.codec.mqtt.MqttQoS;
@@ -26,35 +24,18 @@ import org.apache.commons.lang3.StringUtils; @@ -26,35 +24,18 @@ import org.apache.commons.lang3.StringUtils;
26 import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; 24 import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
27 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 25 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
28 import org.eclipse.paho.client.mqttv3.MqttCallback; 26 import org.eclipse.paho.client.mqttv3.MqttCallback;
29 -import org.eclipse.paho.client.mqttv3.MqttConnectOptions;  
30 import org.eclipse.paho.client.mqttv3.MqttException; 27 import org.eclipse.paho.client.mqttv3.MqttException;
31 import org.eclipse.paho.client.mqttv3.MqttMessage; 28 import org.eclipse.paho.client.mqttv3.MqttMessage;
32 -import org.junit.After;  
33 import org.junit.Assert; 29 import org.junit.Assert;
34 -import org.junit.Before;  
35 -import org.junit.Test;  
36 import org.thingsboard.server.common.data.Device; 30 import org.thingsboard.server.common.data.Device;
37 -import org.thingsboard.server.common.data.DeviceProfile;  
38 -import org.thingsboard.server.common.data.DeviceProfileType;  
39 -import org.thingsboard.server.common.data.DeviceTransportType;  
40 -import org.thingsboard.server.common.data.Tenant;  
41 import org.thingsboard.server.common.data.TransportPayloadType; 31 import org.thingsboard.server.common.data.TransportPayloadType;
42 -import org.thingsboard.server.common.data.User;  
43 -import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;  
44 -import org.thingsboard.server.common.data.device.profile.DeviceProfileData;  
45 -import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;  
46 import org.thingsboard.server.common.data.device.profile.MqttTopics; 32 import org.thingsboard.server.common.data.device.profile.MqttTopics;
47 -import org.thingsboard.server.common.data.security.Authority;  
48 -import org.thingsboard.server.common.data.security.DeviceCredentials;  
49 -import org.thingsboard.server.controller.AbstractControllerTest;  
50 import org.thingsboard.server.dao.util.mapping.JacksonUtil; 33 import org.thingsboard.server.dao.util.mapping.JacksonUtil;
51 import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest; 34 import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest;
52 -import org.thingsboard.server.service.security.AccessValidator;  
53 35
54 import java.util.Arrays; 36 import java.util.Arrays;
55 import java.util.concurrent.CountDownLatch; 37 import java.util.concurrent.CountDownLatch;
56 import java.util.concurrent.TimeUnit; 38 import java.util.concurrent.TimeUnit;
57 -import java.util.concurrent.atomic.AtomicInteger;  
58 39
59 import static org.junit.Assert.assertEquals; 40 import static org.junit.Assert.assertEquals;
60 import static org.junit.Assert.assertNotNull; 41 import static org.junit.Assert.assertNotNull;
@@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j; @@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j;
19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
20 import org.junit.After; 20 import org.junit.After;
21 import org.junit.Before; 21 import org.junit.Before;
22 -import org.junit.Ignore;  
23 import org.junit.Test; 22 import org.junit.Test;
24 import org.thingsboard.server.common.data.TransportPayloadType; 23 import org.thingsboard.server.common.data.TransportPayloadType;
25 24
@@ -22,16 +22,12 @@ import org.eclipse.paho.client.mqttv3.MqttException; @@ -22,16 +22,12 @@ import org.eclipse.paho.client.mqttv3.MqttException;
22 import org.eclipse.paho.client.mqttv3.MqttMessage; 22 import org.eclipse.paho.client.mqttv3.MqttMessage;
23 import org.junit.After; 23 import org.junit.After;
24 import org.junit.Before; 24 import org.junit.Before;
25 -import org.junit.Ignore;  
26 import org.junit.Test; 25 import org.junit.Test;
27 import org.thingsboard.server.common.data.TransportPayloadType; 26 import org.thingsboard.server.common.data.TransportPayloadType;
28 import org.thingsboard.server.common.data.device.profile.MqttTopics; 27 import org.thingsboard.server.common.data.device.profile.MqttTopics;
29 import org.thingsboard.server.gen.transport.TransportApiProtos; 28 import org.thingsboard.server.gen.transport.TransportApiProtos;
30 import org.thingsboard.server.gen.transport.TransportProtos; 29 import org.thingsboard.server.gen.transport.TransportProtos;
31 30
32 -import static org.junit.Assert.assertEquals;  
33 -import static org.junit.Assert.assertNotNull;  
34 -  
35 @Slf4j 31 @Slf4j
36 public abstract class AbstractMqttServerSideRpcProtoIntegrationTest extends AbstractMqttServerSideRpcIntegrationTest { 32 public abstract class AbstractMqttServerSideRpcProtoIntegrationTest extends AbstractMqttServerSideRpcIntegrationTest {
37 33
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.mqtt.telemetry.attributes; 16 package org.thingsboard.server.mqtt.telemetry.attributes;
17 17
  18 +import com.fasterxml.jackson.core.JsonProcessingException;
18 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 20 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
20 import org.junit.After; 21 import org.junit.After;
@@ -142,7 +143,7 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt @@ -142,7 +143,7 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt
142 143
143 } 144 }
144 145
145 - protected void assertAttributesValues(List<Map<String, Object>> deviceValues, Set<String> expectedKeySet) { 146 + protected void assertAttributesValues(List<Map<String, Object>> deviceValues, Set<String> expectedKeySet) throws JsonProcessingException {
146 for (Map<String, Object> map : deviceValues) { 147 for (Map<String, Object> map : deviceValues) {
147 String key = (String) map.get("key"); 148 String key = (String) map.get("key");
148 Object value = map.get("value"); 149 Object value = map.get("value");
@@ -15,18 +15,24 @@ @@ -15,18 +15,24 @@
15 */ 15 */
16 package org.thingsboard.server.mqtt.telemetry.attributes; 16 package org.thingsboard.server.mqtt.telemetry.attributes;
17 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;
18 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
19 import org.junit.After; 23 import org.junit.After;
20 -import org.junit.Before;  
21 import org.junit.Test; 24 import org.junit.Test;
22 import org.thingsboard.server.common.data.TransportPayloadType; 25 import org.thingsboard.server.common.data.TransportPayloadType;
  26 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  27 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  28 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  29 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
23 import org.thingsboard.server.gen.transport.TransportApiProtos; 30 import org.thingsboard.server.gen.transport.TransportApiProtos;
24 import org.thingsboard.server.gen.transport.TransportProtos; 31 import org.thingsboard.server.gen.transport.TransportProtos;
25 32
26 import java.util.Arrays; 33 import java.util.Arrays;
27 import java.util.List; 34 import java.util.List;
28 35
29 -import static org.junit.Assert.assertEquals;  
30 import static org.junit.Assert.assertNotNull; 36 import static org.junit.Assert.assertNotNull;
31 import static org.junit.Assert.assertTrue; 37 import static org.junit.Assert.assertTrue;
32 38
@@ -35,11 +41,6 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac @@ -35,11 +41,6 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac
35 41
36 private static final String POST_DATA_ATTRIBUTES_TOPIC = "proto/attributes"; 42 private static final String POST_DATA_ATTRIBUTES_TOPIC = "proto/attributes";
37 43
38 - @Before  
39 - public void beforeTest() throws Exception {  
40 - processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC);  
41 - }  
42 -  
43 @After 44 @After
44 public void afterTest() throws Exception { 45 public void afterTest() throws Exception {
45 processAfterTest(); 46 processAfterTest();
@@ -47,13 +48,49 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac @@ -47,13 +48,49 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac
47 48
48 @Test 49 @Test
49 public void testPushMqttAttributes() throws Exception { 50 public void testPushMqttAttributes() throws Exception {
  51 + super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC);
50 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); 52 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
51 - TransportProtos.PostAttributeMsg msg = getPostAttributeMsg(expectedKeys);  
52 - processAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, expectedKeys, msg.toByteArray()); 53 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  54 + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
  55 + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
  56 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
  57 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  58 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  59 + ProtoFileElement transportProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_ATTRIBUTES_PROTO_SCHEMA);
  60 + DynamicSchema attributesSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchemaFile, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA);
  61 +
  62 + DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject");
  63 + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
  64 + assertNotNull(nestedJsonObjectBuilderDescriptor);
  65 + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
  66 +
  67 + DynamicMessage.Builder jsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject");
  68 + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
  69 + assertNotNull(jsonObjectBuilderDescriptor);
  70 + DynamicMessage jsonObject = jsonObjectBuilder
  71 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
  72 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
  73 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
  74 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
  75 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
  76 + .build();
  77 +
  78 + DynamicMessage.Builder postAttributesBuilder = attributesSchema.newMessageBuilder("PostAttributes");
  79 + Descriptors.Descriptor postAttributesMsgDescriptor = postAttributesBuilder.getDescriptorForType();
  80 + assertNotNull(postAttributesMsgDescriptor);
  81 + DynamicMessage postAttributesMsg = postAttributesBuilder
  82 + .setField(postAttributesMsgDescriptor.findFieldByName("key1"), "value1")
  83 + .setField(postAttributesMsgDescriptor.findFieldByName("key2"), true)
  84 + .setField(postAttributesMsgDescriptor.findFieldByName("key3"), 3.0)
  85 + .setField(postAttributesMsgDescriptor.findFieldByName("key4"), 4)
  86 + .setField(postAttributesMsgDescriptor.findFieldByName("key5"), jsonObject)
  87 + .build();
  88 + processAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, expectedKeys, postAttributesMsg.toByteArray());
53 } 89 }
54 90
55 @Test 91 @Test
56 public void testPushMqttAttributesGateway() throws Exception { 92 public void testPushMqttAttributesGateway() throws Exception {
  93 + super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, null);
57 TransportApiProtos.GatewayAttributesMsg.Builder gatewayAttributesMsgProtoBuilder = TransportApiProtos.GatewayAttributesMsg.newBuilder(); 94 TransportApiProtos.GatewayAttributesMsg.Builder gatewayAttributesMsgProtoBuilder = TransportApiProtos.GatewayAttributesMsg.newBuilder();
58 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); 95 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
59 String deviceName1 = "Device A"; 96 String deviceName1 = "Device A";
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.telemetry.attributes.nosql; 16 package org.thingsboard.server.mqtt.telemetry.attributes.nosql;
17 17
18 import org.thingsboard.server.dao.service.DaoNoSqlTest; 18 import org.thingsboard.server.dao.service.DaoNoSqlTest;
19 -import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest;  
20 import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest; 19 import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest;
21 20
22 @DaoNoSqlTest 21 @DaoNoSqlTest
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.telemetry.attributes.nosql; 16 package org.thingsboard.server.mqtt.telemetry.attributes.nosql;
17 17
18 import org.thingsboard.server.dao.service.DaoNoSqlTest; 18 import org.thingsboard.server.dao.service.DaoNoSqlTest;
19 -import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest;  
20 import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest; 19 import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest;
21 20
22 @DaoNoSqlTest 21 @DaoNoSqlTest
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.telemetry.attributes.sql; 16 package org.thingsboard.server.mqtt.telemetry.attributes.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest;  
20 import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest; 19 import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest;
21 20
22 @DaoSqlTest 21 @DaoSqlTest
@@ -27,7 +27,6 @@ import org.junit.After; @@ -27,7 +27,6 @@ import org.junit.After;
27 import org.junit.Before; 27 import org.junit.Before;
28 import org.junit.Test; 28 import org.junit.Test;
29 import org.thingsboard.server.common.data.Device; 29 import org.thingsboard.server.common.data.Device;
30 -import org.thingsboard.server.common.data.TransportPayloadType;  
31 import org.thingsboard.server.common.data.device.profile.MqttTopics; 30 import org.thingsboard.server.common.data.device.profile.MqttTopics;
32 import org.thingsboard.server.common.data.id.DeviceId; 31 import org.thingsboard.server.common.data.id.DeviceId;
33 import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest; 32 import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest;
@@ -27,7 +27,6 @@ import org.thingsboard.server.common.data.device.profile.MqttTopics; @@ -27,7 +27,6 @@ import org.thingsboard.server.common.data.device.profile.MqttTopics;
27 import java.util.Arrays; 27 import java.util.Arrays;
28 import java.util.List; 28 import java.util.List;
29 29
30 -import static org.junit.Assert.assertEquals;  
31 import static org.junit.Assert.assertNotNull; 30 import static org.junit.Assert.assertNotNull;
32 31
33 @Slf4j 32 @Slf4j
@@ -15,33 +15,36 @@ @@ -15,33 +15,36 @@
15 */ 15 */
16 package org.thingsboard.server.mqtt.telemetry.timeseries; 16 package org.thingsboard.server.mqtt.telemetry.timeseries;
17 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;
18 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 23 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
20 import org.junit.After; 24 import org.junit.After;
21 -import org.junit.Before;  
22 import org.junit.Test; 25 import org.junit.Test;
23 import org.thingsboard.server.common.data.Device; 26 import org.thingsboard.server.common.data.Device;
  27 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
24 import org.thingsboard.server.common.data.TransportPayloadType; 28 import org.thingsboard.server.common.data.TransportPayloadType;
  29 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  30 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  31 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
25 import org.thingsboard.server.common.data.device.profile.MqttTopics; 32 import org.thingsboard.server.common.data.device.profile.MqttTopics;
  33 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
26 import org.thingsboard.server.gen.transport.TransportApiProtos; 34 import org.thingsboard.server.gen.transport.TransportApiProtos;
27 import org.thingsboard.server.gen.transport.TransportProtos; 35 import org.thingsboard.server.gen.transport.TransportProtos;
28 36
29 import java.util.Arrays; 37 import java.util.Arrays;
30 import java.util.List; 38 import java.util.List;
31 39
32 -import static org.junit.Assert.assertEquals;  
33 import static org.junit.Assert.assertNotNull; 40 import static org.junit.Assert.assertNotNull;
  41 +import static org.junit.Assert.assertTrue;
34 42
35 @Slf4j 43 @Slf4j
36 public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends AbstractMqttTimeseriesIntegrationTest { 44 public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends AbstractMqttTimeseriesIntegrationTest {
37 45
38 private static final String POST_DATA_TELEMETRY_TOPIC = "proto/telemetry"; 46 private static final String POST_DATA_TELEMETRY_TOPIC = "proto/telemetry";
39 47
40 - @Before  
41 - public void beforeTest() throws Exception {  
42 - processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null);  
43 - }  
44 -  
45 @After 48 @After
46 public void afterTest() throws Exception { 49 public void afterTest() throws Exception {
47 processAfterTest(); 50 processAfterTest();
@@ -49,20 +52,127 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac @@ -49,20 +52,127 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac
49 52
50 @Test 53 @Test
51 public void testPushMqttTelemetry() throws Exception { 54 public void testPushMqttTelemetry() throws Exception {
  55 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null);
52 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); 56 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
53 - TransportProtos.TsKvListProto tsKvListProto = getTsKvListProto(expectedKeys, 0);  
54 - processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, tsKvListProto.toByteArray(), false); 57 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  58 + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
  59 + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
  60 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
  61 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  62 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  63 + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_TELEMETRY_PROTO_SCHEMA);
  64 + DynamicSchema telemetrySchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, "telemetrySchema");
  65 +
  66 + DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject");
  67 + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
  68 + assertNotNull(nestedJsonObjectBuilderDescriptor);
  69 + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
  70 +
  71 + DynamicMessage.Builder jsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject");
  72 + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
  73 + assertNotNull(jsonObjectBuilderDescriptor);
  74 + DynamicMessage jsonObject = jsonObjectBuilder
  75 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
  76 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
  77 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
  78 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
  79 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
  80 + .build();
  81 +
  82 + DynamicMessage.Builder postTelemetryBuilder = telemetrySchema.newMessageBuilder("PostTelemetry");
  83 + Descriptors.Descriptor postTelemetryMsgDescriptor = postTelemetryBuilder.getDescriptorForType();
  84 + assertNotNull(postTelemetryMsgDescriptor);
  85 + DynamicMessage postTelemetryMsg = postTelemetryBuilder
  86 + .setField(postTelemetryMsgDescriptor.findFieldByName("key1"), "value1")
  87 + .setField(postTelemetryMsgDescriptor.findFieldByName("key2"), true)
  88 + .setField(postTelemetryMsgDescriptor.findFieldByName("key3"), 3.0)
  89 + .setField(postTelemetryMsgDescriptor.findFieldByName("key4"), 4)
  90 + .setField(postTelemetryMsgDescriptor.findFieldByName("key5"), jsonObject)
  91 + .build();
  92 + processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, postTelemetryMsg.toByteArray(), false);
55 } 93 }
56 94
57 @Test 95 @Test
58 public void testPushMqttTelemetryWithTs() throws Exception { 96 public void testPushMqttTelemetryWithTs() throws Exception {
  97 + String schemaStr = "syntax =\"proto3\";\n" +
  98 + "\n" +
  99 + "package test;\n" +
  100 + "\n" +
  101 + "message PostTelemetry {\n" +
  102 + " int64 ts = 1;\n" +
  103 + " Values values = 2;\n" +
  104 + " \n" +
  105 + " message Values {\n" +
  106 + " string key1 = 3;\n" +
  107 + " bool key2 = 4;\n" +
  108 + " double key3 = 5;\n" +
  109 + " int32 key4 = 6;\n" +
  110 + " JsonObject key5 = 7;\n" +
  111 + " }\n" +
  112 + " \n" +
  113 + " message JsonObject {\n" +
  114 + " int32 someNumber = 8;\n" +
  115 + " repeated int32 someArray = 9;\n" +
  116 + " NestedJsonObject someNestedObject = 10;\n" +
  117 + " message NestedJsonObject {\n" +
  118 + " string key = 11;\n" +
  119 + " }\n" +
  120 + " }\n" +
  121 + "}";
  122 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, DeviceProfileProvisionType.DISABLED, null, null);
59 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); 123 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
60 - TransportProtos.TsKvListProto tsKvListProto = getTsKvListProto(expectedKeys, 10000);  
61 - processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, tsKvListProto.toByteArray(), true); 124 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  125 + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
  126 + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
  127 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
  128 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  129 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  130 + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(schemaStr);
  131 + DynamicSchema telemetrySchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, "telemetrySchema");
  132 +
  133 + DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject");
  134 + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
  135 + assertNotNull(nestedJsonObjectBuilderDescriptor);
  136 + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
  137 +
  138 + DynamicMessage.Builder jsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject");
  139 + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
  140 + assertNotNull(jsonObjectBuilderDescriptor);
  141 + DynamicMessage jsonObject = jsonObjectBuilder
  142 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
  143 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
  144 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
  145 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
  146 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
  147 + .build();
  148 +
  149 +
  150 + DynamicMessage.Builder valuesBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.Values");
  151 + Descriptors.Descriptor valuesDescriptor = valuesBuilder.getDescriptorForType();
  152 + assertNotNull(valuesDescriptor);
  153 +
  154 + DynamicMessage valuesMsg = valuesBuilder
  155 + .setField(valuesDescriptor.findFieldByName("key1"), "value1")
  156 + .setField(valuesDescriptor.findFieldByName("key2"), true)
  157 + .setField(valuesDescriptor.findFieldByName("key3"), 3.0)
  158 + .setField(valuesDescriptor.findFieldByName("key4"), 4)
  159 + .setField(valuesDescriptor.findFieldByName("key5"), jsonObject)
  160 + .build();
  161 +
  162 + DynamicMessage.Builder postTelemetryBuilder = telemetrySchema.newMessageBuilder("PostTelemetry");
  163 + Descriptors.Descriptor postTelemetryMsgDescriptor = postTelemetryBuilder.getDescriptorForType();
  164 + assertNotNull(postTelemetryMsgDescriptor);
  165 + DynamicMessage postTelemetryMsg = postTelemetryBuilder
  166 + .setField(postTelemetryMsgDescriptor.findFieldByName("ts"), 10000L)
  167 + .setField(postTelemetryMsgDescriptor.findFieldByName("values"), valuesMsg)
  168 + .build();
  169 +
  170 + processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, postTelemetryMsg.toByteArray(), true);
62 } 171 }
63 172
64 @Test 173 @Test
65 public void testPushMqttTelemetryGateway() throws Exception { 174 public void testPushMqttTelemetryGateway() throws Exception {
  175 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.DISABLED, null, null);
66 TransportApiProtos.GatewayTelemetryMsg.Builder gatewayTelemetryMsgProtoBuilder = TransportApiProtos.GatewayTelemetryMsg.newBuilder(); 176 TransportApiProtos.GatewayTelemetryMsg.Builder gatewayTelemetryMsgProtoBuilder = TransportApiProtos.GatewayTelemetryMsg.newBuilder();
67 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); 177 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
68 String deviceName1 = "Device A"; 178 String deviceName1 = "Device A";
@@ -76,6 +186,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac @@ -76,6 +186,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac
76 186
77 @Test 187 @Test
78 public void testGatewayConnect() throws Exception { 188 public void testGatewayConnect() throws Exception {
  189 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, null, null, DeviceProfileProvisionType.DISABLED, null, null);
79 String deviceName = "Device A"; 190 String deviceName = "Device A";
80 TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName); 191 TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName);
81 MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); 192 MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.telemetry.timeseries.sql; 16 package org.thingsboard.server.mqtt.telemetry.timeseries.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest;  
20 import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest; 19 import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest;
21 20
22 /** 21 /**
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.telemetry.timeseries.sql; 16 package org.thingsboard.server.mqtt.telemetry.timeseries.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest;  
20 import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest; 19 import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest;
21 20
22 /** 21 /**
@@ -71,6 +71,14 @@ @@ -71,6 +71,14 @@
71 <artifactId>java-driver-core</artifactId> 71 <artifactId>java-driver-core</artifactId>
72 <scope>test</scope> 72 <scope>test</scope>
73 </dependency> 73 </dependency>
  74 + <dependency>
  75 + <groupId>com.squareup.wire</groupId>
  76 + <artifactId>wire-schema</artifactId>
  77 + </dependency>
  78 + <dependency>
  79 + <groupId>org.thingsboard</groupId>
  80 + <artifactId>protobuf-dynamic</artifactId>
  81 + </dependency>
74 </dependencies> 82 </dependencies>
75 83
76 <build> 84 <build>
@@ -29,7 +29,7 @@ import org.thingsboard.server.common.data.DeviceTransportType; @@ -29,7 +29,7 @@ import org.thingsboard.server.common.data.DeviceTransportType;
29 property = "type") 29 property = "type")
30 @JsonSubTypes({ 30 @JsonSubTypes({
31 @JsonSubTypes.Type(value = DefaultDeviceProfileTransportConfiguration.class, name = "DEFAULT"), 31 @JsonSubTypes.Type(value = DefaultDeviceProfileTransportConfiguration.class, name = "DEFAULT"),
32 - @JsonSubTypes.Type(value = MqttDeviceProfileTransportConfiguration.class, name = "MQTT"), 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 public interface DeviceProfileTransportConfiguration { 34 public interface DeviceProfileTransportConfiguration {
35 35
  1 +/**
  2 + * Copyright © 2016-2020 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.TransportPayloadType;
  20 +
  21 +@Data
  22 +public class JsonTransportPayloadConfiguration implements TransportPayloadTypeConfiguration {
  23 +
  24 + @Override
  25 + public TransportPayloadType getTransportPayloadType() {
  26 + return TransportPayloadType.JSON;
  27 + }
  28 +}
@@ -16,20 +16,27 @@ @@ -16,20 +16,27 @@
16 package org.thingsboard.server.common.data.device.profile; 16 package org.thingsboard.server.common.data.device.profile;
17 17
18 import lombok.Data; 18 import lombok.Data;
19 -import org.thingsboard.server.common.data.TransportPayloadType;  
20 import org.thingsboard.server.common.data.DeviceTransportType; 19 import org.thingsboard.server.common.data.DeviceTransportType;
21 20
22 @Data 21 @Data
23 public class MqttDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration { 22 public class MqttDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration {
24 23
25 - private TransportPayloadType transportPayloadType = TransportPayloadType.JSON;  
26 -  
27 private String deviceTelemetryTopic = MqttTopics.DEVICE_TELEMETRY_TOPIC; 24 private String deviceTelemetryTopic = MqttTopics.DEVICE_TELEMETRY_TOPIC;
28 private String deviceAttributesTopic = MqttTopics.DEVICE_ATTRIBUTES_TOPIC; 25 private String deviceAttributesTopic = MqttTopics.DEVICE_ATTRIBUTES_TOPIC;
  26 + private TransportPayloadTypeConfiguration transportPayloadTypeConfiguration;
29 27
30 @Override 28 @Override
31 public DeviceTransportType getType() { 29 public DeviceTransportType getType() {
32 return DeviceTransportType.MQTT; 30 return DeviceTransportType.MQTT;
33 } 31 }
34 32
  33 + public TransportPayloadTypeConfiguration getTransportPayloadTypeConfiguration() {
  34 + if (transportPayloadTypeConfiguration != null) {
  35 + return transportPayloadTypeConfiguration;
  36 + } else {
  37 + return new JsonTransportPayloadConfiguration();
  38 + }
  39 + }
  40 +
  41 +
35 } 42 }
  1 +/**
  2 + * Copyright © 2016-2020 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.github.os72.protobuf.dynamic.DynamicSchema;
  20 +import com.github.os72.protobuf.dynamic.EnumDefinition;
  21 +import com.github.os72.protobuf.dynamic.MessageDefinition;
  22 +import com.google.protobuf.Descriptors;
  23 +import com.google.protobuf.DynamicMessage;
  24 +import com.squareup.wire.schema.Location;
  25 +import com.squareup.wire.schema.internal.parser.EnumConstantElement;
  26 +import com.squareup.wire.schema.internal.parser.EnumElement;
  27 +import com.squareup.wire.schema.internal.parser.FieldElement;
  28 +import com.squareup.wire.schema.internal.parser.MessageElement;
  29 +import com.squareup.wire.schema.internal.parser.OneOfElement;
  30 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
  31 +import com.squareup.wire.schema.internal.parser.ProtoParser;
  32 +import com.squareup.wire.schema.internal.parser.TypeElement;
  33 +import lombok.Data;
  34 +import lombok.extern.slf4j.Slf4j;
  35 +import org.thingsboard.server.common.data.TransportPayloadType;
  36 +
  37 +import java.util.ArrayList;
  38 +import java.util.Collections;
  39 +import java.util.List;
  40 +import java.util.stream.Collectors;
  41 +
  42 +@Slf4j
  43 +@Data
  44 +public class ProtoTransportPayloadConfiguration implements TransportPayloadTypeConfiguration {
  45 +
  46 + public static final Location LOCATION = new Location("", "", -1, -1);
  47 + public static final String ATTRIBUTES_PROTO_SCHEMA = "attributes proto schema";
  48 + public static final String TELEMETRY_PROTO_SCHEMA = "telemetry proto schema";
  49 +
  50 + private String deviceTelemetryProtoSchema;
  51 + private String deviceAttributesProtoSchema;
  52 +
  53 + @Override
  54 + public TransportPayloadType getTransportPayloadType() {
  55 + return TransportPayloadType.PROTOBUF;
  56 + }
  57 +
  58 + public Descriptors.Descriptor getTelemetryDynamicMessageDescriptor(String deviceTelemetryProtoSchema) {
  59 + return getDescriptor(deviceTelemetryProtoSchema, TELEMETRY_PROTO_SCHEMA);
  60 + }
  61 +
  62 + public Descriptors.Descriptor getAttributesDynamicMessageDescriptor(String deviceAttributesProtoSchema) {
  63 + return getDescriptor(deviceAttributesProtoSchema, ATTRIBUTES_PROTO_SCHEMA);
  64 + }
  65 +
  66 + private Descriptors.Descriptor getDescriptor(String protoSchema, String schemaName) {
  67 + try {
  68 + ProtoFileElement protoFileElement = getTransportProtoSchema(protoSchema);
  69 + DynamicSchema dynamicSchema = getDynamicSchema(protoFileElement, schemaName);
  70 + String lastMsgName = getMessageTypes(protoFileElement.getTypes()).stream()
  71 + .map(MessageElement::getName).reduce((previous, last) -> last).get();
  72 + DynamicMessage.Builder builder = dynamicSchema.newMessageBuilder(lastMsgName);
  73 + return builder.getDescriptorForType();
  74 + } catch (Exception e) {
  75 + log.warn("Failed to get Message Descriptor due to {}", e.getMessage());
  76 + return null;
  77 + }
  78 + }
  79 +
  80 + public DynamicSchema getDynamicSchema(ProtoFileElement protoFileElement, String schemaName) {
  81 + DynamicSchema.Builder schemaBuilder = DynamicSchema.newBuilder();
  82 + schemaBuilder.setName(schemaName);
  83 + schemaBuilder.setPackage(!isEmptyStr(protoFileElement.getPackageName()) ?
  84 + protoFileElement.getPackageName() : schemaName.toLowerCase());
  85 + List<TypeElement> types = protoFileElement.getTypes();
  86 + List<MessageElement> messageTypes = getMessageTypes(types);
  87 +
  88 + if (!messageTypes.isEmpty()) {
  89 + List<EnumElement> enumTypes = getEnumElements(types);
  90 + if (!enumTypes.isEmpty()) {
  91 + enumTypes.forEach(enumElement -> {
  92 + EnumDefinition enumDefinition = getEnumDefinition(enumElement);
  93 + schemaBuilder.addEnumDefinition(enumDefinition);
  94 + });
  95 + }
  96 + List<MessageDefinition> messageDefinitions = getMessageDefinitions(messageTypes);
  97 + messageDefinitions.forEach(schemaBuilder::addMessageDefinition);
  98 + try {
  99 + return schemaBuilder.build();
  100 + } catch (Descriptors.DescriptorValidationException e) {
  101 + throw new RuntimeException("Failed to create dynamic schema due to: " + e.getMessage());
  102 + }
  103 + } else {
  104 + throw new RuntimeException("Failed to get Dynamic Schema! Message types is empty for schema:" + schemaName);
  105 + }
  106 + }
  107 +
  108 + public ProtoFileElement getTransportProtoSchema(String protoSchema) {
  109 + return new ProtoParser(LOCATION, protoSchema.toCharArray()).readProtoFile();
  110 + }
  111 +
  112 + private List<MessageElement> getMessageTypes(List<TypeElement> types) {
  113 + return types.stream()
  114 + .filter(typeElement -> typeElement instanceof MessageElement)
  115 + .map(typeElement -> (MessageElement) typeElement)
  116 + .collect(Collectors.toList());
  117 + }
  118 +
  119 + private List<EnumElement> getEnumElements(List<TypeElement> types) {
  120 + return types.stream()
  121 + .filter(typeElement -> typeElement instanceof EnumElement)
  122 + .map(typeElement -> (EnumElement) typeElement)
  123 + .collect(Collectors.toList());
  124 + }
  125 +
  126 + private List<MessageDefinition> getMessageDefinitions(List<MessageElement> messageElementsList) {
  127 + if (!messageElementsList.isEmpty()) {
  128 + List<MessageDefinition> messageDefinitions = new ArrayList<>();
  129 + messageElementsList.forEach(messageElement -> {
  130 + MessageDefinition.Builder messageDefinitionBuilder = MessageDefinition.newBuilder(messageElement.getName());
  131 +
  132 + List<TypeElement> nestedTypes = messageElement.getNestedTypes();
  133 + if (!nestedTypes.isEmpty()) {
  134 + List<EnumElement> nestedEnumTypes = getEnumElements(nestedTypes);
  135 + if (!nestedEnumTypes.isEmpty()) {
  136 + nestedEnumTypes.forEach(enumElement -> {
  137 + EnumDefinition nestedEnumDefinition = getEnumDefinition(enumElement);
  138 + messageDefinitionBuilder.addEnumDefinition(nestedEnumDefinition);
  139 + });
  140 + }
  141 + List<MessageElement> nestedMessageTypes = getMessageTypes(nestedTypes);
  142 + List<MessageDefinition> nestedMessageDefinitions = getMessageDefinitions(nestedMessageTypes);
  143 + nestedMessageDefinitions.forEach(messageDefinitionBuilder::addMessageDefinition);
  144 + }
  145 + List<FieldElement> messageElementFields = messageElement.getFields();
  146 + List<OneOfElement> oneOfs = messageElement.getOneOfs();
  147 + if (!oneOfs.isEmpty()) {
  148 + for (OneOfElement oneOfelement : oneOfs) {
  149 + MessageDefinition.OneofBuilder oneofBuilder = messageDefinitionBuilder.addOneof(oneOfelement.getName());
  150 + addMessageFieldsToTheOneOfDefinition(oneOfelement.getFields(), oneofBuilder);
  151 + }
  152 + }
  153 + if (!messageElementFields.isEmpty()) {
  154 + addMessageFieldsToTheMessageDefinition(messageElementFields, messageDefinitionBuilder);
  155 + }
  156 + messageDefinitions.add(messageDefinitionBuilder.build());
  157 + });
  158 + return messageDefinitions;
  159 + } else {
  160 + return Collections.emptyList();
  161 + }
  162 + }
  163 +
  164 + private EnumDefinition getEnumDefinition(EnumElement enumElement) {
  165 + List<EnumConstantElement> enumElementTypeConstants = enumElement.getConstants();
  166 + EnumDefinition.Builder enumDefinitionBuilder = EnumDefinition.newBuilder(enumElement.getName());
  167 + if (!enumElementTypeConstants.isEmpty()) {
  168 + enumElementTypeConstants.forEach(constantElement -> enumDefinitionBuilder.addValue(constantElement.getName(), constantElement.getTag()));
  169 + }
  170 + return enumDefinitionBuilder.build();
  171 + }
  172 +
  173 +
  174 + private void addMessageFieldsToTheMessageDefinition(List<FieldElement> messageElementFields, MessageDefinition.Builder messageDefinitionBuilder) {
  175 + messageElementFields.forEach(fieldElement -> {
  176 + String labelStr = null;
  177 + if (fieldElement.getLabel() != null) {
  178 + labelStr = fieldElement.getLabel().name().toLowerCase();
  179 + }
  180 + messageDefinitionBuilder.addField(
  181 + labelStr,
  182 + fieldElement.getType(),
  183 + fieldElement.getName(),
  184 + fieldElement.getTag());
  185 + });
  186 + }
  187 +
  188 + private void addMessageFieldsToTheOneOfDefinition(List<FieldElement> oneOfsElementFields, MessageDefinition.OneofBuilder oneofBuilder) {
  189 + oneOfsElementFields.forEach(fieldElement -> oneofBuilder.addField(
  190 + fieldElement.getType(),
  191 + fieldElement.getName(),
  192 + fieldElement.getTag()));
  193 + oneofBuilder.msgDefBuilder();
  194 + }
  195 +
  196 + private boolean isEmptyStr(String str) {
  197 + return str == null || "".equals(str);
  198 + }
  199 +
  200 +}
  1 +/**
  2 + * Copyright © 2016-2020 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.TransportPayloadType;
  23 +
  24 +@JsonIgnoreProperties(ignoreUnknown = true)
  25 +@JsonTypeInfo(
  26 + use = JsonTypeInfo.Id.NAME,
  27 + include = JsonTypeInfo.As.PROPERTY,
  28 + property = "transportPayloadType")
  29 +@JsonSubTypes({
  30 + @JsonSubTypes.Type(value = JsonTransportPayloadConfiguration.class, name = "JSON"),
  31 + @JsonSubTypes.Type(value = ProtoTransportPayloadConfiguration.class, name = "PROTOBUF")})
  32 +public interface TransportPayloadTypeConfiguration {
  33 +
  34 + @JsonIgnore
  35 + TransportPayloadType getTransportPayloadType();
  36 +
  37 +}
@@ -15,7 +15,11 @@ @@ -15,7 +15,11 @@
15 */ 15 */
16 package org.thingsboard.server.transport.mqtt.adaptors; 16 package org.thingsboard.server.transport.mqtt.adaptors;
17 17
  18 +import com.google.gson.JsonParser;
  19 +import com.google.protobuf.Descriptors;
  20 +import com.google.protobuf.DynamicMessage;
18 import com.google.protobuf.InvalidProtocolBufferException; 21 import com.google.protobuf.InvalidProtocolBufferException;
  22 +import com.google.protobuf.util.JsonFormat;
19 import io.netty.buffer.ByteBuf; 23 import io.netty.buffer.ByteBuf;
20 import io.netty.buffer.ByteBufAllocator; 24 import io.netty.buffer.ByteBufAllocator;
21 import io.netty.buffer.UnpooledByteBufAllocator; 25 import io.netty.buffer.UnpooledByteBufAllocator;
@@ -29,10 +33,11 @@ import org.springframework.stereotype.Component; @@ -29,10 +33,11 @@ import org.springframework.stereotype.Component;
29 import org.springframework.util.StringUtils; 33 import org.springframework.util.StringUtils;
30 import org.thingsboard.server.common.data.device.profile.MqttTopics; 34 import org.thingsboard.server.common.data.device.profile.MqttTopics;
31 import org.thingsboard.server.common.transport.adaptor.AdaptorException; 35 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
  36 +import org.thingsboard.server.common.transport.adaptor.JsonConverter;
32 import org.thingsboard.server.common.transport.adaptor.ProtoConverter; 37 import org.thingsboard.server.common.transport.adaptor.ProtoConverter;
33 import org.thingsboard.server.gen.transport.TransportApiProtos; 38 import org.thingsboard.server.gen.transport.TransportApiProtos;
34 import org.thingsboard.server.gen.transport.TransportProtos; 39 import org.thingsboard.server.gen.transport.TransportProtos;
35 -import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; 40 +import org.thingsboard.server.transport.mqtt.session.DeviceSessionCtx;
36 import org.thingsboard.server.transport.mqtt.session.MqttDeviceAwareSessionContext; 41 import org.thingsboard.server.transport.mqtt.session.MqttDeviceAwareSessionContext;
37 42
38 import java.util.Optional; 43 import java.util.Optional;
@@ -45,20 +50,24 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { @@ -45,20 +50,24 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor {
45 50
46 @Override 51 @Override
47 public TransportProtos.PostTelemetryMsg convertToPostTelemetry(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { 52 public TransportProtos.PostTelemetryMsg convertToPostTelemetry(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException {
  53 + DeviceSessionCtx deviceSessionCtx = (DeviceSessionCtx) ctx;
48 byte[] bytes = toBytes(inbound.payload()); 54 byte[] bytes = toBytes(inbound.payload());
  55 + Descriptors.Descriptor telemetryDynamicMsgDescriptor = getDescriptor(deviceSessionCtx.getTelemetryDynamicMsgDescriptor());
49 try { 56 try {
50 - return ProtoConverter.convertToTelemetryProto(bytes);  
51 - } catch (InvalidProtocolBufferException | IllegalArgumentException e) { 57 + return JsonConverter.convertToTelemetryProto(new JsonParser().parse(dynamicMsgToJson(bytes, telemetryDynamicMsgDescriptor)));
  58 + } catch (Exception e) {
52 throw new AdaptorException(e); 59 throw new AdaptorException(e);
53 } 60 }
54 } 61 }
55 62
56 @Override 63 @Override
57 public TransportProtos.PostAttributeMsg convertToPostAttributes(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { 64 public TransportProtos.PostAttributeMsg convertToPostAttributes(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException {
  65 + DeviceSessionCtx deviceSessionCtx = (DeviceSessionCtx) ctx;
58 byte[] bytes = toBytes(inbound.payload()); 66 byte[] bytes = toBytes(inbound.payload());
  67 + Descriptors.Descriptor attributesDynamicMessage = getDescriptor(deviceSessionCtx.getAttributesDynamicMessageDescriptor());
59 try { 68 try {
60 - return ProtoConverter.validatePostAttributeMsg(bytes);  
61 - } catch (InvalidProtocolBufferException | IllegalArgumentException e) { 69 + return JsonConverter.convertToAttributesProto(new JsonParser().parse(dynamicMsgToJson(bytes, attributesDynamicMessage)));
  70 + } catch (Exception e) {
62 throw new AdaptorException(e); 71 throw new AdaptorException(e);
63 } 72 }
64 } 73 }
@@ -112,7 +121,6 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { @@ -112,7 +121,6 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor {
112 @Override 121 @Override
113 public TransportProtos.ProvisionDeviceRequestMsg convertToProvisionRequestMsg(MqttDeviceAwareSessionContext ctx, MqttPublishMessage mqttMsg) throws AdaptorException { 122 public TransportProtos.ProvisionDeviceRequestMsg convertToProvisionRequestMsg(MqttDeviceAwareSessionContext ctx, MqttPublishMessage mqttMsg) throws AdaptorException {
114 byte[] bytes = toBytes(mqttMsg.payload()); 123 byte[] bytes = toBytes(mqttMsg.payload());
115 - String topicName = mqttMsg.variableHeader().topicName();  
116 try { 124 try {
117 return ProtoConverter.convertToProvisionRequestMsg(bytes); 125 return ProtoConverter.convertToProvisionRequestMsg(bytes);
118 } catch (InvalidProtocolBufferException ex) { 126 } catch (InvalidProtocolBufferException ex) {
@@ -207,4 +215,16 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { @@ -207,4 +215,16 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor {
207 return Integer.parseInt(topicName.substring(topic.length())); 215 return Integer.parseInt(topicName.substring(topic.length()));
208 } 216 }
209 217
  218 + private Descriptors.Descriptor getDescriptor(Descriptors.Descriptor descriptor) throws AdaptorException {
  219 + if (descriptor == null) {
  220 + throw new AdaptorException("Failed to get dynamic message descriptor!");
  221 + }
  222 + return descriptor;
  223 + }
  224 +
  225 + private String dynamicMsgToJson(byte[] bytes, Descriptors.Descriptor descriptor) throws InvalidProtocolBufferException {
  226 + DynamicMessage dynamicMessage = DynamicMessage.parseFrom(descriptor, bytes);
  227 + return JsonFormat.printer().includingDefaultValueFields().print(dynamicMessage);
  228 + }
  229 +
210 } 230 }
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.transport.mqtt.session; 16 package org.thingsboard.server.transport.mqtt.session;
17 17
  18 +import com.google.protobuf.Descriptors;
18 import io.netty.channel.ChannelHandlerContext; 19 import io.netty.channel.ChannelHandlerContext;
19 import lombok.Getter; 20 import lombok.Getter;
20 import lombok.Setter; 21 import lombok.Setter;
@@ -24,6 +25,8 @@ import org.thingsboard.server.common.data.DeviceTransportType; @@ -24,6 +25,8 @@ import org.thingsboard.server.common.data.DeviceTransportType;
24 import org.thingsboard.server.common.data.TransportPayloadType; 25 import org.thingsboard.server.common.data.TransportPayloadType;
25 import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; 26 import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
26 import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; 27 import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  28 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  29 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
27 import org.thingsboard.server.transport.mqtt.MqttTransportContext; 30 import org.thingsboard.server.transport.mqtt.MqttTransportContext;
28 import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor; 31 import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor;
29 import org.thingsboard.server.transport.mqtt.util.MqttTopicFilter; 32 import org.thingsboard.server.transport.mqtt.util.MqttTopicFilter;
@@ -54,6 +57,8 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { @@ -54,6 +57,8 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext {
54 private volatile MqttTopicFilter telemetryTopicFilter = MqttTopicFilterFactory.getDefaultTelemetryFilter(); 57 private volatile MqttTopicFilter telemetryTopicFilter = MqttTopicFilterFactory.getDefaultTelemetryFilter();
55 private volatile MqttTopicFilter attributesTopicFilter = MqttTopicFilterFactory.getDefaultAttributesFilter(); 58 private volatile MqttTopicFilter attributesTopicFilter = MqttTopicFilterFactory.getDefaultAttributesFilter();
56 private volatile TransportPayloadType payloadType = TransportPayloadType.JSON; 59 private volatile TransportPayloadType payloadType = TransportPayloadType.JSON;
  60 + private volatile Descriptors.Descriptor attributesDynamicMessageDescriptor;
  61 + private volatile Descriptors.Descriptor telemetryDynamicMessageDescriptor;
57 62
58 @Getter 63 @Getter
59 @Setter 64 @Setter
@@ -72,7 +77,9 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { @@ -72,7 +77,9 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext {
72 return msgIdSeq.incrementAndGet(); 77 return msgIdSeq.incrementAndGet();
73 } 78 }
74 79
75 - public boolean isDeviceTelemetryTopic(String topicName) { return telemetryTopicFilter.filter(topicName); } 80 + public boolean isDeviceTelemetryTopic(String topicName) {
  81 + return telemetryTopicFilter.filter(topicName);
  82 + }
76 83
77 public boolean isDeviceAttributesTopic(String topicName) { 84 public boolean isDeviceAttributesTopic(String topicName) {
78 return attributesTopicFilter.filter(topicName); 85 return attributesTopicFilter.filter(topicName);
@@ -86,6 +93,14 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { @@ -86,6 +93,14 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext {
86 return payloadType.equals(TransportPayloadType.JSON); 93 return payloadType.equals(TransportPayloadType.JSON);
87 } 94 }
88 95
  96 + public Descriptors.Descriptor getTelemetryDynamicMsgDescriptor() {
  97 + return telemetryDynamicMessageDescriptor;
  98 + }
  99 +
  100 + public Descriptors.Descriptor getAttributesDynamicMessageDescriptor() {
  101 + return attributesDynamicMessageDescriptor;
  102 + }
  103 +
89 @Override 104 @Override
90 public void setDeviceProfile(DeviceProfile deviceProfile) { 105 public void setDeviceProfile(DeviceProfile deviceProfile) {
91 super.setDeviceProfile(deviceProfile); 106 super.setDeviceProfile(deviceProfile);
@@ -104,13 +119,22 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { @@ -104,13 +119,22 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext {
104 if (transportConfiguration.getType().equals(DeviceTransportType.MQTT) && 119 if (transportConfiguration.getType().equals(DeviceTransportType.MQTT) &&
105 transportConfiguration instanceof MqttDeviceProfileTransportConfiguration) { 120 transportConfiguration instanceof MqttDeviceProfileTransportConfiguration) {
106 MqttDeviceProfileTransportConfiguration mqttConfig = (MqttDeviceProfileTransportConfiguration) transportConfiguration; 121 MqttDeviceProfileTransportConfiguration mqttConfig = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
107 - payloadType = mqttConfig.getTransportPayloadType(); 122 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttConfig.getTransportPayloadTypeConfiguration();
  123 + payloadType = transportPayloadTypeConfiguration.getTransportPayloadType();
108 telemetryTopicFilter = MqttTopicFilterFactory.toFilter(mqttConfig.getDeviceTelemetryTopic()); 124 telemetryTopicFilter = MqttTopicFilterFactory.toFilter(mqttConfig.getDeviceTelemetryTopic());
109 attributesTopicFilter = MqttTopicFilterFactory.toFilter(mqttConfig.getDeviceAttributesTopic()); 125 attributesTopicFilter = MqttTopicFilterFactory.toFilter(mqttConfig.getDeviceAttributesTopic());
  126 + if (TransportPayloadType.PROTOBUF.equals(payloadType)) {
  127 + updateDynamicMessageDescriptors(transportPayloadTypeConfiguration);
  128 + }
110 } else { 129 } else {
111 telemetryTopicFilter = MqttTopicFilterFactory.getDefaultTelemetryFilter(); 130 telemetryTopicFilter = MqttTopicFilterFactory.getDefaultTelemetryFilter();
112 attributesTopicFilter = MqttTopicFilterFactory.getDefaultAttributesFilter(); 131 attributesTopicFilter = MqttTopicFilterFactory.getDefaultAttributesFilter();
113 } 132 }
114 } 133 }
115 134
  135 + private void updateDynamicMessageDescriptors(TransportPayloadTypeConfiguration transportPayloadTypeConfiguration) {
  136 + ProtoTransportPayloadConfiguration protoTransportPayloadConfig = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  137 + telemetryDynamicMessageDescriptor = protoTransportPayloadConfig.getTelemetryDynamicMessageDescriptor(protoTransportPayloadConfig.getDeviceTelemetryProtoSchema());
  138 + attributesDynamicMessageDescriptor = protoTransportPayloadConfig.getAttributesDynamicMessageDescriptor(protoTransportPayloadConfig.getDeviceAttributesProtoSchema());
  139 + }
116 } 140 }
@@ -213,13 +213,7 @@ public class JsonConverter { @@ -213,13 +213,7 @@ public class JsonConverter {
213 throw new JsonSyntaxException(CAN_T_PARSE_VALUE + value); 213 throw new JsonSyntaxException(CAN_T_PARSE_VALUE + value);
214 } 214 }
215 } else if (element.isJsonObject() || element.isJsonArray()) { 215 } else if (element.isJsonObject() || element.isJsonArray()) {
216 - result.add(KeyValueProto  
217 - .newBuilder()  
218 - .setKey(valueEntry  
219 - .getKey())  
220 - .setType(KeyValueType.JSON_V)  
221 - .setJsonV(element.toString())  
222 - .build()); 216 + result.add(KeyValueProto.newBuilder().setKey(valueEntry.getKey()).setType(KeyValueType.JSON_V).setJsonV(element.toString()).build());
223 } else if (!element.isJsonNull()) { 217 } else if (!element.isJsonNull()) {
224 throw new JsonSyntaxException(CAN_T_PARSE_VALUE + element); 218 throw new JsonSyntaxException(CAN_T_PARSE_VALUE + element);
225 } 219 }
@@ -15,6 +15,16 @@ @@ -15,6 +15,16 @@
15 */ 15 */
16 package org.thingsboard.server.dao.device; 16 package org.thingsboard.server.dao.device;
17 17
  18 +import com.squareup.wire.Syntax;
  19 +import com.squareup.wire.schema.Field;
  20 +import com.squareup.wire.schema.Location;
  21 +import com.squareup.wire.schema.internal.parser.EnumElement;
  22 +import com.squareup.wire.schema.internal.parser.FieldElement;
  23 +import com.squareup.wire.schema.internal.parser.MessageElement;
  24 +import com.squareup.wire.schema.internal.parser.OneOfElement;
  25 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
  26 +import com.squareup.wire.schema.internal.parser.ProtoParser;
  27 +import com.squareup.wire.schema.internal.parser.TypeElement;
18 import lombok.extern.slf4j.Slf4j; 28 import lombok.extern.slf4j.Slf4j;
19 import org.apache.commons.lang3.StringUtils; 29 import org.apache.commons.lang3.StringUtils;
20 import org.hibernate.exception.ConstraintViolationException; 30 import org.hibernate.exception.ConstraintViolationException;
@@ -35,7 +45,10 @@ import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileCon @@ -35,7 +45,10 @@ import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileCon
35 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration; 45 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration;
36 import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; 46 import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm;
37 import org.thingsboard.server.common.data.device.profile.DeviceProfileData; 47 import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
  48 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
38 import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration; 49 import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration;
  50 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  51 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
39 import org.thingsboard.server.common.data.id.DeviceProfileId; 52 import org.thingsboard.server.common.data.id.DeviceProfileId;
40 import org.thingsboard.server.common.data.id.TenantId; 53 import org.thingsboard.server.common.data.id.TenantId;
41 import org.thingsboard.server.common.data.page.PageData; 54 import org.thingsboard.server.common.data.page.PageData;
@@ -51,6 +64,7 @@ import java.util.Arrays; @@ -51,6 +64,7 @@ import java.util.Arrays;
51 import java.util.Collections; 64 import java.util.Collections;
52 import java.util.HashSet; 65 import java.util.HashSet;
53 import java.util.List; 66 import java.util.List;
  67 +import java.util.stream.Collectors;
54 import java.util.Set; 68 import java.util.Set;
55 69
56 import static org.thingsboard.server.common.data.CacheConstants.DEVICE_PROFILE_CACHE; 70 import static org.thingsboard.server.common.data.CacheConstants.DEVICE_PROFILE_CACHE;
@@ -64,6 +78,14 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -64,6 +78,14 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
64 private static final String INCORRECT_DEVICE_PROFILE_ID = "Incorrect deviceProfileId "; 78 private static final String INCORRECT_DEVICE_PROFILE_ID = "Incorrect deviceProfileId ";
65 private static final String INCORRECT_DEVICE_PROFILE_NAME = "Incorrect deviceProfileName "; 79 private static final String INCORRECT_DEVICE_PROFILE_NAME = "Incorrect deviceProfileName ";
66 80
  81 + private static final Location LOCATION = new Location("", "", -1, -1);
  82 + private static final String ATTRIBUTES_PROTO_SCHEMA = "attributes proto schema";
  83 + private static final String TELEMETRY_PROTO_SCHEMA = "telemetry proto schema";
  84 +
  85 + private static String invalidSchemaProvidedMessage(String schemaName) {
  86 + return "[Transport Configuration] invalid " + schemaName + " provided!";
  87 + }
  88 +
67 @Autowired 89 @Autowired
68 private DeviceProfileDao deviceProfileDao; 90 private DeviceProfileDao deviceProfileDao;
69 91
@@ -314,6 +336,22 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -314,6 +336,22 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
314 throw new DataValidationException("Another default device profile is present in scope of current tenant!"); 336 throw new DataValidationException("Another default device profile is present in scope of current tenant!");
315 } 337 }
316 } 338 }
  339 +
  340 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  341 + if (transportConfiguration instanceof MqttDeviceProfileTransportConfiguration) {
  342 + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
  343 + if (mqttTransportConfiguration.getTransportPayloadTypeConfiguration() instanceof ProtoTransportPayloadConfiguration) {
  344 + ProtoTransportPayloadConfiguration protoTransportPayloadTypeConfiguration =
  345 + (ProtoTransportPayloadConfiguration) mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
  346 + try {
  347 + validateTransportProtoSchema(protoTransportPayloadTypeConfiguration.getDeviceAttributesProtoSchema(), ATTRIBUTES_PROTO_SCHEMA);
  348 + validateTransportProtoSchema(protoTransportPayloadTypeConfiguration.getDeviceTelemetryProtoSchema(), TELEMETRY_PROTO_SCHEMA);
  349 + } catch (Exception exception) {
  350 + throw new DataValidationException(exception.getMessage());
  351 + }
  352 + }
  353 + }
  354 +
317 List<DeviceProfileAlarm> profileAlarms = deviceProfile.getProfileData().getAlarms(); 355 List<DeviceProfileAlarm> profileAlarms = deviceProfile.getProfileData().getAlarms();
318 356
319 if (!CollectionUtils.isEmpty(profileAlarms)) { 357 if (!CollectionUtils.isEmpty(profileAlarms)) {
@@ -327,8 +365,8 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -327,8 +365,8 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
327 throw new DataValidationException(String.format("Can't create device profile with the same alarm rule types: \"%s\"!", alarmType)); 365 throw new DataValidationException(String.format("Can't create device profile with the same alarm rule types: \"%s\"!", alarmType));
328 } 366 }
329 } 367 }
330 -  
331 } 368 }
  369 +
332 } 370 }
333 371
334 @Override 372 @Override
@@ -352,6 +390,122 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -352,6 +390,122 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
352 } 390 }
353 } 391 }
354 } 392 }
  393 +
  394 + private void validateTransportProtoSchema(String schema, String schemaName) throws IllegalArgumentException {
  395 + ProtoParser schemaParser = new ProtoParser(LOCATION, schema.toCharArray());
  396 + ProtoFileElement protoFileElement;
  397 + try {
  398 + protoFileElement = schemaParser.readProtoFile();
  399 + } catch (Exception e) {
  400 + throw new IllegalArgumentException("[Transport Configuration] failed to parse " + schemaName + " due to: " + e.getMessage());
  401 + }
  402 + checkProtoFileSyntax(schemaName, protoFileElement);
  403 + checkProtoFileCommonSettings(schemaName, protoFileElement.getOptions().isEmpty(), " Schema options don't support!");
  404 + checkProtoFileCommonSettings(schemaName, protoFileElement.getPublicImports().isEmpty(), " Schema public imports don't support!");
  405 + checkProtoFileCommonSettings(schemaName, protoFileElement.getImports().isEmpty(), " Schema imports don't support!");
  406 + checkProtoFileCommonSettings(schemaName, protoFileElement.getExtendDeclarations().isEmpty(), " Schema extend declarations don't support!");
  407 + checkTypeElements(schemaName, protoFileElement);
  408 + }
  409 +
  410 + private void checkProtoFileSyntax(String schemaName, ProtoFileElement protoFileElement) {
  411 + if (protoFileElement.getSyntax() == null || !protoFileElement.getSyntax().equals(Syntax.PROTO_3)) {
  412 + throw new IllegalArgumentException("[Transport Configuration] invalid schema syntax: " + protoFileElement.getSyntax() +
  413 + " for " + schemaName + " provided! Only " + Syntax.PROTO_3 + " allowed!");
  414 + }
  415 + }
  416 +
  417 + private void checkProtoFileCommonSettings(String schemaName, boolean isEmptySettings, String invalidSettingsMessage) {
  418 + if (!isEmptySettings) {
  419 + throw new IllegalArgumentException(invalidSchemaProvidedMessage(schemaName) + invalidSettingsMessage);
  420 + }
  421 + }
  422 +
  423 + private void checkTypeElements(String schemaName, ProtoFileElement protoFileElement) {
  424 + List<TypeElement> types = protoFileElement.getTypes();
  425 + if (!types.isEmpty()) {
  426 + if (types.stream().noneMatch(typeElement -> typeElement instanceof MessageElement)) {
  427 + throw new IllegalArgumentException(invalidSchemaProvidedMessage(schemaName) + " At least one Message definition should exists!");
  428 + } else {
  429 + checkEnumElements(schemaName, getEnumElements(types));
  430 + checkMessageElements(schemaName, getMessageTypes(types));
  431 + }
  432 + } else {
  433 + throw new IllegalArgumentException(invalidSchemaProvidedMessage(schemaName) + " Type elements is empty!");
  434 + }
  435 + }
  436 +
  437 + private void checkFieldElements(String schemaName, List<FieldElement> fieldElements) {
  438 + if (!fieldElements.isEmpty()) {
  439 + boolean hasRequiredLabel = fieldElements.stream().anyMatch(fieldElement -> {
  440 + Field.Label label = fieldElement.getLabel();
  441 + return label != null && label.equals(Field.Label.REQUIRED);
  442 + });
  443 + if (hasRequiredLabel) {
  444 + throw new IllegalArgumentException(invalidSchemaProvidedMessage(schemaName) + " Required labels are not supported!");
  445 + }
  446 + boolean hasDefaultValue = fieldElements.stream().anyMatch(fieldElement -> fieldElement.getDefaultValue() != null);
  447 + if (hasDefaultValue) {
  448 + throw new IllegalArgumentException(invalidSchemaProvidedMessage(schemaName) + " Default values are not supported!");
  449 + }
  450 + }
  451 + }
  452 +
  453 + private void checkEnumElements(String schemaName, List<EnumElement> enumTypes) {
  454 + if (enumTypes.stream().anyMatch(enumElement -> !enumElement.getNestedTypes().isEmpty())) {
  455 + throw new IllegalArgumentException(invalidSchemaProvidedMessage(schemaName) + " Nested types in Enum definitions are not supported!");
  456 + }
  457 + if (enumTypes.stream().anyMatch(enumElement -> !enumElement.getOptions().isEmpty())) {
  458 + throw new IllegalArgumentException(invalidSchemaProvidedMessage(schemaName) + " Enum definitions options are not supported!");
  459 + }
  460 + }
  461 +
  462 + private void checkMessageElements(String schemaName, List<MessageElement> messageElementsList) {
  463 + if (!messageElementsList.isEmpty()) {
  464 + messageElementsList.forEach(messageElement -> {
  465 + checkProtoFileCommonSettings(schemaName, messageElement.getGroups().isEmpty(),
  466 + " Message definition groups don't support!");
  467 + checkProtoFileCommonSettings(schemaName, messageElement.getOptions().isEmpty(),
  468 + " Message definition options don't support!");
  469 + checkProtoFileCommonSettings(schemaName, messageElement.getExtensions().isEmpty(),
  470 + " Message definition extensions don't support!");
  471 + checkProtoFileCommonSettings(schemaName, messageElement.getReserveds().isEmpty(),
  472 + " Message definition reserved elements don't support!");
  473 + checkFieldElements(schemaName, messageElement.getFields());
  474 + List<OneOfElement> oneOfs = messageElement.getOneOfs();
  475 + if (!oneOfs.isEmpty()) {
  476 + oneOfs.forEach(oneOfElement -> {
  477 + checkProtoFileCommonSettings(schemaName, oneOfElement.getGroups().isEmpty(),
  478 + " OneOf definition groups don't support!");
  479 + checkFieldElements(schemaName, oneOfElement.getFields());
  480 + });
  481 + }
  482 + List<TypeElement> nestedTypes = messageElement.getNestedTypes();
  483 + if (!nestedTypes.isEmpty()) {
  484 + List<EnumElement> nestedEnumTypes = getEnumElements(nestedTypes);
  485 + if (!nestedEnumTypes.isEmpty()) {
  486 + checkEnumElements(schemaName, nestedEnumTypes);
  487 + }
  488 + List<MessageElement> nestedMessageTypes = getMessageTypes(nestedTypes);
  489 + checkMessageElements(schemaName, nestedMessageTypes);
  490 + }
  491 + });
  492 + }
  493 + }
  494 +
  495 + private List<MessageElement> getMessageTypes(List<TypeElement> types) {
  496 + return types.stream()
  497 + .filter(typeElement -> typeElement instanceof MessageElement)
  498 + .map(typeElement -> (MessageElement) typeElement)
  499 + .collect(Collectors.toList());
  500 + }
  501 +
  502 + private List<EnumElement> getEnumElements(List<TypeElement> types) {
  503 + return types.stream()
  504 + .filter(typeElement -> typeElement instanceof EnumElement)
  505 + .map(typeElement -> (EnumElement) typeElement)
  506 + .collect(Collectors.toList());
  507 + }
  508 +
355 }; 509 };
356 510
357 private PaginatedRemover<TenantId, DeviceProfile> tenantDeviceProfilesRemover = 511 private PaginatedRemover<TenantId, DeviceProfile> tenantDeviceProfilesRemover =
@@ -106,6 +106,8 @@ @@ -106,6 +106,8 @@
106 <commons-collections.version>3.2.2</commons-collections.version> 106 <commons-collections.version>3.2.2</commons-collections.version>
107 <java-websocket.version>1.5.0</java-websocket.version> 107 <java-websocket.version>1.5.0</java-websocket.version>
108 <micrometer.version>1.5.2</micrometer.version> 108 <micrometer.version>1.5.2</micrometer.version>
  109 + <protobuf-dynamic.version>1.0.2TB</protobuf-dynamic.version>
  110 + <wire-schema.version>3.4.0</wire-schema.version>
109 </properties> 111 </properties>
110 112
111 <modules> 113 <modules>
@@ -1369,6 +1371,16 @@ @@ -1369,6 +1371,16 @@
1369 <artifactId>micrometer-registry-prometheus</artifactId> 1371 <artifactId>micrometer-registry-prometheus</artifactId>
1370 <version>${micrometer.version}</version> 1372 <version>${micrometer.version}</version>
1371 </dependency> 1373 </dependency>
  1374 + <dependency>
  1375 + <groupId>org.thingsboard</groupId>
  1376 + <artifactId>protobuf-dynamic</artifactId>
  1377 + <version>${protobuf-dynamic.version}</version>
  1378 + </dependency>
  1379 + <dependency>
  1380 + <groupId>com.squareup.wire</groupId>
  1381 + <artifactId>wire-schema</artifactId>
  1382 + <version>${wire-schema.version}</version>
  1383 + </dependency>
1372 </dependencies> 1384 </dependencies>
1373 </dependencyManagement> 1385 </dependencyManagement>
1374 1386
@@ -20,17 +20,6 @@ @@ -20,17 +20,6 @@
20 <fieldset class="fields-group"> 20 <fieldset class="fields-group">
21 <legend class="group-title" translate>device-profile.mqtt-device-topic-filters</legend> 21 <legend class="group-title" translate>device-profile.mqtt-device-topic-filters</legend>
22 <div fxLayoutGap="8px" fxLayout="column"> 22 <div fxLayoutGap="8px" fxLayout="column">
23 - <mat-form-field class="mat-block">  
24 - <mat-label translate>device-profile.mqtt-device-payload-type</mat-label>  
25 - <mat-select formControlName="transportPayloadType" required>  
26 - <mat-option *ngFor="let type of mqttTransportPayloadTypes" [value]="type">  
27 - {{mqttTransportPayloadTypeTranslations.get(type) | translate}}  
28 - </mat-option>  
29 - </mat-select>  
30 - <mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.transportPayloadType').hasError('required')">  
31 - {{ 'device-profile.mqtt-payload-type-required' | translate }}  
32 - </mat-error>  
33 - </mat-form-field>  
34 <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"> 23 <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column">
35 <mat-form-field fxFlex> 24 <mat-form-field fxFlex>
36 <mat-label translate>device-profile.telemetry-topic-filter</mat-label> 25 <mat-label translate>device-profile.telemetry-topic-filter</mat-label>
@@ -71,5 +60,42 @@ @@ -71,5 +60,42 @@
71 <div class="tb-hint" innerHTML="{{ 'device-profile.multi-level-wildcards-hint' | translate }}"></div> 60 <div class="tb-hint" innerHTML="{{ 'device-profile.multi-level-wildcards-hint' | translate }}"></div>
72 </div> 61 </div>
73 </fieldset> 62 </fieldset>
  63 + <section formGroupName="transportPayloadTypeConfiguration">
  64 + <fieldset class="fields-group">
  65 + <legend class="group-title" translate>device-profile.mqtt-device-payload-type</legend>
  66 + <div fxLayoutGap="8px" fxLayout="column">
  67 + <mat-form-field class="mat-block">
  68 + <mat-select formControlName="transportPayloadType" required>
  69 + <mat-option *ngFor="let type of mqttTransportPayloadTypes" [value]="type">
  70 + {{mqttTransportPayloadTypeTranslations.get(type) | translate}}
  71 + </mat-option>
  72 + </mat-select>
  73 + <mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.transportPayloadTypeConfiguration.transportPayloadType').hasError('required')">
  74 + {{ 'device-profile.mqtt-payload-type-required' | translate }}
  75 + </mat-error>
  76 + </mat-form-field>
  77 + <div *ngIf="protoPayloadType" fxLayout="column">
  78 + <mat-form-field fxFlex>
  79 + <mat-label translate>device-profile.telemetry-proto-schema</mat-label>
  80 + <textarea matInput required
  81 + formControlName="deviceTelemetryProtoSchema"
  82 + rows="5"></textarea>
  83 + <mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.transportPayloadTypeConfiguration.deviceTelemetryProtoSchema').hasError('required')">
  84 + {{ 'device-profile.telemetry-proto-schema-required' | translate}}
  85 + </mat-error>
  86 + </mat-form-field>
  87 + <mat-form-field fxFlex>
  88 + <mat-label translate>device-profile.attributes-proto-schema</mat-label>
  89 + <textarea matInput required
  90 + formControlName="deviceAttributesProtoSchema"
  91 + rows="5"></textarea>
  92 + <mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.transportPayloadTypeConfiguration.deviceAttributesProtoSchema').hasError('required')">
  93 + {{ 'device-profile.attributes-proto-schema-required' | translate}}
  94 + </mat-error>
  95 + </mat-form-field>
  96 + </div>
  97 + </div>
  98 + </fieldset>
  99 + </section>
74 </section> 100 </section>
75 </form> 101 </form>
@@ -28,10 +28,11 @@ import { Store } from '@ngrx/store'; @@ -28,10 +28,11 @@ import { Store } from '@ngrx/store';
28 import { AppState } from '@app/core/core.state'; 28 import { AppState } from '@app/core/core.state';
29 import { coerceBooleanProperty } from '@angular/cdk/coercion'; 29 import { coerceBooleanProperty } from '@angular/cdk/coercion';
30 import { 30 import {
31 - MqttTransportPayloadType,  
32 DeviceProfileTransportConfiguration, 31 DeviceProfileTransportConfiguration,
33 DeviceTransportType, 32 DeviceTransportType,
34 - MqttDeviceProfileTransportConfiguration, mqttTransportPayloadTypeTranslationMap 33 + MqttDeviceProfileTransportConfiguration,
  34 + MqttTransportPayloadType,
  35 + mqttTransportPayloadTypeTranslationMap
35 } from '@shared/models/device.models'; 36 } from '@shared/models/device.models';
36 import { isDefinedAndNotNull } from '@core/utils'; 37 import { isDefinedAndNotNull } from '@core/utils';
37 38
@@ -85,9 +86,15 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control @@ -85,9 +86,15 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
85 configuration: this.fb.group({ 86 configuration: this.fb.group({
86 deviceAttributesTopic: [null, [Validators.required, this.validationMQTTTopic()]], 87 deviceAttributesTopic: [null, [Validators.required, this.validationMQTTTopic()]],
87 deviceTelemetryTopic: [null, [Validators.required, this.validationMQTTTopic()]], 88 deviceTelemetryTopic: [null, [Validators.required, this.validationMQTTTopic()]],
88 - transportPayloadType: [MqttTransportPayloadType.JSON, Validators.required] 89 + transportPayloadTypeConfiguration: this.fb.group({
  90 + transportPayloadType: [MqttTransportPayloadType.JSON, Validators.required]
  91 + })
89 }, {validator: this.uniqueDeviceTopicValidator}) 92 }, {validator: this.uniqueDeviceTopicValidator})
90 }); 93 });
  94 + this.mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.transportPayloadTypeConfiguration.transportPayloadType').valueChanges.subscribe(payloadType => {
  95 + this.updateTransportPayloadBasedControls(payloadType);
  96 + this.mqttDeviceProfileTransportConfigurationFormGroup.updateValueAndValidity();
  97 + });
91 this.mqttDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => { 98 this.mqttDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => {
92 this.updateModel(); 99 this.updateModel();
93 }); 100 });
@@ -102,8 +109,14 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control @@ -102,8 +109,14 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
102 } 109 }
103 } 110 }
104 111
  112 + get protoPayloadType(): boolean {
  113 + let transportPayloadType = this.mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.transportPayloadTypeConfiguration.transportPayloadType').value;
  114 + return transportPayloadType === MqttTransportPayloadType.PROTOBUF;
  115 + }
  116 +
105 writeValue(value: MqttDeviceProfileTransportConfiguration | null): void { 117 writeValue(value: MqttDeviceProfileTransportConfiguration | null): void {
106 if (isDefinedAndNotNull(value)) { 118 if (isDefinedAndNotNull(value)) {
  119 + this.updateTransportPayloadBasedControls(value.transportPayloadTypeConfiguration.transportPayloadType);
107 this.mqttDeviceProfileTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false}); 120 this.mqttDeviceProfileTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false});
108 } 121 }
109 } 122 }
@@ -117,6 +130,41 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control @@ -117,6 +130,41 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
117 this.propagateChange(configuration); 130 this.propagateChange(configuration);
118 } 131 }
119 132
  133 + private updateTransportPayloadBasedControls(type: MqttTransportPayloadType) {
  134 + const transportPayloadTypeConfigurationFormGroup = this.mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.transportPayloadTypeConfiguration') as FormGroup;
  135 + if (type === MqttTransportPayloadType.PROTOBUF) {
  136 + const defaultTelemetrySchema = "syntax =\"proto3\";\n" +
  137 + "package telemetry;\n" +
  138 + "\n" +
  139 + "message SensorDataReading {\n" +
  140 + "\n" +
  141 + " double temperature = 1;\n" +
  142 + " double humidity = 2;\n" +
  143 + " InnerObject innerObject = 3;\n" +
  144 + "\n" +
  145 + " message InnerObject {\n" +
  146 + " string key1 = 1;\n" +
  147 + " bool key2 = 2;\n" +
  148 + " double key3 = 3;\n" +
  149 + " int32 key4 = 4;\n" +
  150 + " string key5 = 5;\n" +
  151 + " }\n" +
  152 + "}\n";
  153 + const defaultAttributesSchema = "syntax =\"proto3\";\n" +
  154 + "package attributes;\n" +
  155 + "\n" +
  156 + "message SensorConfiguration {\n" +
  157 + " string firmwareVersion = 1;\n" +
  158 + " string serialNumber = 2;\n" +
  159 + "}";
  160 + transportPayloadTypeConfigurationFormGroup.registerControl('deviceTelemetryProtoSchema', this.fb.control(defaultTelemetrySchema, Validators.required));
  161 + transportPayloadTypeConfigurationFormGroup.registerControl('deviceAttributesProtoSchema', this.fb.control(defaultAttributesSchema, Validators.required));
  162 + } else {
  163 + transportPayloadTypeConfigurationFormGroup.removeControl('deviceTelemetryProtoSchema');
  164 + transportPayloadTypeConfigurationFormGroup.removeControl('deviceAttributesProtoSchema');
  165 + }
  166 + }
  167 +
120 private validationMQTTTopic(): ValidatorFn { 168 private validationMQTTTopic(): ValidatorFn {
121 return (c: FormControl) => { 169 return (c: FormControl) => {
122 const newTopic = c.value; 170 const newTopic = c.value;
@@ -148,6 +148,9 @@ export interface DefaultDeviceProfileTransportConfiguration { @@ -148,6 +148,9 @@ export interface DefaultDeviceProfileTransportConfiguration {
148 export interface MqttDeviceProfileTransportConfiguration { 148 export interface MqttDeviceProfileTransportConfiguration {
149 deviceTelemetryTopic?: string; 149 deviceTelemetryTopic?: string;
150 deviceAttributesTopic?: string; 150 deviceAttributesTopic?: string;
  151 + transportPayloadTypeConfiguration?: {
  152 + transportPayloadType?: MqttTransportPayloadType;
  153 + };
151 [key: string]: any; 154 [key: string]: any;
152 } 155 }
153 156
@@ -207,7 +210,7 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT @@ -207,7 +210,7 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT
207 const mqttTransportConfiguration: MqttDeviceProfileTransportConfiguration = { 210 const mqttTransportConfiguration: MqttDeviceProfileTransportConfiguration = {
208 deviceTelemetryTopic: 'v1/devices/me/telemetry', 211 deviceTelemetryTopic: 'v1/devices/me/telemetry',
209 deviceAttributesTopic: 'v1/devices/me/attributes', 212 deviceAttributesTopic: 'v1/devices/me/attributes',
210 - transportPayloadType: MqttTransportPayloadType.JSON 213 + transportPayloadTypeConfiguration: {transportPayloadType: MqttTransportPayloadType.JSON}
211 }; 214 };
212 transportConfiguration = {...mqttTransportConfiguration, type: DeviceTransportType.MQTT}; 215 transportConfiguration = {...mqttTransportConfiguration, type: DeviceTransportType.MQTT};
213 break; 216 break;
@@ -895,6 +895,10 @@ @@ -895,6 +895,10 @@
895 "telemetry-topic-filter-required": "Telemetry topic filter is required.", 895 "telemetry-topic-filter-required": "Telemetry topic filter is required.",
896 "attributes-topic-filter": "Attributes topic filter", 896 "attributes-topic-filter": "Attributes topic filter",
897 "attributes-topic-filter-required": "Attributes topic filter is required.", 897 "attributes-topic-filter-required": "Attributes topic filter is required.",
  898 + "telemetry-proto-schema": "Telemetry proto schema",
  899 + "telemetry-proto-schema-required": "Telemetry proto schema is required.",
  900 + "attributes-proto-schema": "Attributes proto schema",
  901 + "attributes-proto-schema-required": "Attributes proto schema is required.",
898 "rpc-response-topic-filter": "RPC response topic filter", 902 "rpc-response-topic-filter": "RPC response topic filter",
899 "rpc-response-topic-filter-required": "RPC response topic filter is required.", 903 "rpc-response-topic-filter-required": "RPC response topic filter is required.",
900 "not-valid-pattern-topic-filter": "Not valid pattern topic filter", 904 "not-valid-pattern-topic-filter": "Not valid pattern topic filter",