Commit ad87924437b99ccdf0cf3ea6d4ea79599d524469

Authored by Igor Kulikov
1 parent 07738c31

Tenant and Device profile improvements

Showing 33 changed files with 783 additions and 129 deletions
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
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;
18 import com.fasterxml.jackson.core.type.TypeReference; 19 import com.fasterxml.jackson.core.type.TypeReference;
19 import com.fasterxml.jackson.databind.JsonNode; 20 import com.fasterxml.jackson.databind.JsonNode;
20 import com.fasterxml.jackson.databind.ObjectMapper; 21 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -59,9 +60,14 @@ import org.springframework.util.MultiValueMap; @@ -59,9 +60,14 @@ import org.springframework.util.MultiValueMap;
59 import org.springframework.web.context.WebApplicationContext; 60 import org.springframework.web.context.WebApplicationContext;
60 import org.thingsboard.server.common.data.BaseData; 61 import org.thingsboard.server.common.data.BaseData;
61 import org.thingsboard.server.common.data.Customer; 62 import org.thingsboard.server.common.data.Customer;
  63 +import org.thingsboard.server.common.data.DeviceProfile;
  64 +import org.thingsboard.server.common.data.DeviceProfileType;
62 import org.thingsboard.server.common.data.Tenant; 65 import org.thingsboard.server.common.data.Tenant;
63 import org.thingsboard.server.common.data.User; 66 import org.thingsboard.server.common.data.User;
  67 +import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
  68 +import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
64 import org.thingsboard.server.common.data.id.HasId; 69 import org.thingsboard.server.common.data.id.HasId;
  70 +import org.thingsboard.server.common.data.id.RuleChainId;
65 import org.thingsboard.server.common.data.id.TenantId; 71 import org.thingsboard.server.common.data.id.TenantId;
66 import org.thingsboard.server.common.data.id.UUIDBased; 72 import org.thingsboard.server.common.data.id.UUIDBased;
67 import org.thingsboard.server.common.data.page.PageLink; 73 import org.thingsboard.server.common.data.page.PageLink;
@@ -305,6 +311,20 @@ public abstract class AbstractWebTest { @@ -305,6 +311,20 @@ public abstract class AbstractWebTest {
305 } 311 }
306 } 312 }
307 313
  314 + protected DeviceProfile createDeviceProfile(String name) {
  315 + DeviceProfile deviceProfile = new DeviceProfile();
  316 + deviceProfile.setName(name);
  317 + deviceProfile.setType(DeviceProfileType.DEFAULT);
  318 + deviceProfile.setDescription(name + " Test");
  319 + DeviceProfileData deviceProfileData = new DeviceProfileData();
  320 + DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
  321 + deviceProfileData.setConfiguration(configuration);
  322 + deviceProfile.setProfileData(deviceProfileData);
  323 + deviceProfile.setDefault(false);
  324 + deviceProfile.setDefaultRuleChainId(new RuleChainId(Uuids.timeBased()));
  325 + return deviceProfile;
  326 + }
  327 +
308 protected ResultActions doGet(String urlTemplate, Object... urlVariables) throws Exception { 328 protected ResultActions doGet(String urlTemplate, Object... urlVariables) throws Exception {
309 MockHttpServletRequestBuilder getRequest = get(urlTemplate, urlVariables); 329 MockHttpServletRequestBuilder getRequest = get(urlTemplate, urlVariables);
310 setJwtToken(getRequest); 330 setJwtToken(getRequest);
@@ -24,6 +24,7 @@ import org.junit.Before; @@ -24,6 +24,7 @@ import org.junit.Before;
24 import org.junit.Test; 24 import org.junit.Test;
25 import org.thingsboard.server.common.data.Customer; 25 import org.thingsboard.server.common.data.Customer;
26 import org.thingsboard.server.common.data.Device; 26 import org.thingsboard.server.common.data.Device;
  27 +import org.thingsboard.server.common.data.DeviceProfile;
27 import org.thingsboard.server.common.data.EntitySubtype; 28 import org.thingsboard.server.common.data.EntitySubtype;
28 import org.thingsboard.server.common.data.Tenant; 29 import org.thingsboard.server.common.data.Tenant;
29 import org.thingsboard.server.common.data.User; 30 import org.thingsboard.server.common.data.User;
@@ -237,6 +238,21 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { @@ -237,6 +238,21 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
237 } 238 }
238 239
239 @Test 240 @Test
  241 + public void testSaveSameDeviceWithDifferentDeviceProfileId() throws Exception {
  242 + Device device = new Device();
  243 + device.setName("My device");
  244 + device.setType("default");
  245 + Device savedDevice = doPost("/api/device", device, Device.class);
  246 + DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile 2");
  247 + DeviceProfile savedDeviceProfile2 = doPost("/api/deviceProfile", deviceProfile2, DeviceProfile.class);
  248 +
  249 + savedDevice.setDeviceProfileId(savedDeviceProfile2.getId());
  250 +
  251 + doPost("/api/device/", savedDevice).andExpect(status().isBadRequest())
  252 + .andExpect(statusReason(containsString("Changing device profile is prohibited")));
  253 + }
  254 +
  255 + @Test
240 public void testAssignDeviceToCustomerFromDifferentTenant() throws Exception { 256 public void testAssignDeviceToCustomerFromDifferentTenant() throws Exception {
241 loginSysAdmin(); 257 loginSysAdmin();
242 258
@@ -15,21 +15,20 @@ @@ -15,21 +15,20 @@
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 org.junit.After; 19 import org.junit.After;
21 import org.junit.Assert; 20 import org.junit.Assert;
22 import org.junit.Before; 21 import org.junit.Before;
23 import org.junit.Test; 22 import org.junit.Test;
  23 +import org.thingsboard.server.common.data.Device;
24 import org.thingsboard.server.common.data.DeviceProfile; 24 import org.thingsboard.server.common.data.DeviceProfile;
  25 +import org.thingsboard.server.common.data.DeviceProfileType;
25 import org.thingsboard.server.common.data.EntityInfo; 26 import org.thingsboard.server.common.data.EntityInfo;
26 import org.thingsboard.server.common.data.Tenant; 27 import org.thingsboard.server.common.data.Tenant;
27 import org.thingsboard.server.common.data.User; 28 import org.thingsboard.server.common.data.User;
28 -import org.thingsboard.server.common.data.id.RuleChainId;  
29 import org.thingsboard.server.common.data.page.PageData; 29 import org.thingsboard.server.common.data.page.PageData;
30 import org.thingsboard.server.common.data.page.PageLink; 30 import org.thingsboard.server.common.data.page.PageLink;
31 import org.thingsboard.server.common.data.security.Authority; 31 import org.thingsboard.server.common.data.security.Authority;
32 -import org.thingsboard.server.dao.util.mapping.JacksonUtil;  
33 32
34 import java.util.ArrayList; 33 import java.util.ArrayList;
35 import java.util.Collections; 34 import java.util.Collections;
@@ -149,6 +148,32 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -149,6 +148,32 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
149 } 148 }
150 149
151 @Test 150 @Test
  151 + public void testSaveSameDeviceProfileWithDifferentType() throws Exception {
  152 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
  153 + DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
  154 + savedDeviceProfile.setType(DeviceProfileType.LWM2M);
  155 + doPost("/api/deviceProfile", savedDeviceProfile).andExpect(status().isBadRequest())
  156 + .andExpect(statusReason(containsString("Changing type of device profile is prohibited")));
  157 + }
  158 +
  159 + @Test
  160 + public void testDeleteDeviceProfileWithExistingDevice() throws Exception {
  161 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
  162 + DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
  163 +
  164 + Device device = new Device();
  165 + device.setName("Test device");
  166 + device.setType("default");
  167 + device.setDeviceProfileId(savedDeviceProfile.getId());
  168 +
  169 + Device savedDevice = doPost("/api/device", device, Device.class);
  170 +
  171 + doDelete("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString())
  172 + .andExpect(status().isBadRequest())
  173 + .andExpect(statusReason(containsString("The device profile referenced by the devices cannot be deleted")));
  174 + }
  175 +
  176 + @Test
152 public void testDeleteDeviceProfile() throws Exception { 177 public void testDeleteDeviceProfile() throws Exception {
153 DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 178 DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
154 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 179 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
@@ -254,13 +279,4 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -254,13 +279,4 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
254 Assert.assertEquals(1, pageData.getTotalElements()); 279 Assert.assertEquals(1, pageData.getTotalElements());
255 } 280 }
256 281
257 - private DeviceProfile createDeviceProfile(String name) {  
258 - DeviceProfile deviceProfile = new DeviceProfile();  
259 - deviceProfile.setName(name);  
260 - deviceProfile.setDescription(name + " Test");  
261 - deviceProfile.setProfileData(JacksonUtil.OBJECT_MAPPER.createObjectNode());  
262 - deviceProfile.setDefault(false);  
263 - deviceProfile.setDefaultRuleChainId(new RuleChainId(Uuids.timeBased()));  
264 - return deviceProfile;  
265 - }  
266 } 282 }
@@ -20,16 +20,14 @@ import org.junit.After; @@ -20,16 +20,14 @@ import org.junit.After;
20 import org.junit.Assert; 20 import org.junit.Assert;
21 import org.junit.Test; 21 import org.junit.Test;
22 import org.springframework.beans.factory.annotation.Autowired; 22 import org.springframework.beans.factory.annotation.Autowired;
23 -import org.thingsboard.server.common.data.Device;  
24 import org.thingsboard.server.common.data.EntityInfo; 23 import org.thingsboard.server.common.data.EntityInfo;
25 import org.thingsboard.server.common.data.Tenant; 24 import org.thingsboard.server.common.data.Tenant;
26 import org.thingsboard.server.common.data.TenantProfile; 25 import org.thingsboard.server.common.data.TenantProfile;
  26 +import org.thingsboard.server.common.data.TenantProfileData;
27 import org.thingsboard.server.common.data.id.TenantId; 27 import org.thingsboard.server.common.data.id.TenantId;
28 import org.thingsboard.server.common.data.page.PageData; 28 import org.thingsboard.server.common.data.page.PageData;
29 import org.thingsboard.server.common.data.page.PageLink; 29 import org.thingsboard.server.common.data.page.PageLink;
30 -import org.thingsboard.server.dao.exception.DataValidationException;  
31 import org.thingsboard.server.dao.tenant.TenantProfileService; 30 import org.thingsboard.server.dao.tenant.TenantProfileService;
32 -import org.thingsboard.server.dao.util.mapping.JacksonUtil;  
33 31
34 import java.util.ArrayList; 32 import java.util.ArrayList;
35 import java.util.Collections; 33 import java.util.Collections;
@@ -48,7 +46,9 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController @@ -48,7 +46,9 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController
48 private TenantProfileService tenantProfileService; 46 private TenantProfileService tenantProfileService;
49 47
50 @After 48 @After
51 - public void after() { 49 + @Override
  50 + public void teardown() throws Exception {
  51 + super.teardown();
52 tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID); 52 tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID);
53 } 53 }
54 54
@@ -134,6 +134,45 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController @@ -134,6 +134,45 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController
134 } 134 }
135 135
136 @Test 136 @Test
  137 + public void testSaveSameTenantProfileWithDifferentIsolatedTbRuleEngine() throws Exception {
  138 + loginSysAdmin();
  139 + TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
  140 + TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class);
  141 + savedTenantProfile.setIsolatedTbRuleEngine(true);
  142 + doPost("/api/tenantProfile", savedTenantProfile).andExpect(status().isBadRequest())
  143 + .andExpect(statusReason(containsString("Can't update isolatedTbRuleEngine property")));
  144 + }
  145 +
  146 + @Test
  147 + public void testSaveSameTenantProfileWithDifferentIsolatedTbCore() throws Exception {
  148 + loginSysAdmin();
  149 + TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
  150 + TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class);
  151 + savedTenantProfile.setIsolatedTbCore(true);
  152 + doPost("/api/tenantProfile", savedTenantProfile).andExpect(status().isBadRequest())
  153 + .andExpect(statusReason(containsString("Can't update isolatedTbCore property")));
  154 + }
  155 +
  156 + @Test
  157 + public void testDeleteTenantProfileWithExistingTenant() throws Exception {
  158 + loginSysAdmin();
  159 + TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
  160 + TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class);
  161 +
  162 + Tenant tenant = new Tenant();
  163 + tenant.setTitle("My tenant with tenant profile");
  164 + tenant.setTenantProfileId(savedTenantProfile.getId());
  165 + Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
  166 +
  167 + doDelete("/api/tenantProfile/" + savedTenantProfile.getId().getId().toString())
  168 + .andExpect(status().isBadRequest())
  169 + .andExpect(statusReason(containsString("The tenant profile referenced by the tenants cannot be deleted")));
  170 +
  171 + doDelete("/api/tenant/"+savedTenant.getId().getId().toString())
  172 + .andExpect(status().isOk());
  173 + }
  174 +
  175 + @Test
137 public void testDeleteTenantProfile() throws Exception { 176 public void testDeleteTenantProfile() throws Exception {
138 loginSysAdmin(); 177 loginSysAdmin();
139 TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile"); 178 TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
@@ -246,7 +285,7 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController @@ -246,7 +285,7 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController
246 TenantProfile tenantProfile = new TenantProfile(); 285 TenantProfile tenantProfile = new TenantProfile();
247 tenantProfile.setName(name); 286 tenantProfile.setName(name);
248 tenantProfile.setDescription(name + " Test"); 287 tenantProfile.setDescription(name + " Test");
249 - tenantProfile.setProfileData(JacksonUtil.OBJECT_MAPPER.createObjectNode()); 288 + tenantProfile.setProfileData(new TenantProfileData());
250 tenantProfile.setDefault(false); 289 tenantProfile.setDefault(false);
251 tenantProfile.setIsolatedTbCore(false); 290 tenantProfile.setIsolatedTbCore(false);
252 tenantProfile.setIsolatedTbRuleEngine(false); 291 tenantProfile.setIsolatedTbRuleEngine(false);
@@ -15,13 +15,22 @@ @@ -15,13 +15,22 @@
15 */ 15 */
16 package org.thingsboard.server.common.data; 16 package org.thingsboard.server.common.data;
17 17
  18 +import com.fasterxml.jackson.annotation.JsonIgnore;
  19 +import com.fasterxml.jackson.core.JsonProcessingException;
18 import lombok.EqualsAndHashCode; 20 import lombok.EqualsAndHashCode;
  21 +import lombok.extern.slf4j.Slf4j;
  22 +import org.thingsboard.server.common.data.device.data.DeviceData;
  23 +import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
19 import org.thingsboard.server.common.data.id.CustomerId; 24 import org.thingsboard.server.common.data.id.CustomerId;
20 import org.thingsboard.server.common.data.id.DeviceId; 25 import org.thingsboard.server.common.data.id.DeviceId;
21 import org.thingsboard.server.common.data.id.DeviceProfileId; 26 import org.thingsboard.server.common.data.id.DeviceProfileId;
22 import org.thingsboard.server.common.data.id.TenantId; 27 import org.thingsboard.server.common.data.id.TenantId;
23 28
  29 +import java.io.ByteArrayInputStream;
  30 +import java.io.IOException;
  31 +
24 @EqualsAndHashCode(callSuper = true) 32 @EqualsAndHashCode(callSuper = true)
  33 +@Slf4j
25 public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implements HasName, HasTenantId, HasCustomerId { 34 public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implements HasName, HasTenantId, HasCustomerId {
26 35
27 private static final long serialVersionUID = 2807343040519543363L; 36 private static final long serialVersionUID = 2807343040519543363L;
@@ -32,6 +41,9 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen @@ -32,6 +41,9 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
32 private String type; 41 private String type;
33 private String label; 42 private String label;
34 private DeviceProfileId deviceProfileId; 43 private DeviceProfileId deviceProfileId;
  44 + private transient DeviceData deviceData;
  45 + @JsonIgnore
  46 + private byte[] deviceDataBytes;
35 47
36 public Device() { 48 public Device() {
37 super(); 49 super();
@@ -49,6 +61,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen @@ -49,6 +61,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
49 this.type = device.getType(); 61 this.type = device.getType();
50 this.label = device.getLabel(); 62 this.label = device.getLabel();
51 this.deviceProfileId = device.getDeviceProfileId(); 63 this.deviceProfileId = device.getDeviceProfileId();
  64 + this.setDeviceData(device.getDeviceData());
52 } 65 }
53 66
54 public TenantId getTenantId() { 67 public TenantId getTenantId() {
@@ -100,6 +113,33 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen @@ -100,6 +113,33 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
100 this.deviceProfileId = deviceProfileId; 113 this.deviceProfileId = deviceProfileId;
101 } 114 }
102 115
  116 + public DeviceData getDeviceData() {
  117 + if (deviceData != null) {
  118 + return deviceData;
  119 + } else {
  120 + if (deviceDataBytes != null) {
  121 + try {
  122 + deviceData = mapper.readValue(new ByteArrayInputStream(deviceDataBytes), DeviceData.class);
  123 + } catch (IOException e) {
  124 + log.warn("Can't deserialize device data: ", e);
  125 + return null;
  126 + }
  127 + return deviceData;
  128 + } else {
  129 + return null;
  130 + }
  131 + }
  132 + }
  133 +
  134 + public void setDeviceData(DeviceData data) {
  135 + this.deviceData = data;
  136 + try {
  137 + this.deviceDataBytes = data != null ? mapper.writeValueAsBytes(data) : null;
  138 + } catch (JsonProcessingException e) {
  139 + log.warn("Can't serialize device data: ", e);
  140 + }
  141 + }
  142 +
103 @Override 143 @Override
104 public String getSearchText() { 144 public String getSearchText() {
105 return getName(); 145 return getName();
@@ -120,6 +160,8 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen @@ -120,6 +160,8 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
120 builder.append(label); 160 builder.append(label);
121 builder.append(", deviceProfileId="); 161 builder.append(", deviceProfileId=");
122 builder.append(deviceProfileId); 162 builder.append(deviceProfileId);
  163 + builder.append(", deviceData=");
  164 + builder.append(deviceData);
123 builder.append(", additionalInfo="); 165 builder.append(", additionalInfo=");
124 builder.append(getAdditionalInfo()); 166 builder.append(getAdditionalInfo());
125 builder.append(", createdTime="); 167 builder.append(", createdTime=");
@@ -16,26 +16,32 @@ @@ -16,26 +16,32 @@
16 package org.thingsboard.server.common.data; 16 package org.thingsboard.server.common.data;
17 17
18 import com.fasterxml.jackson.annotation.JsonIgnore; 18 import com.fasterxml.jackson.annotation.JsonIgnore;
19 -import com.fasterxml.jackson.databind.JsonNode; 19 +import com.fasterxml.jackson.core.JsonProcessingException;
20 import lombok.Data; 20 import lombok.Data;
21 import lombok.EqualsAndHashCode; 21 import lombok.EqualsAndHashCode;
  22 +import lombok.extern.slf4j.Slf4j;
  23 +import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
22 import org.thingsboard.server.common.data.id.DeviceProfileId; 24 import org.thingsboard.server.common.data.id.DeviceProfileId;
23 import org.thingsboard.server.common.data.id.RuleChainId; 25 import org.thingsboard.server.common.data.id.RuleChainId;
24 import org.thingsboard.server.common.data.id.TenantId; 26 import org.thingsboard.server.common.data.id.TenantId;
25 27
26 -import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.getJson;  
27 -import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.setJson; 28 +import java.io.ByteArrayInputStream;
  29 +import java.io.IOException;
  30 +
  31 +import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.mapper;
28 32
29 @Data 33 @Data
30 @EqualsAndHashCode(callSuper = true) 34 @EqualsAndHashCode(callSuper = true)
  35 +@Slf4j
31 public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements HasName, HasTenantId { 36 public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements HasName, HasTenantId {
32 37
33 private TenantId tenantId; 38 private TenantId tenantId;
34 private String name; 39 private String name;
35 private String description; 40 private String description;
36 private boolean isDefault; 41 private boolean isDefault;
  42 + private DeviceProfileType type;
37 private RuleChainId defaultRuleChainId; 43 private RuleChainId defaultRuleChainId;
38 - private transient JsonNode profileData; 44 + private transient DeviceProfileData profileData;
39 @JsonIgnore 45 @JsonIgnore
40 private byte[] profileDataBytes; 46 private byte[] profileDataBytes;
41 47
@@ -67,12 +73,31 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H @@ -67,12 +73,31 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
67 return name; 73 return name;
68 } 74 }
69 75
70 - public JsonNode getProfileData() {  
71 - return getJson(() -> profileData, () -> profileDataBytes); 76 + public DeviceProfileData getProfileData() {
  77 + if (profileData != null) {
  78 + return profileData;
  79 + } else {
  80 + if (profileDataBytes != null) {
  81 + try {
  82 + profileData = mapper.readValue(new ByteArrayInputStream(profileDataBytes), DeviceProfileData.class);
  83 + } catch (IOException e) {
  84 + log.warn("Can't deserialize device profile data: ", e);
  85 + return null;
  86 + }
  87 + return profileData;
  88 + } else {
  89 + return null;
  90 + }
  91 + }
72 } 92 }
73 93
74 - public void setProfileData(JsonNode data) {  
75 - setJson(data, json -> this.profileData = json, bytes -> this.profileDataBytes = bytes); 94 + public void setProfileData(DeviceProfileData data) {
  95 + this.profileData = data;
  96 + try {
  97 + this.profileDataBytes = data != null ? mapper.writeValueAsBytes(data) : null;
  98 + } catch (JsonProcessingException e) {
  99 + log.warn("Can't serialize device profile data: ", e);
  100 + }
76 } 101 }
77 102
78 } 103 }
  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;
  17 +
  18 +public enum DeviceProfileType {
  19 + DEFAULT,
  20 + LWM2M
  21 +}
@@ -35,7 +35,7 @@ import java.util.function.Consumer; @@ -35,7 +35,7 @@ import java.util.function.Consumer;
35 @Slf4j 35 @Slf4j
36 public abstract class SearchTextBasedWithAdditionalInfo<I extends UUIDBased> extends SearchTextBased<I> implements HasAdditionalInfo { 36 public abstract class SearchTextBasedWithAdditionalInfo<I extends UUIDBased> extends SearchTextBased<I> implements HasAdditionalInfo {
37 37
38 - private static final ObjectMapper mapper = new ObjectMapper(); 38 + public static final ObjectMapper mapper = new ObjectMapper();
39 private transient JsonNode additionalInfo; 39 private transient JsonNode additionalInfo;
40 @JsonIgnore 40 @JsonIgnore
41 private byte[] additionalInfoBytes; 41 private byte[] additionalInfoBytes;
@@ -84,7 +84,7 @@ public abstract class SearchTextBasedWithAdditionalInfo<I extends UUIDBased> ext @@ -84,7 +84,7 @@ public abstract class SearchTextBasedWithAdditionalInfo<I extends UUIDBased> ext
84 byte[] data = binaryData.get(); 84 byte[] data = binaryData.get();
85 if (data != null) { 85 if (data != null) {
86 try { 86 try {
87 - return new ObjectMapper().readTree(new ByteArrayInputStream(data)); 87 + return mapper.readTree(new ByteArrayInputStream(data));
88 } catch (IOException e) { 88 } catch (IOException e) {
89 log.warn("Can't deserialize json data: ", e); 89 log.warn("Can't deserialize json data: ", e);
90 return null; 90 return null;
@@ -16,16 +16,20 @@ @@ -16,16 +16,20 @@
16 package org.thingsboard.server.common.data; 16 package org.thingsboard.server.common.data;
17 17
18 import com.fasterxml.jackson.annotation.JsonIgnore; 18 import com.fasterxml.jackson.annotation.JsonIgnore;
19 -import com.fasterxml.jackson.databind.JsonNode; 19 +import com.fasterxml.jackson.core.JsonProcessingException;
20 import lombok.Data; 20 import lombok.Data;
21 import lombok.EqualsAndHashCode; 21 import lombok.EqualsAndHashCode;
  22 +import lombok.extern.slf4j.Slf4j;
22 import org.thingsboard.server.common.data.id.TenantProfileId; 23 import org.thingsboard.server.common.data.id.TenantProfileId;
23 24
24 -import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.getJson;  
25 -import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.setJson; 25 +import java.io.ByteArrayInputStream;
  26 +import java.io.IOException;
  27 +
  28 +import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.mapper;
26 29
27 @Data 30 @Data
28 @EqualsAndHashCode(callSuper = true) 31 @EqualsAndHashCode(callSuper = true)
  32 +@Slf4j
29 public class TenantProfile extends SearchTextBased<TenantProfileId> implements HasName { 33 public class TenantProfile extends SearchTextBased<TenantProfileId> implements HasName {
30 34
31 private String name; 35 private String name;
@@ -33,7 +37,7 @@ public class TenantProfile extends SearchTextBased<TenantProfileId> implements H @@ -33,7 +37,7 @@ public class TenantProfile extends SearchTextBased<TenantProfileId> implements H
33 private boolean isDefault; 37 private boolean isDefault;
34 private boolean isolatedTbCore; 38 private boolean isolatedTbCore;
35 private boolean isolatedTbRuleEngine; 39 private boolean isolatedTbRuleEngine;
36 - private transient JsonNode profileData; 40 + private transient TenantProfileData profileData;
37 @JsonIgnore 41 @JsonIgnore
38 private byte[] profileDataBytes; 42 private byte[] profileDataBytes;
39 43
@@ -65,12 +69,31 @@ public class TenantProfile extends SearchTextBased<TenantProfileId> implements H @@ -65,12 +69,31 @@ public class TenantProfile extends SearchTextBased<TenantProfileId> implements H
65 return name; 69 return name;
66 } 70 }
67 71
68 - public JsonNode getProfileData() {  
69 - return getJson(() -> profileData, () -> profileDataBytes); 72 + public TenantProfileData getProfileData() {
  73 + if (profileData != null) {
  74 + return profileData;
  75 + } else {
  76 + if (profileDataBytes != null) {
  77 + try {
  78 + profileData = mapper.readValue(new ByteArrayInputStream(profileDataBytes), TenantProfileData.class);
  79 + } catch (IOException e) {
  80 + log.warn("Can't deserialize tenant profile data: ", e);
  81 + return null;
  82 + }
  83 + return profileData;
  84 + } else {
  85 + return null;
  86 + }
  87 + }
70 } 88 }
71 89
72 - public void setProfileData(JsonNode data) {  
73 - setJson(data, json -> this.profileData = json, bytes -> this.profileDataBytes = bytes); 90 + public void setProfileData(TenantProfileData data) {
  91 + this.profileData = data;
  92 + try {
  93 + this.profileDataBytes = data != null ? mapper.writeValueAsBytes(data) : null;
  94 + } catch (JsonProcessingException e) {
  95 + log.warn("Can't serialize tenant profile data: ", e);
  96 + }
74 } 97 }
75 98
76 } 99 }
  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;
  17 +
  18 +import com.fasterxml.jackson.annotation.JsonAnyGetter;
  19 +import com.fasterxml.jackson.annotation.JsonAnySetter;
  20 +import lombok.Data;
  21 +
  22 +import java.util.HashMap;
  23 +import java.util.Map;
  24 +
  25 +@Data
  26 +public class TenantProfileData {
  27 +
  28 + private Map<String, String> properties = new HashMap<>();
  29 +
  30 + @JsonAnyGetter
  31 + public Map<String, String> properties() {
  32 + return this.properties;
  33 + }
  34 +
  35 + @JsonAnySetter
  36 + public void put(String name, String value) {
  37 + this.properties.put(name, value);
  38 + }
  39 +
  40 +}
  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.data;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.DeviceProfileType;
  20 +
  21 +@Data
  22 +public class DefaultDeviceConfiguration implements DeviceConfiguration {
  23 +
  24 + @Override
  25 + public DeviceProfileType getType() {
  26 + return DeviceProfileType.DEFAULT;
  27 + }
  28 +
  29 +}
  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.data;
  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.DeviceProfileType;
  23 +
  24 +@JsonIgnoreProperties(ignoreUnknown = true)
  25 +@JsonTypeInfo(
  26 + use = JsonTypeInfo.Id.NAME,
  27 + include = JsonTypeInfo.As.PROPERTY,
  28 + property = "type")
  29 +@JsonSubTypes({
  30 + @JsonSubTypes.Type(value = DefaultDeviceConfiguration.class, name = "DEFAULT"),
  31 + @JsonSubTypes.Type(value = Lwm2mDeviceConfiguration.class, name = "LWM2M")})
  32 +public interface DeviceConfiguration {
  33 +
  34 + @JsonIgnore
  35 + DeviceProfileType getType();
  36 +
  37 +}
  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.data;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class DeviceData {
  22 +
  23 + private DeviceConfiguration configuration;
  24 +
  25 +}
  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.data;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.DeviceProfileType;
  20 +
  21 +@Data
  22 +public class Lwm2mDeviceConfiguration implements DeviceConfiguration {
  23 +
  24 + @Override
  25 + public DeviceProfileType getType() {
  26 + return DeviceProfileType.LWM2M;
  27 + }
  28 +
  29 +}
  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.DeviceProfileType;
  20 +
  21 +@Data
  22 +public class DefaultDeviceProfileConfiguration implements DeviceProfileConfiguration {
  23 +
  24 + @Override
  25 + public DeviceProfileType getType() {
  26 + return DeviceProfileType.DEFAULT;
  27 + }
  28 +
  29 +}
  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.DeviceProfileType;
  23 +
  24 +@JsonIgnoreProperties(ignoreUnknown = true)
  25 +@JsonTypeInfo(
  26 + use = JsonTypeInfo.Id.NAME,
  27 + include = JsonTypeInfo.As.PROPERTY,
  28 + property = "type")
  29 +@JsonSubTypes({
  30 + @JsonSubTypes.Type(value = DefaultDeviceProfileConfiguration.class, name = "DEFAULT"),
  31 + @JsonSubTypes.Type(value = Lwm2mDeviceProfileConfiguration.class, name = "LWM2M")})
  32 +public interface DeviceProfileConfiguration {
  33 +
  34 + @JsonIgnore
  35 + DeviceProfileType getType();
  36 +
  37 +}
  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 +
  20 +@Data
  21 +public class DeviceProfileData {
  22 +
  23 + private DeviceProfileConfiguration configuration;
  24 +
  25 +}
  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.DeviceProfileType;
  20 +
  21 +@Data
  22 +public class Lwm2mDeviceProfileConfiguration implements DeviceProfileConfiguration {
  23 +
  24 + @Override
  25 + public DeviceProfileType getType() {
  26 + return DeviceProfileType.LWM2M;
  27 + }
  28 +
  29 +}
@@ -24,8 +24,11 @@ import org.springframework.cache.CacheManager; @@ -24,8 +24,11 @@ import org.springframework.cache.CacheManager;
24 import org.springframework.cache.annotation.Cacheable; 24 import org.springframework.cache.annotation.Cacheable;
25 import org.springframework.stereotype.Service; 25 import org.springframework.stereotype.Service;
26 import org.thingsboard.server.common.data.DeviceProfile; 26 import org.thingsboard.server.common.data.DeviceProfile;
  27 +import org.thingsboard.server.common.data.DeviceProfileType;
27 import org.thingsboard.server.common.data.EntityInfo; 28 import org.thingsboard.server.common.data.EntityInfo;
28 import org.thingsboard.server.common.data.Tenant; 29 import org.thingsboard.server.common.data.Tenant;
  30 +import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
  31 +import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
29 import org.thingsboard.server.common.data.id.DeviceProfileId; 32 import org.thingsboard.server.common.data.id.DeviceProfileId;
30 import org.thingsboard.server.common.data.id.TenantId; 33 import org.thingsboard.server.common.data.id.TenantId;
31 import org.thingsboard.server.common.data.page.PageData; 34 import org.thingsboard.server.common.data.page.PageData;
@@ -113,8 +116,17 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -113,8 +116,17 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
113 } 116 }
114 117
115 private void removeDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId) { 118 private void removeDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId) {
  119 + try {
  120 + deviceProfileDao.removeById(tenantId, deviceProfileId.getId());
  121 + } catch (Exception t) {
  122 + ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
  123 + if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_device_profile")) {
  124 + throw new DataValidationException("The device profile referenced by the devices cannot be deleted!");
  125 + } else {
  126 + throw t;
  127 + }
  128 + }
116 deleteEntityRelations(tenantId, deviceProfileId); 129 deleteEntityRelations(tenantId, deviceProfileId);
117 - deviceProfileDao.removeById(tenantId, deviceProfileId.getId());  
118 Cache cache = cacheManager.getCache(DEVICE_PROFILE_CACHE); 130 Cache cache = cacheManager.getCache(DEVICE_PROFILE_CACHE);
119 cache.evict(Collections.singletonList(deviceProfileId.getId())); 131 cache.evict(Collections.singletonList(deviceProfileId.getId()));
120 cache.evict(Arrays.asList("info", deviceProfileId.getId())); 132 cache.evict(Arrays.asList("info", deviceProfileId.getId()));
@@ -144,8 +156,12 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -144,8 +156,12 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
144 deviceProfile.setTenantId(tenantId); 156 deviceProfile.setTenantId(tenantId);
145 deviceProfile.setDefault(true); 157 deviceProfile.setDefault(true);
146 deviceProfile.setName("Default"); 158 deviceProfile.setName("Default");
  159 + deviceProfile.setType(DeviceProfileType.DEFAULT);
147 deviceProfile.setDescription("Default device profile"); 160 deviceProfile.setDescription("Default device profile");
148 - deviceProfile.setProfileData(JacksonUtil.OBJECT_MAPPER.createObjectNode()); 161 + DeviceProfileData deviceProfileData = new DeviceProfileData();
  162 + DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
  163 + deviceProfileData.setConfiguration(configuration);
  164 + deviceProfile.setProfileData(deviceProfileData);
149 return saveDeviceProfile(deviceProfile); 165 return saveDeviceProfile(deviceProfile);
150 } 166 }
151 167
@@ -226,6 +242,16 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -226,6 +242,16 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
226 } 242 }
227 } 243 }
228 } 244 }
  245 +
  246 + @Override
  247 + protected void validateUpdate(TenantId tenantId, DeviceProfile deviceProfile) {
  248 + DeviceProfile old = deviceProfileDao.findById(deviceProfile.getTenantId(), deviceProfile.getId().getId());
  249 + if (old == null) {
  250 + throw new DataValidationException("Can't update non existing device profile!");
  251 + } else if (!old.getType().equals(deviceProfile.getType())) {
  252 + throw new DataValidationException("Changing type of device profile is prohibited!");
  253 + }
  254 + }
229 }; 255 };
230 256
231 private PaginatedRemover<TenantId, DeviceProfile> tenantDeviceProfilesRemover = 257 private PaginatedRemover<TenantId, DeviceProfile> tenantDeviceProfilesRemover =
@@ -41,6 +41,8 @@ import org.thingsboard.server.common.data.EntityType; @@ -41,6 +41,8 @@ import org.thingsboard.server.common.data.EntityType;
41 import org.thingsboard.server.common.data.EntityView; 41 import org.thingsboard.server.common.data.EntityView;
42 import org.thingsboard.server.common.data.Tenant; 42 import org.thingsboard.server.common.data.Tenant;
43 import org.thingsboard.server.common.data.device.DeviceSearchQuery; 43 import org.thingsboard.server.common.data.device.DeviceSearchQuery;
  44 +import org.thingsboard.server.common.data.device.data.DefaultDeviceConfiguration;
  45 +import org.thingsboard.server.common.data.device.data.DeviceData;
44 import org.thingsboard.server.common.data.id.CustomerId; 46 import org.thingsboard.server.common.data.id.CustomerId;
45 import org.thingsboard.server.common.data.id.DeviceId; 47 import org.thingsboard.server.common.data.id.DeviceId;
46 import org.thingsboard.server.common.data.id.DeviceProfileId; 48 import org.thingsboard.server.common.data.id.DeviceProfileId;
@@ -168,6 +170,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -168,6 +170,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
168 if (device.getDeviceProfileId() == null) { 170 if (device.getDeviceProfileId() == null) {
169 EntityInfo deviceProfile = this.deviceProfileService.findDefaultDeviceProfileInfo(device.getTenantId()); 171 EntityInfo deviceProfile = this.deviceProfileService.findDefaultDeviceProfileInfo(device.getTenantId());
170 device.setDeviceProfileId(new DeviceProfileId(deviceProfile.getId().getId())); 172 device.setDeviceProfileId(new DeviceProfileId(deviceProfile.getId().getId()));
  173 + DeviceData deviceData = new DeviceData();
  174 + deviceData.setConfiguration(new DefaultDeviceConfiguration());
  175 + device.setDeviceData(deviceData);
171 } 176 }
172 savedDevice = deviceDao.save(device.getTenantId(), device); 177 savedDevice = deviceDao.save(device.getTenantId(), device);
173 } catch (Exception t) { 178 } catch (Exception t) {
@@ -411,6 +416,12 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -411,6 +416,12 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
411 416
412 @Override 417 @Override
413 protected void validateUpdate(TenantId tenantId, Device device) { 418 protected void validateUpdate(TenantId tenantId, Device device) {
  419 + Device old = deviceDao.findById(device.getTenantId(), device.getId().getId());
  420 + if (old == null) {
  421 + throw new DataValidationException("Can't update non existing device!");
  422 + } else if (!old.getDeviceProfileId().equals(device.getDeviceProfileId())) {
  423 + throw new DataValidationException("Changing device profile is prohibited!");
  424 + }
414 } 425 }
415 426
416 @Override 427 @Override
@@ -152,6 +152,8 @@ public class ModelConstants { @@ -152,6 +152,8 @@ public class ModelConstants {
152 public static final String DEVICE_LABEL_PROPERTY = "label"; 152 public static final String DEVICE_LABEL_PROPERTY = "label";
153 public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; 153 public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
154 public static final String DEVICE_DEVICE_PROFILE_ID_PROPERTY = "device_profile_id"; 154 public static final String DEVICE_DEVICE_PROFILE_ID_PROPERTY = "device_profile_id";
  155 + public static final String DEVICE_DEVICE_DATA_PROPERTY = "device_data";
  156 +
155 public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text"; 157 public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text";
156 public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text"; 158 public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text";
157 public static final String DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_and_search_text"; 159 public static final String DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_and_search_text";
@@ -165,6 +167,7 @@ public class ModelConstants { @@ -165,6 +167,7 @@ public class ModelConstants {
165 public static final String DEVICE_PROFILE_COLUMN_FAMILY_NAME = "device_profile"; 167 public static final String DEVICE_PROFILE_COLUMN_FAMILY_NAME = "device_profile";
166 public static final String DEVICE_PROFILE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; 168 public static final String DEVICE_PROFILE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
167 public static final String DEVICE_PROFILE_NAME_PROPERTY = "name"; 169 public static final String DEVICE_PROFILE_NAME_PROPERTY = "name";
  170 + public static final String DEVICE_PROFILE_TYPE_PROPERTY = "type";
168 public static final String DEVICE_PROFILE_PROFILE_DATA_PROPERTY = "profile_data"; 171 public static final String DEVICE_PROFILE_PROFILE_DATA_PROPERTY = "profile_data";
169 public static final String DEVICE_PROFILE_DESCRIPTION_PROPERTY = "description"; 172 public static final String DEVICE_PROFILE_DESCRIPTION_PROPERTY = "description";
170 public static final String DEVICE_PROFILE_IS_DEFAULT_PROPERTY = "is_default"; 173 public static final String DEVICE_PROFILE_IS_DEFAULT_PROPERTY = "is_default";
@@ -16,11 +16,13 @@ @@ -16,11 +16,13 @@
16 package org.thingsboard.server.dao.model.sql; 16 package org.thingsboard.server.dao.model.sql;
17 17
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
  19 +import com.fasterxml.jackson.databind.node.ObjectNode;
19 import lombok.Data; 20 import lombok.Data;
20 import lombok.EqualsAndHashCode; 21 import lombok.EqualsAndHashCode;
21 import org.hibernate.annotations.Type; 22 import org.hibernate.annotations.Type;
22 import org.hibernate.annotations.TypeDef; 23 import org.hibernate.annotations.TypeDef;
23 import org.thingsboard.server.common.data.Device; 24 import org.thingsboard.server.common.data.Device;
  25 +import org.thingsboard.server.common.data.device.data.DeviceData;
24 import org.thingsboard.server.common.data.id.CustomerId; 26 import org.thingsboard.server.common.data.id.CustomerId;
25 import org.thingsboard.server.common.data.id.DeviceId; 27 import org.thingsboard.server.common.data.id.DeviceId;
26 import org.thingsboard.server.common.data.id.DeviceProfileId; 28 import org.thingsboard.server.common.data.id.DeviceProfileId;
@@ -28,6 +30,7 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -28,6 +30,7 @@ import org.thingsboard.server.common.data.id.TenantId;
28 import org.thingsboard.server.dao.model.BaseSqlEntity; 30 import org.thingsboard.server.dao.model.BaseSqlEntity;
29 import org.thingsboard.server.dao.model.ModelConstants; 31 import org.thingsboard.server.dao.model.ModelConstants;
30 import org.thingsboard.server.dao.model.SearchTextEntity; 32 import org.thingsboard.server.dao.model.SearchTextEntity;
  33 +import org.thingsboard.server.dao.util.mapping.JacksonUtil;
31 import org.thingsboard.server.dao.util.mapping.JsonStringType; 34 import org.thingsboard.server.dao.util.mapping.JsonStringType;
32 35
33 import javax.persistence.Column; 36 import javax.persistence.Column;
@@ -65,6 +68,10 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti @@ -65,6 +68,10 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti
65 @Column(name = ModelConstants.DEVICE_DEVICE_PROFILE_ID_PROPERTY, columnDefinition = "uuid") 68 @Column(name = ModelConstants.DEVICE_DEVICE_PROFILE_ID_PROPERTY, columnDefinition = "uuid")
66 private UUID deviceProfileId; 69 private UUID deviceProfileId;
67 70
  71 + @Type(type = "json")
  72 + @Column(name = ModelConstants.DEVICE_DEVICE_DATA_PROPERTY)
  73 + private JsonNode deviceData;
  74 +
68 public AbstractDeviceEntity() { 75 public AbstractDeviceEntity() {
69 super(); 76 super();
70 } 77 }
@@ -83,6 +90,7 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti @@ -83,6 +90,7 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti
83 if (device.getDeviceProfileId() != null) { 90 if (device.getDeviceProfileId() != null) {
84 this.deviceProfileId = device.getDeviceProfileId().getId(); 91 this.deviceProfileId = device.getDeviceProfileId().getId();
85 } 92 }
  93 + this.deviceData = JacksonUtil.convertValue(device.getDeviceData(), ObjectNode.class);
86 this.name = device.getName(); 94 this.name = device.getName();
87 this.type = device.getType(); 95 this.type = device.getType();
88 this.label = device.getLabel(); 96 this.label = device.getLabel();
@@ -95,6 +103,7 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti @@ -95,6 +103,7 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti
95 this.tenantId = deviceEntity.getTenantId(); 103 this.tenantId = deviceEntity.getTenantId();
96 this.customerId = deviceEntity.getCustomerId(); 104 this.customerId = deviceEntity.getCustomerId();
97 this.deviceProfileId = deviceEntity.getDeviceProfileId(); 105 this.deviceProfileId = deviceEntity.getDeviceProfileId();
  106 + this.deviceData = deviceEntity.getDeviceData();
98 this.type = deviceEntity.getType(); 107 this.type = deviceEntity.getType();
99 this.name = deviceEntity.getName(); 108 this.name = deviceEntity.getName();
100 this.label = deviceEntity.getLabel(); 109 this.label = deviceEntity.getLabel();
@@ -124,6 +133,7 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti @@ -124,6 +133,7 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti
124 if (deviceProfileId != null) { 133 if (deviceProfileId != null) {
125 device.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); 134 device.setDeviceProfileId(new DeviceProfileId(deviceProfileId));
126 } 135 }
  136 + device.setDeviceData(JacksonUtil.convertValue(deviceData, DeviceData.class));
127 device.setName(name); 137 device.setName(name);
128 device.setType(type); 138 device.setType(type);
129 device.setLabel(label); 139 device.setLabel(label);
@@ -16,21 +16,27 @@ @@ -16,21 +16,27 @@
16 package org.thingsboard.server.dao.model.sql; 16 package org.thingsboard.server.dao.model.sql;
17 17
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
  19 +import com.fasterxml.jackson.databind.node.ObjectNode;
19 import lombok.Data; 20 import lombok.Data;
20 import lombok.EqualsAndHashCode; 21 import lombok.EqualsAndHashCode;
21 import org.hibernate.annotations.Type; 22 import org.hibernate.annotations.Type;
22 import org.hibernate.annotations.TypeDef; 23 import org.hibernate.annotations.TypeDef;
23 import org.thingsboard.server.common.data.DeviceProfile; 24 import org.thingsboard.server.common.data.DeviceProfile;
  25 +import org.thingsboard.server.common.data.DeviceProfileType;
  26 +import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
24 import org.thingsboard.server.common.data.id.DeviceProfileId; 27 import org.thingsboard.server.common.data.id.DeviceProfileId;
25 import org.thingsboard.server.common.data.id.RuleChainId; 28 import org.thingsboard.server.common.data.id.RuleChainId;
26 import org.thingsboard.server.common.data.id.TenantId; 29 import org.thingsboard.server.common.data.id.TenantId;
27 import org.thingsboard.server.dao.model.BaseSqlEntity; 30 import org.thingsboard.server.dao.model.BaseSqlEntity;
28 import org.thingsboard.server.dao.model.ModelConstants; 31 import org.thingsboard.server.dao.model.ModelConstants;
29 import org.thingsboard.server.dao.model.SearchTextEntity; 32 import org.thingsboard.server.dao.model.SearchTextEntity;
  33 +import org.thingsboard.server.dao.util.mapping.JacksonUtil;
30 import org.thingsboard.server.dao.util.mapping.JsonStringType; 34 import org.thingsboard.server.dao.util.mapping.JsonStringType;
31 35
32 import javax.persistence.Column; 36 import javax.persistence.Column;
33 import javax.persistence.Entity; 37 import javax.persistence.Entity;
  38 +import javax.persistence.EnumType;
  39 +import javax.persistence.Enumerated;
34 import javax.persistence.Table; 40 import javax.persistence.Table;
35 import java.util.UUID; 41 import java.util.UUID;
36 42
@@ -47,6 +53,10 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl @@ -47,6 +53,10 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
47 @Column(name = ModelConstants.DEVICE_PROFILE_NAME_PROPERTY) 53 @Column(name = ModelConstants.DEVICE_PROFILE_NAME_PROPERTY)
48 private String name; 54 private String name;
49 55
  56 + @Enumerated(EnumType.STRING)
  57 + @Column(name = ModelConstants.DEVICE_PROFILE_TYPE_PROPERTY)
  58 + private DeviceProfileType type;
  59 +
50 @Column(name = ModelConstants.DEVICE_PROFILE_DESCRIPTION_PROPERTY) 60 @Column(name = ModelConstants.DEVICE_PROFILE_DESCRIPTION_PROPERTY)
51 private String description; 61 private String description;
52 62
@@ -76,9 +86,10 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl @@ -76,9 +86,10 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
76 } 86 }
77 this.setCreatedTime(deviceProfile.getCreatedTime()); 87 this.setCreatedTime(deviceProfile.getCreatedTime());
78 this.name = deviceProfile.getName(); 88 this.name = deviceProfile.getName();
  89 + this.type = deviceProfile.getType();
79 this.description = deviceProfile.getDescription(); 90 this.description = deviceProfile.getDescription();
80 this.isDefault = deviceProfile.isDefault(); 91 this.isDefault = deviceProfile.isDefault();
81 - this.profileData = deviceProfile.getProfileData(); 92 + this.profileData = JacksonUtil.convertValue(deviceProfile.getProfileData(), ObjectNode.class);
82 if (deviceProfile.getDefaultRuleChainId() != null) { 93 if (deviceProfile.getDefaultRuleChainId() != null) {
83 this.defaultRuleChainId = deviceProfile.getDefaultRuleChainId().getId(); 94 this.defaultRuleChainId = deviceProfile.getDefaultRuleChainId().getId();
84 } 95 }
@@ -106,9 +117,10 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl @@ -106,9 +117,10 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
106 deviceProfile.setTenantId(new TenantId(tenantId)); 117 deviceProfile.setTenantId(new TenantId(tenantId));
107 } 118 }
108 deviceProfile.setName(name); 119 deviceProfile.setName(name);
  120 + deviceProfile.setType(type);
109 deviceProfile.setDescription(description); 121 deviceProfile.setDescription(description);
110 deviceProfile.setDefault(isDefault); 122 deviceProfile.setDefault(isDefault);
111 - deviceProfile.setProfileData(profileData); 123 + deviceProfile.setProfileData(JacksonUtil.convertValue(profileData, DeviceProfileData.class));
112 if (defaultRuleChainId != null) { 124 if (defaultRuleChainId != null) {
113 deviceProfile.setDefaultRuleChainId(new RuleChainId(defaultRuleChainId)); 125 deviceProfile.setDefaultRuleChainId(new RuleChainId(defaultRuleChainId));
114 } 126 }
@@ -16,15 +16,18 @@ @@ -16,15 +16,18 @@
16 package org.thingsboard.server.dao.model.sql; 16 package org.thingsboard.server.dao.model.sql;
17 17
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
  19 +import com.fasterxml.jackson.databind.node.ObjectNode;
19 import lombok.Data; 20 import lombok.Data;
20 import lombok.EqualsAndHashCode; 21 import lombok.EqualsAndHashCode;
21 import org.hibernate.annotations.Type; 22 import org.hibernate.annotations.Type;
22 import org.hibernate.annotations.TypeDef; 23 import org.hibernate.annotations.TypeDef;
23 import org.thingsboard.server.common.data.TenantProfile; 24 import org.thingsboard.server.common.data.TenantProfile;
  25 +import org.thingsboard.server.common.data.TenantProfileData;
24 import org.thingsboard.server.common.data.id.TenantProfileId; 26 import org.thingsboard.server.common.data.id.TenantProfileId;
25 import org.thingsboard.server.dao.model.BaseSqlEntity; 27 import org.thingsboard.server.dao.model.BaseSqlEntity;
26 import org.thingsboard.server.dao.model.ModelConstants; 28 import org.thingsboard.server.dao.model.ModelConstants;
27 import org.thingsboard.server.dao.model.SearchTextEntity; 29 import org.thingsboard.server.dao.model.SearchTextEntity;
  30 +import org.thingsboard.server.dao.util.mapping.JacksonUtil;
28 import org.thingsboard.server.dao.util.mapping.JsonStringType; 31 import org.thingsboard.server.dao.util.mapping.JsonStringType;
29 32
30 import javax.persistence.Column; 33 import javax.persistence.Column;
@@ -74,7 +77,7 @@ public final class TenantProfileEntity extends BaseSqlEntity<TenantProfile> impl @@ -74,7 +77,7 @@ public final class TenantProfileEntity extends BaseSqlEntity<TenantProfile> impl
74 this.isDefault = tenantProfile.isDefault(); 77 this.isDefault = tenantProfile.isDefault();
75 this.isolatedTbCore = tenantProfile.isIsolatedTbCore(); 78 this.isolatedTbCore = tenantProfile.isIsolatedTbCore();
76 this.isolatedTbRuleEngine = tenantProfile.isIsolatedTbRuleEngine(); 79 this.isolatedTbRuleEngine = tenantProfile.isIsolatedTbRuleEngine();
77 - this.profileData = tenantProfile.getProfileData(); 80 + this.profileData = JacksonUtil.convertValue(tenantProfile.getProfileData(), ObjectNode.class);
78 } 81 }
79 82
80 @Override 83 @Override
@@ -100,9 +103,8 @@ public final class TenantProfileEntity extends BaseSqlEntity<TenantProfile> impl @@ -100,9 +103,8 @@ public final class TenantProfileEntity extends BaseSqlEntity<TenantProfile> impl
100 tenantProfile.setDefault(isDefault); 103 tenantProfile.setDefault(isDefault);
101 tenantProfile.setIsolatedTbCore(isolatedTbCore); 104 tenantProfile.setIsolatedTbCore(isolatedTbCore);
102 tenantProfile.setIsolatedTbRuleEngine(isolatedTbRuleEngine); 105 tenantProfile.setIsolatedTbRuleEngine(isolatedTbRuleEngine);
103 - tenantProfile.setProfileData(profileData); 106 + tenantProfile.setProfileData(JacksonUtil.convertValue(profileData, TenantProfileData.class));
104 return tenantProfile; 107 return tenantProfile;
105 } 108 }
106 109
107 -  
108 } 110 }
@@ -23,8 +23,10 @@ import org.springframework.cache.Cache; @@ -23,8 +23,10 @@ import org.springframework.cache.Cache;
23 import org.springframework.cache.CacheManager; 23 import org.springframework.cache.CacheManager;
24 import org.springframework.cache.annotation.Cacheable; 24 import org.springframework.cache.annotation.Cacheable;
25 import org.springframework.stereotype.Service; 25 import org.springframework.stereotype.Service;
  26 +import org.thingsboard.server.common.data.DeviceProfile;
26 import org.thingsboard.server.common.data.EntityInfo; 27 import org.thingsboard.server.common.data.EntityInfo;
27 import org.thingsboard.server.common.data.TenantProfile; 28 import org.thingsboard.server.common.data.TenantProfile;
  29 +import org.thingsboard.server.common.data.TenantProfileData;
28 import org.thingsboard.server.common.data.id.TenantId; 30 import org.thingsboard.server.common.data.id.TenantId;
29 import org.thingsboard.server.common.data.id.TenantProfileId; 31 import org.thingsboard.server.common.data.id.TenantProfileId;
30 import org.thingsboard.server.common.data.page.PageData; 32 import org.thingsboard.server.common.data.page.PageData;
@@ -107,8 +109,17 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T @@ -107,8 +109,17 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T
107 } 109 }
108 110
109 private void removeTenantProfile(TenantId tenantId, TenantProfileId tenantProfileId) { 111 private void removeTenantProfile(TenantId tenantId, TenantProfileId tenantProfileId) {
  112 + try {
  113 + tenantProfileDao.removeById(tenantId, tenantProfileId.getId());
  114 + } catch (Exception t) {
  115 + ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
  116 + if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_tenant_profile")) {
  117 + throw new DataValidationException("The tenant profile referenced by the tenants cannot be deleted!");
  118 + } else {
  119 + throw t;
  120 + }
  121 + }
110 deleteEntityRelations(tenantId, tenantProfileId); 122 deleteEntityRelations(tenantId, tenantProfileId);
111 - tenantProfileDao.removeById(tenantId, tenantProfileId.getId());  
112 Cache cache = cacheManager.getCache(TENANT_PROFILE_CACHE); 123 Cache cache = cacheManager.getCache(TENANT_PROFILE_CACHE);
113 cache.evict(Collections.singletonList(tenantProfileId.getId())); 124 cache.evict(Collections.singletonList(tenantProfileId.getId()));
114 cache.evict(Arrays.asList("info", tenantProfileId.getId())); 125 cache.evict(Arrays.asList("info", tenantProfileId.getId()));
@@ -136,7 +147,7 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T @@ -136,7 +147,7 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T
136 defaultTenantProfile = new TenantProfile(); 147 defaultTenantProfile = new TenantProfile();
137 defaultTenantProfile.setDefault(true); 148 defaultTenantProfile.setDefault(true);
138 defaultTenantProfile.setName("Default"); 149 defaultTenantProfile.setName("Default");
139 - defaultTenantProfile.setProfileData(JacksonUtil.OBJECT_MAPPER.createObjectNode()); 150 + defaultTenantProfile.setProfileData(new TenantProfileData());
140 defaultTenantProfile.setDescription("Default tenant profile"); 151 defaultTenantProfile.setDescription("Default tenant profile");
141 defaultTenantProfile.setIsolatedTbCore(false); 152 defaultTenantProfile.setIsolatedTbCore(false);
142 defaultTenantProfile.setIsolatedTbRuleEngine(false); 153 defaultTenantProfile.setIsolatedTbRuleEngine(false);
@@ -211,6 +222,18 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T @@ -211,6 +222,18 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T
211 } 222 }
212 } 223 }
213 } 224 }
  225 +
  226 + @Override
  227 + protected void validateUpdate(TenantId tenantId, TenantProfile tenantProfile) {
  228 + TenantProfile old = tenantProfileDao.findById(TenantId.SYS_TENANT_ID, tenantProfile.getId().getId());
  229 + if (old == null) {
  230 + throw new DataValidationException("Can't update non existing tenant profile!");
  231 + } else if (old.isIsolatedTbRuleEngine() != tenantProfile.isIsolatedTbRuleEngine()) {
  232 + throw new DataValidationException("Can't update isolatedTbRuleEngine property!");
  233 + } else if (old.isIsolatedTbCore() != tenantProfile.isIsolatedTbCore()) {
  234 + throw new DataValidationException("Can't update isolatedTbCore property!");
  235 + }
  236 + }
214 }; 237 };
215 238
216 private PaginatedRemover<String, TenantProfile> tenantProfilesRemover = 239 private PaginatedRemover<String, TenantProfile> tenantProfilesRemover =
@@ -163,12 +163,6 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @@ -163,12 +163,6 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
163 if (old == null) { 163 if (old == null) {
164 throw new DataValidationException("Can't update non existing tenant!"); 164 throw new DataValidationException("Can't update non existing tenant!");
165 } 165 }
166 - // TODO: Move validation to tenant profile  
167 - /* else if (old.isIsolatedTbRuleEngine() != tenant.isIsolatedTbRuleEngine()) {  
168 - throw new DataValidationException("Can't update isolatedTbRuleEngine property!");  
169 - } else if (old.isIsolatedTbCore() != tenant.isIsolatedTbCore()) {  
170 - throw new DataValidationException("Can't update isolatedTbCore property!");  
171 - } */  
172 } 166 }
173 }; 167 };
174 168
@@ -30,7 +30,7 @@ public class JacksonUtil { @@ -30,7 +30,7 @@ public class JacksonUtil {
30 30
31 public static <T> T convertValue(Object fromValue, Class<T> toValueType) { 31 public static <T> T convertValue(Object fromValue, Class<T> toValueType) {
32 try { 32 try {
33 - return OBJECT_MAPPER.convertValue(fromValue, toValueType); 33 + return fromValue != null ? OBJECT_MAPPER.convertValue(fromValue, toValueType) : null;
34 } catch (IllegalArgumentException e) { 34 } catch (IllegalArgumentException e) {
35 throw new IllegalArgumentException("The given object value: " 35 throw new IllegalArgumentException("The given object value: "
36 + fromValue + " cannot be converted to " + toValueType); 36 + fromValue + " cannot be converted to " + toValueType);
@@ -39,7 +39,7 @@ public class JacksonUtil { @@ -39,7 +39,7 @@ public class JacksonUtil {
39 39
40 public static <T> T fromString(String string, Class<T> clazz) { 40 public static <T> T fromString(String string, Class<T> clazz) {
41 try { 41 try {
42 - return OBJECT_MAPPER.readValue(string, clazz); 42 + return string != null ? OBJECT_MAPPER.readValue(string, clazz) : null;
43 } catch (IOException e) { 43 } catch (IOException e) {
44 throw new IllegalArgumentException("The given string value: " 44 throw new IllegalArgumentException("The given string value: "
45 + string + " cannot be transformed to Json object"); 45 + string + " cannot be transformed to Json object");
@@ -48,7 +48,7 @@ public class JacksonUtil { @@ -48,7 +48,7 @@ public class JacksonUtil {
48 48
49 public static String toString(Object value) { 49 public static String toString(Object value) {
50 try { 50 try {
51 - return OBJECT_MAPPER.writeValueAsString(value); 51 + return value != null ? OBJECT_MAPPER.writeValueAsString(value) : null;
52 } catch (JsonProcessingException e) { 52 } catch (JsonProcessingException e) {
53 throw new IllegalArgumentException("The given Json object value: " 53 throw new IllegalArgumentException("The given Json object value: "
54 + value + " cannot be transformed to a String"); 54 + value + " cannot be transformed to a String");
@@ -122,24 +122,12 @@ CREATE TABLE IF NOT EXISTS dashboard ( @@ -122,24 +122,12 @@ CREATE TABLE IF NOT EXISTS dashboard (
122 title varchar(255) 122 title varchar(255)
123 ); 123 );
124 124
125 -CREATE TABLE IF NOT EXISTS device (  
126 - id uuid NOT NULL CONSTRAINT device_pkey PRIMARY KEY,  
127 - created_time bigint NOT NULL,  
128 - additional_info varchar,  
129 - customer_id uuid,  
130 - device_profile_id uuid NOT NULL,  
131 - type varchar(255),  
132 - name varchar(255),  
133 - label varchar(255),  
134 - search_text varchar(255),  
135 - tenant_id uuid,  
136 - CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name)  
137 -);  
138 125
139 CREATE TABLE IF NOT EXISTS device_profile ( 126 CREATE TABLE IF NOT EXISTS device_profile (
140 id uuid NOT NULL CONSTRAINT device_profile_pkey PRIMARY KEY, 127 id uuid NOT NULL CONSTRAINT device_profile_pkey PRIMARY KEY,
141 created_time bigint NOT NULL, 128 created_time bigint NOT NULL,
142 name varchar(255), 129 name varchar(255),
  130 + type varchar(255),
143 profile_data varchar, 131 profile_data varchar,
144 description varchar, 132 description varchar,
145 search_text varchar(255), 133 search_text varchar(255),
@@ -149,6 +137,22 @@ CREATE TABLE IF NOT EXISTS device_profile ( @@ -149,6 +137,22 @@ CREATE TABLE IF NOT EXISTS device_profile (
149 CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name) 137 CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name)
150 ); 138 );
151 139
  140 +CREATE TABLE IF NOT EXISTS device (
  141 + id uuid NOT NULL CONSTRAINT device_pkey PRIMARY KEY,
  142 + created_time bigint NOT NULL,
  143 + additional_info varchar,
  144 + customer_id uuid,
  145 + device_profile_id uuid NOT NULL,
  146 + device_data varchar,
  147 + type varchar(255),
  148 + name varchar(255),
  149 + label varchar(255),
  150 + search_text varchar(255),
  151 + tenant_id uuid,
  152 + CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name),
  153 + CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id)
  154 +);
  155 +
152 CREATE TABLE IF NOT EXISTS device_credentials ( 156 CREATE TABLE IF NOT EXISTS device_credentials (
153 id uuid NOT NULL CONSTRAINT device_credentials_pkey PRIMARY KEY, 157 id uuid NOT NULL CONSTRAINT device_credentials_pkey PRIMARY KEY,
154 created_time bigint NOT NULL, 158 created_time bigint NOT NULL,
@@ -197,6 +201,19 @@ CREATE TABLE IF NOT EXISTS tb_user ( @@ -197,6 +201,19 @@ CREATE TABLE IF NOT EXISTS tb_user (
197 tenant_id uuid 201 tenant_id uuid
198 ); 202 );
199 203
  204 +CREATE TABLE IF NOT EXISTS tenant_profile (
  205 + id uuid NOT NULL CONSTRAINT tenant_profile_pkey PRIMARY KEY,
  206 + created_time bigint NOT NULL,
  207 + name varchar(255),
  208 + profile_data varchar,
  209 + description varchar,
  210 + search_text varchar(255),
  211 + is_default boolean,
  212 + isolated_tb_core boolean,
  213 + isolated_tb_rule_engine boolean,
  214 + CONSTRAINT tenant_profile_name_unq_key UNIQUE (name)
  215 +);
  216 +
200 CREATE TABLE IF NOT EXISTS tenant ( 217 CREATE TABLE IF NOT EXISTS tenant (
201 id uuid NOT NULL CONSTRAINT tenant_pkey PRIMARY KEY, 218 id uuid NOT NULL CONSTRAINT tenant_pkey PRIMARY KEY,
202 created_time bigint NOT NULL, 219 created_time bigint NOT NULL,
@@ -214,20 +231,8 @@ CREATE TABLE IF NOT EXISTS tenant ( @@ -214,20 +231,8 @@ CREATE TABLE IF NOT EXISTS tenant (
214 title varchar(255), 231 title varchar(255),
215 zip varchar(255), 232 zip varchar(255),
216 isolated_tb_core boolean, 233 isolated_tb_core boolean,
217 - isolated_tb_rule_engine boolean  
218 -);  
219 -  
220 -CREATE TABLE IF NOT EXISTS tenant_profile (  
221 - id uuid NOT NULL CONSTRAINT tenant_profile_pkey PRIMARY KEY,  
222 - created_time bigint NOT NULL,  
223 - name varchar(255),  
224 - profile_data varchar,  
225 - description varchar,  
226 - search_text varchar(255),  
227 - is_default boolean,  
228 - isolated_tb_core boolean,  
229 isolated_tb_rule_engine boolean, 234 isolated_tb_rule_engine boolean,
230 - CONSTRAINT tenant_profile_name_unq_key UNIQUE (name) 235 + CONSTRAINT fk_tenant_profile FOREIGN KEY (tenant_profile_id) REFERENCES tenant_profile(id)
231 ); 236 );
232 237
233 CREATE TABLE IF NOT EXISTS user_credentials ( 238 CREATE TABLE IF NOT EXISTS user_credentials (
@@ -139,24 +139,12 @@ CREATE TABLE IF NOT EXISTS dashboard ( @@ -139,24 +139,12 @@ CREATE TABLE IF NOT EXISTS dashboard (
139 title varchar(255) 139 title varchar(255)
140 ); 140 );
141 141
142 -CREATE TABLE IF NOT EXISTS device (  
143 - id uuid NOT NULL CONSTRAINT device_pkey PRIMARY KEY,  
144 - created_time bigint NOT NULL,  
145 - additional_info varchar,  
146 - customer_id uuid,  
147 - device_profile_id uuid NOT NULL,  
148 - type varchar(255),  
149 - name varchar(255),  
150 - label varchar(255),  
151 - search_text varchar(255),  
152 - tenant_id uuid,  
153 - CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name)  
154 -);  
155 142
156 CREATE TABLE IF NOT EXISTS device_profile ( 143 CREATE TABLE IF NOT EXISTS device_profile (
157 id uuid NOT NULL CONSTRAINT device_profile_pkey PRIMARY KEY, 144 id uuid NOT NULL CONSTRAINT device_profile_pkey PRIMARY KEY,
158 created_time bigint NOT NULL, 145 created_time bigint NOT NULL,
159 name varchar(255), 146 name varchar(255),
  147 + type varchar(255),
160 profile_data varchar, 148 profile_data varchar,
161 description varchar, 149 description varchar,
162 search_text varchar(255), 150 search_text varchar(255),
@@ -166,6 +154,22 @@ CREATE TABLE IF NOT EXISTS device_profile ( @@ -166,6 +154,22 @@ CREATE TABLE IF NOT EXISTS device_profile (
166 CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name) 154 CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name)
167 ); 155 );
168 156
  157 +CREATE TABLE IF NOT EXISTS device (
  158 + id uuid NOT NULL CONSTRAINT device_pkey PRIMARY KEY,
  159 + created_time bigint NOT NULL,
  160 + additional_info varchar,
  161 + customer_id uuid,
  162 + device_profile_id uuid NOT NULL,
  163 + device_data varchar,
  164 + type varchar(255),
  165 + name varchar(255),
  166 + label varchar(255),
  167 + search_text varchar(255),
  168 + tenant_id uuid,
  169 + CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name),
  170 + CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id)
  171 +);
  172 +
169 CREATE TABLE IF NOT EXISTS device_credentials ( 173 CREATE TABLE IF NOT EXISTS device_credentials (
170 id uuid NOT NULL CONSTRAINT device_credentials_pkey PRIMARY KEY, 174 id uuid NOT NULL CONSTRAINT device_credentials_pkey PRIMARY KEY,
171 created_time bigint NOT NULL, 175 created_time bigint NOT NULL,
@@ -221,6 +225,19 @@ CREATE TABLE IF NOT EXISTS tb_user ( @@ -221,6 +225,19 @@ CREATE TABLE IF NOT EXISTS tb_user (
221 tenant_id uuid 225 tenant_id uuid
222 ); 226 );
223 227
  228 +CREATE TABLE IF NOT EXISTS tenant_profile (
  229 + id uuid NOT NULL CONSTRAINT tenant_profile_pkey PRIMARY KEY,
  230 + created_time bigint NOT NULL,
  231 + name varchar(255),
  232 + profile_data varchar,
  233 + description varchar,
  234 + search_text varchar(255),
  235 + is_default boolean,
  236 + isolated_tb_core boolean,
  237 + isolated_tb_rule_engine boolean,
  238 + CONSTRAINT tenant_profile_name_unq_key UNIQUE (name)
  239 +);
  240 +
224 CREATE TABLE IF NOT EXISTS tenant ( 241 CREATE TABLE IF NOT EXISTS tenant (
225 id uuid NOT NULL CONSTRAINT tenant_pkey PRIMARY KEY, 242 id uuid NOT NULL CONSTRAINT tenant_pkey PRIMARY KEY,
226 created_time bigint NOT NULL, 243 created_time bigint NOT NULL,
@@ -238,20 +255,8 @@ CREATE TABLE IF NOT EXISTS tenant ( @@ -238,20 +255,8 @@ CREATE TABLE IF NOT EXISTS tenant (
238 title varchar(255), 255 title varchar(255),
239 zip varchar(255), 256 zip varchar(255),
240 isolated_tb_core boolean, 257 isolated_tb_core boolean,
241 - isolated_tb_rule_engine boolean  
242 -);  
243 -  
244 -CREATE TABLE IF NOT EXISTS tenant_profile (  
245 - id uuid NOT NULL CONSTRAINT tenant_profile_pkey PRIMARY KEY,  
246 - created_time bigint NOT NULL,  
247 - name varchar(255),  
248 - profile_data varchar,  
249 - description varchar,  
250 - search_text varchar(255),  
251 - is_default boolean,  
252 - isolated_tb_core boolean,  
253 isolated_tb_rule_engine boolean, 258 isolated_tb_rule_engine boolean,
254 - CONSTRAINT tenant_profile_name_unq_key UNIQUE (name) 259 + CONSTRAINT fk_tenant_profile FOREIGN KEY (tenant_profile_id) REFERENCES tenant_profile(id)
255 ); 260 );
256 261
257 CREATE TABLE IF NOT EXISTS user_credentials ( 262 CREATE TABLE IF NOT EXISTS user_credentials (
@@ -28,10 +28,15 @@ import org.springframework.test.context.ContextConfiguration; @@ -28,10 +28,15 @@ import org.springframework.test.context.ContextConfiguration;
28 import org.springframework.test.context.junit4.SpringRunner; 28 import org.springframework.test.context.junit4.SpringRunner;
29 import org.springframework.test.context.support.AnnotationConfigContextLoader; 29 import org.springframework.test.context.support.AnnotationConfigContextLoader;
30 import org.thingsboard.server.common.data.BaseData; 30 import org.thingsboard.server.common.data.BaseData;
  31 +import org.thingsboard.server.common.data.DeviceProfile;
  32 +import org.thingsboard.server.common.data.DeviceProfileType;
31 import org.thingsboard.server.common.data.EntityType; 33 import org.thingsboard.server.common.data.EntityType;
32 import org.thingsboard.server.common.data.Event; 34 import org.thingsboard.server.common.data.Event;
  35 +import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
  36 +import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
33 import org.thingsboard.server.common.data.id.EntityId; 37 import org.thingsboard.server.common.data.id.EntityId;
34 import org.thingsboard.server.common.data.id.HasId; 38 import org.thingsboard.server.common.data.id.HasId;
  39 +import org.thingsboard.server.common.data.id.RuleChainId;
35 import org.thingsboard.server.common.data.id.TenantId; 40 import org.thingsboard.server.common.data.id.TenantId;
36 import org.thingsboard.server.common.data.id.UUIDBased; 41 import org.thingsboard.server.common.data.id.UUIDBased;
37 import org.thingsboard.server.dao.alarm.AlarmService; 42 import org.thingsboard.server.dao.alarm.AlarmService;
@@ -187,4 +192,19 @@ public abstract class AbstractServiceTest { @@ -187,4 +192,19 @@ public abstract class AbstractServiceTest {
187 return new AuditLogLevelFilter(mask); 192 return new AuditLogLevelFilter(mask);
188 } 193 }
189 194
  195 + protected DeviceProfile createDeviceProfile(TenantId tenantId, String name) {
  196 + DeviceProfile deviceProfile = new DeviceProfile();
  197 + deviceProfile.setTenantId(tenantId);
  198 + deviceProfile.setName(name);
  199 + deviceProfile.setType(DeviceProfileType.DEFAULT);
  200 + deviceProfile.setDescription(name + " Test");
  201 + DeviceProfileData deviceProfileData = new DeviceProfileData();
  202 + DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
  203 + deviceProfileData.setConfiguration(configuration);
  204 + deviceProfile.setProfileData(deviceProfileData);
  205 + deviceProfile.setDefault(false);
  206 + deviceProfile.setDefaultRuleChainId(new RuleChainId(Uuids.timeBased()));
  207 + return deviceProfile;
  208 + }
  209 +
190 } 210 }
@@ -15,20 +15,19 @@ @@ -15,20 +15,19 @@
15 */ 15 */
16 package org.thingsboard.server.dao.service; 16 package org.thingsboard.server.dao.service;
17 17
18 -import com.datastax.oss.driver.api.core.uuid.Uuids;  
19 import org.junit.After; 18 import org.junit.After;
20 import org.junit.Assert; 19 import org.junit.Assert;
21 import org.junit.Before; 20 import org.junit.Before;
22 import org.junit.Test; 21 import org.junit.Test;
  22 +import org.thingsboard.server.common.data.Device;
23 import org.thingsboard.server.common.data.DeviceProfile; 23 import org.thingsboard.server.common.data.DeviceProfile;
  24 +import org.thingsboard.server.common.data.DeviceProfileType;
24 import org.thingsboard.server.common.data.EntityInfo; 25 import org.thingsboard.server.common.data.EntityInfo;
25 import org.thingsboard.server.common.data.Tenant; 26 import org.thingsboard.server.common.data.Tenant;
26 -import org.thingsboard.server.common.data.id.RuleChainId;  
27 import org.thingsboard.server.common.data.id.TenantId; 27 import org.thingsboard.server.common.data.id.TenantId;
28 import org.thingsboard.server.common.data.page.PageData; 28 import org.thingsboard.server.common.data.page.PageData;
29 import org.thingsboard.server.common.data.page.PageLink; 29 import org.thingsboard.server.common.data.page.PageLink;
30 import org.thingsboard.server.dao.exception.DataValidationException; 30 import org.thingsboard.server.dao.exception.DataValidationException;
31 -import org.thingsboard.server.dao.util.mapping.JacksonUtil;  
32 31
33 import java.util.ArrayList; 32 import java.util.ArrayList;
34 import java.util.Collections; 33 import java.util.Collections;
@@ -58,7 +57,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -58,7 +57,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
58 57
59 @Test 58 @Test
60 public void testSaveDeviceProfile() { 59 public void testSaveDeviceProfile() {
61 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 60 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile");
62 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); 61 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
63 Assert.assertNotNull(savedDeviceProfile); 62 Assert.assertNotNull(savedDeviceProfile);
64 Assert.assertNotNull(savedDeviceProfile.getId()); 63 Assert.assertNotNull(savedDeviceProfile.getId());
@@ -76,7 +75,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -76,7 +75,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
76 75
77 @Test 76 @Test
78 public void testFindDeviceProfileById() { 77 public void testFindDeviceProfileById() {
79 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 78 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");
80 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); 79 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
81 DeviceProfile foundDeviceProfile = deviceProfileService.findDeviceProfileById(tenantId, savedDeviceProfile.getId()); 80 DeviceProfile foundDeviceProfile = deviceProfileService.findDeviceProfileById(tenantId, savedDeviceProfile.getId());
82 Assert.assertNotNull(foundDeviceProfile); 81 Assert.assertNotNull(foundDeviceProfile);
@@ -85,7 +84,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -85,7 +84,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
85 84
86 @Test 85 @Test
87 public void testFindDeviceProfileInfoById() { 86 public void testFindDeviceProfileInfoById() {
88 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 87 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");
89 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); 88 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
90 EntityInfo foundDeviceProfileInfo = deviceProfileService.findDeviceProfileInfoById(tenantId, savedDeviceProfile.getId()); 89 EntityInfo foundDeviceProfileInfo = deviceProfileService.findDeviceProfileInfoById(tenantId, savedDeviceProfile.getId());
91 Assert.assertNotNull(foundDeviceProfileInfo); 90 Assert.assertNotNull(foundDeviceProfileInfo);
@@ -111,8 +110,8 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -111,8 +110,8 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
111 110
112 @Test 111 @Test
113 public void testSetDefaultDeviceProfile() { 112 public void testSetDefaultDeviceProfile() {
114 - DeviceProfile deviceProfile1 = this.createDeviceProfile("Device Profile 1");  
115 - DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile 2"); 113 + DeviceProfile deviceProfile1 = this.createDeviceProfile(tenantId,"Device Profile 1");
  114 + DeviceProfile deviceProfile2 = this.createDeviceProfile(tenantId,"Device Profile 2");
116 115
117 DeviceProfile savedDeviceProfile1 = deviceProfileService.saveDeviceProfile(deviceProfile1); 116 DeviceProfile savedDeviceProfile1 = deviceProfileService.saveDeviceProfile(deviceProfile1);
118 DeviceProfile savedDeviceProfile2 = deviceProfileService.saveDeviceProfile(deviceProfile2); 117 DeviceProfile savedDeviceProfile2 = deviceProfileService.saveDeviceProfile(deviceProfile2);
@@ -138,15 +137,36 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -138,15 +137,36 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
138 137
139 @Test(expected = DataValidationException.class) 138 @Test(expected = DataValidationException.class)
140 public void testSaveDeviceProfileWithSameName() { 139 public void testSaveDeviceProfileWithSameName() {
141 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 140 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");
142 deviceProfileService.saveDeviceProfile(deviceProfile); 141 deviceProfileService.saveDeviceProfile(deviceProfile);
143 - DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile"); 142 + DeviceProfile deviceProfile2 = this.createDeviceProfile(tenantId,"Device Profile");
144 deviceProfileService.saveDeviceProfile(deviceProfile2); 143 deviceProfileService.saveDeviceProfile(deviceProfile2);
145 } 144 }
146 145
  146 + @Test(expected = DataValidationException.class)
  147 + public void testSaveSameDeviceProfileWithDifferentType() {
  148 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");
  149 + DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
  150 + savedDeviceProfile.setType(DeviceProfileType.LWM2M);
  151 + deviceProfileService.saveDeviceProfile(savedDeviceProfile);
  152 + }
  153 +
  154 + @Test(expected = DataValidationException.class)
  155 + public void testDeleteDeviceProfileWithExistingDevice() {
  156 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");
  157 + DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
  158 + Device device = new Device();
  159 + device.setTenantId(tenantId);
  160 + device.setName("Test device");
  161 + device.setType("default");
  162 + device.setDeviceProfileId(savedDeviceProfile.getId());
  163 + deviceService.saveDevice(device);
  164 + deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId());
  165 + }
  166 +
147 @Test 167 @Test
148 public void testDeleteDeviceProfile() { 168 public void testDeleteDeviceProfile() {
149 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 169 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");
150 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); 170 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
151 deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId()); 171 deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId());
152 DeviceProfile foundDeviceProfile = deviceProfileService.findDeviceProfileById(tenantId, savedDeviceProfile.getId()); 172 DeviceProfile foundDeviceProfile = deviceProfileService.findDeviceProfileById(tenantId, savedDeviceProfile.getId());
@@ -164,7 +184,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -164,7 +184,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
164 deviceProfiles.addAll(pageData.getData()); 184 deviceProfiles.addAll(pageData.getData());
165 185
166 for (int i=0;i<28;i++) { 186 for (int i=0;i<28;i++) {
167 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i); 187 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile"+i);
168 deviceProfiles.add(deviceProfileService.saveDeviceProfile(deviceProfile)); 188 deviceProfiles.add(deviceProfileService.saveDeviceProfile(deviceProfile));
169 } 189 }
170 190
@@ -206,7 +226,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -206,7 +226,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
206 deviceProfiles.addAll(deviceProfilePageData.getData()); 226 deviceProfiles.addAll(deviceProfilePageData.getData());
207 227
208 for (int i=0;i<28;i++) { 228 for (int i=0;i<28;i++) {
209 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i); 229 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile"+i);
210 deviceProfiles.add(deviceProfileService.saveDeviceProfile(deviceProfile)); 230 deviceProfiles.add(deviceProfileService.saveDeviceProfile(deviceProfile));
211 } 231 }
212 232
@@ -242,15 +262,6 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -242,15 +262,6 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
242 Assert.assertEquals(1, pageData.getTotalElements()); 262 Assert.assertEquals(1, pageData.getTotalElements());
243 } 263 }
244 264
245 - private DeviceProfile createDeviceProfile(String name) {  
246 - DeviceProfile deviceProfile = new DeviceProfile();  
247 - deviceProfile.setTenantId(tenantId);  
248 - deviceProfile.setName(name);  
249 - deviceProfile.setDescription(name + " Test");  
250 - deviceProfile.setProfileData(JacksonUtil.OBJECT_MAPPER.createObjectNode());  
251 - deviceProfile.setDefault(false);  
252 - deviceProfile.setDefaultRuleChainId(new RuleChainId(Uuids.timeBased()));  
253 - return deviceProfile;  
254 - } 265 +
255 266
256 } 267 }
@@ -127,6 +127,23 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { @@ -127,6 +127,23 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
127 deviceService.deleteDevice(tenantId, device.getId()); 127 deviceService.deleteDevice(tenantId, device.getId());
128 } 128 }
129 } 129 }
  130 +
  131 + @Test(expected = DataValidationException.class)
  132 + public void testSaveSameDeviceWithDifferentDeviceProfileId() {
  133 + Device device = new Device();
  134 + device.setName("My device");
  135 + device.setType("default");
  136 + device.setTenantId(tenantId);
  137 + device = deviceService.saveDevice(device);
  138 + DeviceProfile deviceProfile2 = this.createDeviceProfile(tenantId,"Device Profile 2");
  139 + DeviceProfile savedDeviceProfile2 = deviceProfileService.saveDeviceProfile(deviceProfile2);
  140 + device.setDeviceProfileId(savedDeviceProfile2.getId());
  141 + try {
  142 + deviceService.saveDevice(device);
  143 + } finally {
  144 + deviceService.deleteDevice(tenantId, device.getId());
  145 + }
  146 + }
130 147
131 @Test(expected = DataValidationException.class) 148 @Test(expected = DataValidationException.class)
132 public void testAssignDeviceToCustomerFromDifferentTenant() { 149 public void testAssignDeviceToCustomerFromDifferentTenant() {
@@ -19,7 +19,9 @@ import org.junit.After; @@ -19,7 +19,9 @@ import org.junit.After;
19 import org.junit.Assert; 19 import org.junit.Assert;
20 import org.junit.Test; 20 import org.junit.Test;
21 import org.thingsboard.server.common.data.EntityInfo; 21 import org.thingsboard.server.common.data.EntityInfo;
  22 +import org.thingsboard.server.common.data.Tenant;
22 import org.thingsboard.server.common.data.TenantProfile; 23 import org.thingsboard.server.common.data.TenantProfile;
  24 +import org.thingsboard.server.common.data.TenantProfileData;
23 import org.thingsboard.server.common.data.id.TenantId; 25 import org.thingsboard.server.common.data.id.TenantId;
24 import org.thingsboard.server.common.data.id.TenantProfileId; 26 import org.thingsboard.server.common.data.id.TenantProfileId;
25 import org.thingsboard.server.common.data.page.PageData; 27 import org.thingsboard.server.common.data.page.PageData;
@@ -136,6 +138,37 @@ public class BaseTenantProfileServiceTest extends AbstractServiceTest { @@ -136,6 +138,37 @@ public class BaseTenantProfileServiceTest extends AbstractServiceTest {
136 tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile2); 138 tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile2);
137 } 139 }
138 140
  141 + @Test(expected = DataValidationException.class)
  142 + public void testSaveSameTenantProfileWithDifferentIsolatedTbRuleEngine() {
  143 + TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
  144 + TenantProfile savedTenantProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile);
  145 + savedTenantProfile.setIsolatedTbRuleEngine(true);
  146 + tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, savedTenantProfile);
  147 + }
  148 +
  149 + @Test(expected = DataValidationException.class)
  150 + public void testSaveSameTenantProfileWithDifferentIsolatedTbCore() {
  151 + TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
  152 + TenantProfile savedTenantProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile);
  153 + savedTenantProfile.setIsolatedTbCore(true);
  154 + tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, savedTenantProfile);
  155 + }
  156 +
  157 + @Test(expected = DataValidationException.class)
  158 + public void testDeleteTenantProfileWithExistingTenant() {
  159 + TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
  160 + TenantProfile savedTenantProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile);
  161 + Tenant tenant = new Tenant();
  162 + tenant.setTitle("Test tenant");
  163 + tenant.setTenantProfileId(savedTenantProfile.getId());
  164 + tenant = tenantService.saveTenant(tenant);
  165 + try {
  166 + tenantProfileService.deleteTenantProfile(TenantId.SYS_TENANT_ID, savedTenantProfile.getId());
  167 + } finally {
  168 + tenantService.deleteTenant(tenant.getId());
  169 + }
  170 + }
  171 +
139 @Test 172 @Test
140 public void testDeleteTenantProfile() { 173 public void testDeleteTenantProfile() {
141 TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile"); 174 TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
@@ -230,7 +263,7 @@ public class BaseTenantProfileServiceTest extends AbstractServiceTest { @@ -230,7 +263,7 @@ public class BaseTenantProfileServiceTest extends AbstractServiceTest {
230 TenantProfile tenantProfile = new TenantProfile(); 263 TenantProfile tenantProfile = new TenantProfile();
231 tenantProfile.setName(name); 264 tenantProfile.setName(name);
232 tenantProfile.setDescription(name + " Test"); 265 tenantProfile.setDescription(name + " Test");
233 - tenantProfile.setProfileData(JacksonUtil.OBJECT_MAPPER.createObjectNode()); 266 + tenantProfile.setProfileData(new TenantProfileData());
234 tenantProfile.setDefault(false); 267 tenantProfile.setDefault(false);
235 tenantProfile.setIsolatedTbCore(false); 268 tenantProfile.setIsolatedTbCore(false);
236 tenantProfile.setIsolatedTbRuleEngine(false); 269 tenantProfile.setIsolatedTbRuleEngine(false);