Browse Source

Tenant and Device profile improvements

pull/3477/head
Igor Kulikov 6 years ago
parent
commit
ad87924437
  1. 20
      application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
  2. 16
      application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java
  3. 40
      application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java
  4. 49
      application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java
  5. 42
      common/data/src/main/java/org/thingsboard/server/common/data/Device.java
  6. 41
      common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java
  7. 21
      common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileType.java
  8. 4
      common/data/src/main/java/org/thingsboard/server/common/data/SearchTextBasedWithAdditionalInfo.java
  9. 39
      common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java
  10. 40
      common/data/src/main/java/org/thingsboard/server/common/data/TenantProfileData.java
  11. 29
      common/data/src/main/java/org/thingsboard/server/common/data/device/data/DefaultDeviceConfiguration.java
  12. 37
      common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceConfiguration.java
  13. 25
      common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceData.java
  14. 29
      common/data/src/main/java/org/thingsboard/server/common/data/device/data/Lwm2mDeviceConfiguration.java
  15. 29
      common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DefaultDeviceProfileConfiguration.java
  16. 37
      common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileConfiguration.java
  17. 25
      common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileData.java
  18. 29
      common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileConfiguration.java
  19. 30
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java
  20. 11
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java
  21. 3
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  22. 10
      dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java
  23. 16
      dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java
  24. 8
      dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java
  25. 27
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java
  26. 6
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java
  27. 6
      dao/src/main/java/org/thingsboard/server/dao/util/mapping/JacksonUtil.java
  28. 57
      dao/src/main/resources/sql/schema-entities-hsql.sql
  29. 57
      dao/src/main/resources/sql/schema-entities.sql
  30. 20
      dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java
  31. 57
      dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java
  32. 17
      dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java
  33. 35
      dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java

20
application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.controller;
import com.datastax.oss.driver.api.core.uuid.Uuids;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -59,9 +60,14 @@ import org.springframework.util.MultiValueMap;
import org.springframework.web.context.WebApplicationContext;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.data.page.PageLink;
@ -305,6 +311,20 @@ public abstract class AbstractWebTest {
}
}
protected DeviceProfile createDeviceProfile(String name) {
DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setName(name);
deviceProfile.setType(DeviceProfileType.DEFAULT);
deviceProfile.setDescription(name + " Test");
DeviceProfileData deviceProfileData = new DeviceProfileData();
DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
deviceProfileData.setConfiguration(configuration);
deviceProfile.setProfileData(deviceProfileData);
deviceProfile.setDefault(false);
deviceProfile.setDefaultRuleChainId(new RuleChainId(Uuids.timeBased()));
return deviceProfile;
}
protected ResultActions doGet(String urlTemplate, Object... urlVariables) throws Exception {
MockHttpServletRequestBuilder getRequest = get(urlTemplate, urlVariables);
setJwtToken(getRequest);

16
application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java

@ -24,6 +24,7 @@ import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
@ -236,6 +237,21 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
.andExpect(status().isNotFound());
}
@Test
public void testSaveSameDeviceWithDifferentDeviceProfileId() throws Exception {
Device device = new Device();
device.setName("My device");
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile 2");
DeviceProfile savedDeviceProfile2 = doPost("/api/deviceProfile", deviceProfile2, DeviceProfile.class);
savedDevice.setDeviceProfileId(savedDeviceProfile2.getId());
doPost("/api/device/", savedDevice).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Changing device profile is prohibited")));
}
@Test
public void testAssignDeviceToCustomerFromDifferentTenant() throws Exception {
loginSysAdmin();

40
application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java

@ -15,21 +15,20 @@
*/
package org.thingsboard.server.controller;
import com.datastax.oss.driver.api.core.uuid.Uuids;
import com.fasterxml.jackson.core.type.TypeReference;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import java.util.ArrayList;
import java.util.Collections;
@ -148,6 +147,32 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
.andExpect(statusReason(containsString("Device profile with such name already exists")));
}
@Test
public void testSaveSameDeviceProfileWithDifferentType() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
savedDeviceProfile.setType(DeviceProfileType.LWM2M);
doPost("/api/deviceProfile", savedDeviceProfile).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Changing type of device profile is prohibited")));
}
@Test
public void testDeleteDeviceProfileWithExistingDevice() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
Device device = new Device();
device.setName("Test device");
device.setType("default");
device.setDeviceProfileId(savedDeviceProfile.getId());
Device savedDevice = doPost("/api/device", device, Device.class);
doDelete("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString())
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("The device profile referenced by the devices cannot be deleted")));
}
@Test
public void testDeleteDeviceProfile() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
@ -254,13 +279,4 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
Assert.assertEquals(1, pageData.getTotalElements());
}
private DeviceProfile createDeviceProfile(String name) {
DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setName(name);
deviceProfile.setDescription(name + " Test");
deviceProfile.setProfileData(JacksonUtil.OBJECT_MAPPER.createObjectNode());
deviceProfile.setDefault(false);
deviceProfile.setDefaultRuleChainId(new RuleChainId(Uuids.timeBased()));
return deviceProfile;
}
}

49
application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java

@ -20,16 +20,14 @@ import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.TenantProfileData;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.tenant.TenantProfileService;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import java.util.ArrayList;
import java.util.Collections;
@ -48,7 +46,9 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController
private TenantProfileService tenantProfileService;
@After
public void after() {
@Override
public void teardown() throws Exception {
super.teardown();
tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID);
}
@ -133,6 +133,45 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController
.andExpect(statusReason(containsString("Tenant profile with such name already exists")));
}
@Test
public void testSaveSameTenantProfileWithDifferentIsolatedTbRuleEngine() throws Exception {
loginSysAdmin();
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class);
savedTenantProfile.setIsolatedTbRuleEngine(true);
doPost("/api/tenantProfile", savedTenantProfile).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Can't update isolatedTbRuleEngine property")));
}
@Test
public void testSaveSameTenantProfileWithDifferentIsolatedTbCore() throws Exception {
loginSysAdmin();
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class);
savedTenantProfile.setIsolatedTbCore(true);
doPost("/api/tenantProfile", savedTenantProfile).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Can't update isolatedTbCore property")));
}
@Test
public void testDeleteTenantProfileWithExistingTenant() throws Exception {
loginSysAdmin();
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class);
Tenant tenant = new Tenant();
tenant.setTitle("My tenant with tenant profile");
tenant.setTenantProfileId(savedTenantProfile.getId());
Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
doDelete("/api/tenantProfile/" + savedTenantProfile.getId().getId().toString())
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("The tenant profile referenced by the tenants cannot be deleted")));
doDelete("/api/tenant/"+savedTenant.getId().getId().toString())
.andExpect(status().isOk());
}
@Test
public void testDeleteTenantProfile() throws Exception {
loginSysAdmin();
@ -246,7 +285,7 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController
TenantProfile tenantProfile = new TenantProfile();
tenantProfile.setName(name);
tenantProfile.setDescription(name + " Test");
tenantProfile.setProfileData(JacksonUtil.OBJECT_MAPPER.createObjectNode());
tenantProfile.setProfileData(new TenantProfileData());
tenantProfile.setDefault(false);
tenantProfile.setIsolatedTbCore(false);
tenantProfile.setIsolatedTbRuleEngine(false);

42
common/data/src/main/java/org/thingsboard/server/common/data/Device.java

@ -15,13 +15,22 @@
*/
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.device.data.DeviceData;
import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.TenantId;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@EqualsAndHashCode(callSuper = true)
@Slf4j
public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implements HasName, HasTenantId, HasCustomerId {
private static final long serialVersionUID = 2807343040519543363L;
@ -32,6 +41,9 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
private String type;
private String label;
private DeviceProfileId deviceProfileId;
private transient DeviceData deviceData;
@JsonIgnore
private byte[] deviceDataBytes;
public Device() {
super();
@ -49,6 +61,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
this.type = device.getType();
this.label = device.getLabel();
this.deviceProfileId = device.getDeviceProfileId();
this.setDeviceData(device.getDeviceData());
}
public TenantId getTenantId() {
@ -100,6 +113,33 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
this.deviceProfileId = deviceProfileId;
}
public DeviceData getDeviceData() {
if (deviceData != null) {
return deviceData;
} else {
if (deviceDataBytes != null) {
try {
deviceData = mapper.readValue(new ByteArrayInputStream(deviceDataBytes), DeviceData.class);
} catch (IOException e) {
log.warn("Can't deserialize device data: ", e);
return null;
}
return deviceData;
} else {
return null;
}
}
}
public void setDeviceData(DeviceData data) {
this.deviceData = data;
try {
this.deviceDataBytes = data != null ? mapper.writeValueAsBytes(data) : null;
} catch (JsonProcessingException e) {
log.warn("Can't serialize device data: ", e);
}
}
@Override
public String getSearchText() {
return getName();
@ -120,6 +160,8 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
builder.append(label);
builder.append(", deviceProfileId=");
builder.append(deviceProfileId);
builder.append(", deviceData=");
builder.append(deviceData);
builder.append(", additionalInfo=");
builder.append(getAdditionalInfo());
builder.append(", createdTime=");

41
common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java

@ -16,26 +16,32 @@
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.getJson;
import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.setJson;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.mapper;
@Data
@EqualsAndHashCode(callSuper = true)
@Slf4j
public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements HasName, HasTenantId {
private TenantId tenantId;
private String name;
private String description;
private boolean isDefault;
private DeviceProfileType type;
private RuleChainId defaultRuleChainId;
private transient JsonNode profileData;
private transient DeviceProfileData profileData;
@JsonIgnore
private byte[] profileDataBytes;
@ -67,12 +73,31 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
return name;
}
public JsonNode getProfileData() {
return getJson(() -> profileData, () -> profileDataBytes);
public DeviceProfileData getProfileData() {
if (profileData != null) {
return profileData;
} else {
if (profileDataBytes != null) {
try {
profileData = mapper.readValue(new ByteArrayInputStream(profileDataBytes), DeviceProfileData.class);
} catch (IOException e) {
log.warn("Can't deserialize device profile data: ", e);
return null;
}
return profileData;
} else {
return null;
}
}
}
public void setProfileData(JsonNode data) {
setJson(data, json -> this.profileData = json, bytes -> this.profileDataBytes = bytes);
public void setProfileData(DeviceProfileData data) {
this.profileData = data;
try {
this.profileDataBytes = data != null ? mapper.writeValueAsBytes(data) : null;
} catch (JsonProcessingException e) {
log.warn("Can't serialize device profile data: ", e);
}
}
}

21
common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileType.java

@ -0,0 +1,21 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data;
public enum DeviceProfileType {
DEFAULT,
LWM2M
}

4
common/data/src/main/java/org/thingsboard/server/common/data/SearchTextBasedWithAdditionalInfo.java

@ -35,7 +35,7 @@ import java.util.function.Consumer;
@Slf4j
public abstract class SearchTextBasedWithAdditionalInfo<I extends UUIDBased> extends SearchTextBased<I> implements HasAdditionalInfo {
private static final ObjectMapper mapper = new ObjectMapper();
public static final ObjectMapper mapper = new ObjectMapper();
private transient JsonNode additionalInfo;
@JsonIgnore
private byte[] additionalInfoBytes;
@ -84,7 +84,7 @@ public abstract class SearchTextBasedWithAdditionalInfo<I extends UUIDBased> ext
byte[] data = binaryData.get();
if (data != null) {
try {
return new ObjectMapper().readTree(new ByteArrayInputStream(data));
return mapper.readTree(new ByteArrayInputStream(data));
} catch (IOException e) {
log.warn("Can't deserialize json data: ", e);
return null;

39
common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java

@ -16,16 +16,20 @@
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.TenantProfileId;
import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.getJson;
import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.setJson;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.mapper;
@Data
@EqualsAndHashCode(callSuper = true)
@Slf4j
public class TenantProfile extends SearchTextBased<TenantProfileId> implements HasName {
private String name;
@ -33,7 +37,7 @@ public class TenantProfile extends SearchTextBased<TenantProfileId> implements H
private boolean isDefault;
private boolean isolatedTbCore;
private boolean isolatedTbRuleEngine;
private transient JsonNode profileData;
private transient TenantProfileData profileData;
@JsonIgnore
private byte[] profileDataBytes;
@ -65,12 +69,31 @@ public class TenantProfile extends SearchTextBased<TenantProfileId> implements H
return name;
}
public JsonNode getProfileData() {
return getJson(() -> profileData, () -> profileDataBytes);
public TenantProfileData getProfileData() {
if (profileData != null) {
return profileData;
} else {
if (profileDataBytes != null) {
try {
profileData = mapper.readValue(new ByteArrayInputStream(profileDataBytes), TenantProfileData.class);
} catch (IOException e) {
log.warn("Can't deserialize tenant profile data: ", e);
return null;
}
return profileData;
} else {
return null;
}
}
}
public void setProfileData(JsonNode data) {
setJson(data, json -> this.profileData = json, bytes -> this.profileDataBytes = bytes);
public void setProfileData(TenantProfileData data) {
this.profileData = data;
try {
this.profileDataBytes = data != null ? mapper.writeValueAsBytes(data) : null;
} catch (JsonProcessingException e) {
log.warn("Can't serialize tenant profile data: ", e);
}
}
}

40
common/data/src/main/java/org/thingsboard/server/common/data/TenantProfileData.java

@ -0,0 +1,40 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data
public class TenantProfileData {
private Map<String, String> properties = new HashMap<>();
@JsonAnyGetter
public Map<String, String> properties() {
return this.properties;
}
@JsonAnySetter
public void put(String name, String value) {
this.properties.put(name, value);
}
}

29
common/data/src/main/java/org/thingsboard/server/common/data/device/data/DefaultDeviceConfiguration.java

@ -0,0 +1,29 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.device.data;
import lombok.Data;
import org.thingsboard.server.common.data.DeviceProfileType;
@Data
public class DefaultDeviceConfiguration implements DeviceConfiguration {
@Override
public DeviceProfileType getType() {
return DeviceProfileType.DEFAULT;
}
}

37
common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceConfiguration.java

@ -0,0 +1,37 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.device.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.thingsboard.server.common.data.DeviceProfileType;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = DefaultDeviceConfiguration.class, name = "DEFAULT"),
@JsonSubTypes.Type(value = Lwm2mDeviceConfiguration.class, name = "LWM2M")})
public interface DeviceConfiguration {
@JsonIgnore
DeviceProfileType getType();
}

25
common/data/src/main/java/org/thingsboard/server/common/data/device/data/DeviceData.java

@ -0,0 +1,25 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.device.data;
import lombok.Data;
@Data
public class DeviceData {
private DeviceConfiguration configuration;
}

29
common/data/src/main/java/org/thingsboard/server/common/data/device/data/Lwm2mDeviceConfiguration.java

@ -0,0 +1,29 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.device.data;
import lombok.Data;
import org.thingsboard.server.common.data.DeviceProfileType;
@Data
public class Lwm2mDeviceConfiguration implements DeviceConfiguration {
@Override
public DeviceProfileType getType() {
return DeviceProfileType.LWM2M;
}
}

29
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DefaultDeviceProfileConfiguration.java

@ -0,0 +1,29 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.device.profile;
import lombok.Data;
import org.thingsboard.server.common.data.DeviceProfileType;
@Data
public class DefaultDeviceProfileConfiguration implements DeviceProfileConfiguration {
@Override
public DeviceProfileType getType() {
return DeviceProfileType.DEFAULT;
}
}

37
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileConfiguration.java

@ -0,0 +1,37 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.device.profile;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.thingsboard.server.common.data.DeviceProfileType;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = DefaultDeviceProfileConfiguration.class, name = "DEFAULT"),
@JsonSubTypes.Type(value = Lwm2mDeviceProfileConfiguration.class, name = "LWM2M")})
public interface DeviceProfileConfiguration {
@JsonIgnore
DeviceProfileType getType();
}

25
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileData.java

@ -0,0 +1,25 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.device.profile;
import lombok.Data;
@Data
public class DeviceProfileData {
private DeviceProfileConfiguration configuration;
}

29
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileConfiguration.java

@ -0,0 +1,29 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.device.profile;
import lombok.Data;
import org.thingsboard.server.common.data.DeviceProfileType;
@Data
public class Lwm2mDeviceProfileConfiguration implements DeviceProfileConfiguration {
@Override
public DeviceProfileType getType() {
return DeviceProfileType.LWM2M;
}
}

30
dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java

@ -24,8 +24,11 @@ import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
@ -113,8 +116,17 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
}
private void removeDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId) {
try {
deviceProfileDao.removeById(tenantId, deviceProfileId.getId());
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_device_profile")) {
throw new DataValidationException("The device profile referenced by the devices cannot be deleted!");
} else {
throw t;
}
}
deleteEntityRelations(tenantId, deviceProfileId);
deviceProfileDao.removeById(tenantId, deviceProfileId.getId());
Cache cache = cacheManager.getCache(DEVICE_PROFILE_CACHE);
cache.evict(Collections.singletonList(deviceProfileId.getId()));
cache.evict(Arrays.asList("info", deviceProfileId.getId()));
@ -144,8 +156,12 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
deviceProfile.setTenantId(tenantId);
deviceProfile.setDefault(true);
deviceProfile.setName("Default");
deviceProfile.setType(DeviceProfileType.DEFAULT);
deviceProfile.setDescription("Default device profile");
deviceProfile.setProfileData(JacksonUtil.OBJECT_MAPPER.createObjectNode());
DeviceProfileData deviceProfileData = new DeviceProfileData();
DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
deviceProfileData.setConfiguration(configuration);
deviceProfile.setProfileData(deviceProfileData);
return saveDeviceProfile(deviceProfile);
}
@ -226,6 +242,16 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
}
}
}
@Override
protected void validateUpdate(TenantId tenantId, DeviceProfile deviceProfile) {
DeviceProfile old = deviceProfileDao.findById(deviceProfile.getTenantId(), deviceProfile.getId().getId());
if (old == null) {
throw new DataValidationException("Can't update non existing device profile!");
} else if (!old.getType().equals(deviceProfile.getType())) {
throw new DataValidationException("Changing type of device profile is prohibited!");
}
}
};
private PaginatedRemover<TenantId, DeviceProfile> tenantDeviceProfilesRemover =

11
dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java

@ -41,6 +41,8 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.device.DeviceSearchQuery;
import org.thingsboard.server.common.data.device.data.DefaultDeviceConfiguration;
import org.thingsboard.server.common.data.device.data.DeviceData;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
@ -168,6 +170,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
if (device.getDeviceProfileId() == null) {
EntityInfo deviceProfile = this.deviceProfileService.findDefaultDeviceProfileInfo(device.getTenantId());
device.setDeviceProfileId(new DeviceProfileId(deviceProfile.getId().getId()));
DeviceData deviceData = new DeviceData();
deviceData.setConfiguration(new DefaultDeviceConfiguration());
device.setDeviceData(deviceData);
}
savedDevice = deviceDao.save(device.getTenantId(), device);
} catch (Exception t) {
@ -411,6 +416,12 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
@Override
protected void validateUpdate(TenantId tenantId, Device device) {
Device old = deviceDao.findById(device.getTenantId(), device.getId().getId());
if (old == null) {
throw new DataValidationException("Can't update non existing device!");
} else if (!old.getDeviceProfileId().equals(device.getDeviceProfileId())) {
throw new DataValidationException("Changing device profile is prohibited!");
}
}
@Override

3
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -152,6 +152,8 @@ public class ModelConstants {
public static final String DEVICE_LABEL_PROPERTY = "label";
public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
public static final String DEVICE_DEVICE_PROFILE_ID_PROPERTY = "device_profile_id";
public static final String DEVICE_DEVICE_DATA_PROPERTY = "device_data";
public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text";
public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text";
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 {
public static final String DEVICE_PROFILE_COLUMN_FAMILY_NAME = "device_profile";
public static final String DEVICE_PROFILE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String DEVICE_PROFILE_NAME_PROPERTY = "name";
public static final String DEVICE_PROFILE_TYPE_PROPERTY = "type";
public static final String DEVICE_PROFILE_PROFILE_DATA_PROPERTY = "profile_data";
public static final String DEVICE_PROFILE_DESCRIPTION_PROPERTY = "description";
public static final String DEVICE_PROFILE_IS_DEFAULT_PROPERTY = "is_default";

10
dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java

@ -16,11 +16,13 @@
package org.thingsboard.server.dao.model.sql;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.device.data.DeviceData;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
@ -28,6 +30,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.model.SearchTextEntity;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Column;
@ -65,6 +68,10 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti
@Column(name = ModelConstants.DEVICE_DEVICE_PROFILE_ID_PROPERTY, columnDefinition = "uuid")
private UUID deviceProfileId;
@Type(type = "json")
@Column(name = ModelConstants.DEVICE_DEVICE_DATA_PROPERTY)
private JsonNode deviceData;
public AbstractDeviceEntity() {
super();
}
@ -83,6 +90,7 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti
if (device.getDeviceProfileId() != null) {
this.deviceProfileId = device.getDeviceProfileId().getId();
}
this.deviceData = JacksonUtil.convertValue(device.getDeviceData(), ObjectNode.class);
this.name = device.getName();
this.type = device.getType();
this.label = device.getLabel();
@ -95,6 +103,7 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti
this.tenantId = deviceEntity.getTenantId();
this.customerId = deviceEntity.getCustomerId();
this.deviceProfileId = deviceEntity.getDeviceProfileId();
this.deviceData = deviceEntity.getDeviceData();
this.type = deviceEntity.getType();
this.name = deviceEntity.getName();
this.label = deviceEntity.getLabel();
@ -124,6 +133,7 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti
if (deviceProfileId != null) {
device.setDeviceProfileId(new DeviceProfileId(deviceProfileId));
}
device.setDeviceData(JacksonUtil.convertValue(deviceData, DeviceData.class));
device.setName(name);
device.setType(type);
device.setLabel(label);

16
dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java

@ -16,21 +16,27 @@
package org.thingsboard.server.dao.model.sql;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.model.SearchTextEntity;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Table;
import java.util.UUID;
@ -47,6 +53,10 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
@Column(name = ModelConstants.DEVICE_PROFILE_NAME_PROPERTY)
private String name;
@Enumerated(EnumType.STRING)
@Column(name = ModelConstants.DEVICE_PROFILE_TYPE_PROPERTY)
private DeviceProfileType type;
@Column(name = ModelConstants.DEVICE_PROFILE_DESCRIPTION_PROPERTY)
private String description;
@ -76,9 +86,10 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
}
this.setCreatedTime(deviceProfile.getCreatedTime());
this.name = deviceProfile.getName();
this.type = deviceProfile.getType();
this.description = deviceProfile.getDescription();
this.isDefault = deviceProfile.isDefault();
this.profileData = deviceProfile.getProfileData();
this.profileData = JacksonUtil.convertValue(deviceProfile.getProfileData(), ObjectNode.class);
if (deviceProfile.getDefaultRuleChainId() != null) {
this.defaultRuleChainId = deviceProfile.getDefaultRuleChainId().getId();
}
@ -106,9 +117,10 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
deviceProfile.setTenantId(new TenantId(tenantId));
}
deviceProfile.setName(name);
deviceProfile.setType(type);
deviceProfile.setDescription(description);
deviceProfile.setDefault(isDefault);
deviceProfile.setProfileData(profileData);
deviceProfile.setProfileData(JacksonUtil.convertValue(profileData, DeviceProfileData.class));
if (defaultRuleChainId != null) {
deviceProfile.setDefaultRuleChainId(new RuleChainId(defaultRuleChainId));
}

8
dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java

@ -16,15 +16,18 @@
package org.thingsboard.server.dao.model.sql;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.TenantProfileData;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.model.SearchTextEntity;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Column;
@ -74,7 +77,7 @@ public final class TenantProfileEntity extends BaseSqlEntity<TenantProfile> impl
this.isDefault = tenantProfile.isDefault();
this.isolatedTbCore = tenantProfile.isIsolatedTbCore();
this.isolatedTbRuleEngine = tenantProfile.isIsolatedTbRuleEngine();
this.profileData = tenantProfile.getProfileData();
this.profileData = JacksonUtil.convertValue(tenantProfile.getProfileData(), ObjectNode.class);
}
@Override
@ -100,9 +103,8 @@ public final class TenantProfileEntity extends BaseSqlEntity<TenantProfile> impl
tenantProfile.setDefault(isDefault);
tenantProfile.setIsolatedTbCore(isolatedTbCore);
tenantProfile.setIsolatedTbRuleEngine(isolatedTbRuleEngine);
tenantProfile.setProfileData(profileData);
tenantProfile.setProfileData(JacksonUtil.convertValue(profileData, TenantProfileData.class));
return tenantProfile;
}
}

27
dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java

@ -23,8 +23,10 @@ import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.TenantProfileData;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.page.PageData;
@ -107,8 +109,17 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T
}
private void removeTenantProfile(TenantId tenantId, TenantProfileId tenantProfileId) {
try {
tenantProfileDao.removeById(tenantId, tenantProfileId.getId());
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_tenant_profile")) {
throw new DataValidationException("The tenant profile referenced by the tenants cannot be deleted!");
} else {
throw t;
}
}
deleteEntityRelations(tenantId, tenantProfileId);
tenantProfileDao.removeById(tenantId, tenantProfileId.getId());
Cache cache = cacheManager.getCache(TENANT_PROFILE_CACHE);
cache.evict(Collections.singletonList(tenantProfileId.getId()));
cache.evict(Arrays.asList("info", tenantProfileId.getId()));
@ -136,7 +147,7 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T
defaultTenantProfile = new TenantProfile();
defaultTenantProfile.setDefault(true);
defaultTenantProfile.setName("Default");
defaultTenantProfile.setProfileData(JacksonUtil.OBJECT_MAPPER.createObjectNode());
defaultTenantProfile.setProfileData(new TenantProfileData());
defaultTenantProfile.setDescription("Default tenant profile");
defaultTenantProfile.setIsolatedTbCore(false);
defaultTenantProfile.setIsolatedTbRuleEngine(false);
@ -211,6 +222,18 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T
}
}
}
@Override
protected void validateUpdate(TenantId tenantId, TenantProfile tenantProfile) {
TenantProfile old = tenantProfileDao.findById(TenantId.SYS_TENANT_ID, tenantProfile.getId().getId());
if (old == null) {
throw new DataValidationException("Can't update non existing tenant profile!");
} else if (old.isIsolatedTbRuleEngine() != tenantProfile.isIsolatedTbRuleEngine()) {
throw new DataValidationException("Can't update isolatedTbRuleEngine property!");
} else if (old.isIsolatedTbCore() != tenantProfile.isIsolatedTbCore()) {
throw new DataValidationException("Can't update isolatedTbCore property!");
}
}
};
private PaginatedRemover<String, TenantProfile> tenantProfilesRemover =

6
dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java

@ -163,12 +163,6 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
if (old == null) {
throw new DataValidationException("Can't update non existing tenant!");
}
// TODO: Move validation to tenant profile
/* else if (old.isIsolatedTbRuleEngine() != tenant.isIsolatedTbRuleEngine()) {
throw new DataValidationException("Can't update isolatedTbRuleEngine property!");
} else if (old.isIsolatedTbCore() != tenant.isIsolatedTbCore()) {
throw new DataValidationException("Can't update isolatedTbCore property!");
} */
}
};

6
dao/src/main/java/org/thingsboard/server/dao/util/mapping/JacksonUtil.java

@ -30,7 +30,7 @@ public class JacksonUtil {
public static <T> T convertValue(Object fromValue, Class<T> toValueType) {
try {
return OBJECT_MAPPER.convertValue(fromValue, toValueType);
return fromValue != null ? OBJECT_MAPPER.convertValue(fromValue, toValueType) : null;
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("The given object value: "
+ fromValue + " cannot be converted to " + toValueType);
@ -39,7 +39,7 @@ public class JacksonUtil {
public static <T> T fromString(String string, Class<T> clazz) {
try {
return OBJECT_MAPPER.readValue(string, clazz);
return string != null ? OBJECT_MAPPER.readValue(string, clazz) : null;
} catch (IOException e) {
throw new IllegalArgumentException("The given string value: "
+ string + " cannot be transformed to Json object");
@ -48,7 +48,7 @@ public class JacksonUtil {
public static String toString(Object value) {
try {
return OBJECT_MAPPER.writeValueAsString(value);
return value != null ? OBJECT_MAPPER.writeValueAsString(value) : null;
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("The given Json object value: "
+ value + " cannot be transformed to a String");

57
dao/src/main/resources/sql/schema-entities-hsql.sql

@ -122,24 +122,12 @@ CREATE TABLE IF NOT EXISTS dashboard (
title varchar(255)
);
CREATE TABLE IF NOT EXISTS device (
id uuid NOT NULL CONSTRAINT device_pkey PRIMARY KEY,
created_time bigint NOT NULL,
additional_info varchar,
customer_id uuid,
device_profile_id uuid NOT NULL,
type varchar(255),
name varchar(255),
label varchar(255),
search_text varchar(255),
tenant_id uuid,
CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name)
);
CREATE TABLE IF NOT EXISTS device_profile (
id uuid NOT NULL CONSTRAINT device_profile_pkey PRIMARY KEY,
created_time bigint NOT NULL,
name varchar(255),
type varchar(255),
profile_data varchar,
description varchar,
search_text varchar(255),
@ -149,6 +137,22 @@ CREATE TABLE IF NOT EXISTS device_profile (
CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name)
);
CREATE TABLE IF NOT EXISTS device (
id uuid NOT NULL CONSTRAINT device_pkey PRIMARY KEY,
created_time bigint NOT NULL,
additional_info varchar,
customer_id uuid,
device_profile_id uuid NOT NULL,
device_data varchar,
type varchar(255),
name varchar(255),
label varchar(255),
search_text varchar(255),
tenant_id uuid,
CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name),
CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id)
);
CREATE TABLE IF NOT EXISTS device_credentials (
id uuid NOT NULL CONSTRAINT device_credentials_pkey PRIMARY KEY,
created_time bigint NOT NULL,
@ -197,6 +201,19 @@ CREATE TABLE IF NOT EXISTS tb_user (
tenant_id uuid
);
CREATE TABLE IF NOT EXISTS tenant_profile (
id uuid NOT NULL CONSTRAINT tenant_profile_pkey PRIMARY KEY,
created_time bigint NOT NULL,
name varchar(255),
profile_data varchar,
description varchar,
search_text varchar(255),
is_default boolean,
isolated_tb_core boolean,
isolated_tb_rule_engine boolean,
CONSTRAINT tenant_profile_name_unq_key UNIQUE (name)
);
CREATE TABLE IF NOT EXISTS tenant (
id uuid NOT NULL CONSTRAINT tenant_pkey PRIMARY KEY,
created_time bigint NOT NULL,
@ -214,20 +231,8 @@ CREATE TABLE IF NOT EXISTS tenant (
title varchar(255),
zip varchar(255),
isolated_tb_core boolean,
isolated_tb_rule_engine boolean
);
CREATE TABLE IF NOT EXISTS tenant_profile (
id uuid NOT NULL CONSTRAINT tenant_profile_pkey PRIMARY KEY,
created_time bigint NOT NULL,
name varchar(255),
profile_data varchar,
description varchar,
search_text varchar(255),
is_default boolean,
isolated_tb_core boolean,
isolated_tb_rule_engine boolean,
CONSTRAINT tenant_profile_name_unq_key UNIQUE (name)
CONSTRAINT fk_tenant_profile FOREIGN KEY (tenant_profile_id) REFERENCES tenant_profile(id)
);
CREATE TABLE IF NOT EXISTS user_credentials (

57
dao/src/main/resources/sql/schema-entities.sql

@ -139,24 +139,12 @@ CREATE TABLE IF NOT EXISTS dashboard (
title varchar(255)
);
CREATE TABLE IF NOT EXISTS device (
id uuid NOT NULL CONSTRAINT device_pkey PRIMARY KEY,
created_time bigint NOT NULL,
additional_info varchar,
customer_id uuid,
device_profile_id uuid NOT NULL,
type varchar(255),
name varchar(255),
label varchar(255),
search_text varchar(255),
tenant_id uuid,
CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name)
);
CREATE TABLE IF NOT EXISTS device_profile (
id uuid NOT NULL CONSTRAINT device_profile_pkey PRIMARY KEY,
created_time bigint NOT NULL,
name varchar(255),
type varchar(255),
profile_data varchar,
description varchar,
search_text varchar(255),
@ -166,6 +154,22 @@ CREATE TABLE IF NOT EXISTS device_profile (
CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name)
);
CREATE TABLE IF NOT EXISTS device (
id uuid NOT NULL CONSTRAINT device_pkey PRIMARY KEY,
created_time bigint NOT NULL,
additional_info varchar,
customer_id uuid,
device_profile_id uuid NOT NULL,
device_data varchar,
type varchar(255),
name varchar(255),
label varchar(255),
search_text varchar(255),
tenant_id uuid,
CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name),
CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id)
);
CREATE TABLE IF NOT EXISTS device_credentials (
id uuid NOT NULL CONSTRAINT device_credentials_pkey PRIMARY KEY,
created_time bigint NOT NULL,
@ -221,6 +225,19 @@ CREATE TABLE IF NOT EXISTS tb_user (
tenant_id uuid
);
CREATE TABLE IF NOT EXISTS tenant_profile (
id uuid NOT NULL CONSTRAINT tenant_profile_pkey PRIMARY KEY,
created_time bigint NOT NULL,
name varchar(255),
profile_data varchar,
description varchar,
search_text varchar(255),
is_default boolean,
isolated_tb_core boolean,
isolated_tb_rule_engine boolean,
CONSTRAINT tenant_profile_name_unq_key UNIQUE (name)
);
CREATE TABLE IF NOT EXISTS tenant (
id uuid NOT NULL CONSTRAINT tenant_pkey PRIMARY KEY,
created_time bigint NOT NULL,
@ -238,20 +255,8 @@ CREATE TABLE IF NOT EXISTS tenant (
title varchar(255),
zip varchar(255),
isolated_tb_core boolean,
isolated_tb_rule_engine boolean
);
CREATE TABLE IF NOT EXISTS tenant_profile (
id uuid NOT NULL CONSTRAINT tenant_profile_pkey PRIMARY KEY,
created_time bigint NOT NULL,
name varchar(255),
profile_data varchar,
description varchar,
search_text varchar(255),
is_default boolean,
isolated_tb_core boolean,
isolated_tb_rule_engine boolean,
CONSTRAINT tenant_profile_name_unq_key UNIQUE (name)
CONSTRAINT fk_tenant_profile FOREIGN KEY (tenant_profile_id) REFERENCES tenant_profile(id)
);
CREATE TABLE IF NOT EXISTS user_credentials (

20
dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java

@ -28,10 +28,15 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Event;
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.dao.alarm.AlarmService;
@ -187,4 +192,19 @@ public abstract class AbstractServiceTest {
return new AuditLogLevelFilter(mask);
}
protected DeviceProfile createDeviceProfile(TenantId tenantId, String name) {
DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setTenantId(tenantId);
deviceProfile.setName(name);
deviceProfile.setType(DeviceProfileType.DEFAULT);
deviceProfile.setDescription(name + " Test");
DeviceProfileData deviceProfileData = new DeviceProfileData();
DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
deviceProfileData.setConfiguration(configuration);
deviceProfile.setProfileData(deviceProfileData);
deviceProfile.setDefault(false);
deviceProfile.setDefaultRuleChainId(new RuleChainId(Uuids.timeBased()));
return deviceProfile;
}
}

57
dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java

@ -15,20 +15,19 @@
*/
package org.thingsboard.server.dao.service;
import com.datastax.oss.driver.api.core.uuid.Uuids;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import java.util.ArrayList;
import java.util.Collections;
@ -58,7 +57,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
@Test
public void testSaveDeviceProfile() {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile");
DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
Assert.assertNotNull(savedDeviceProfile);
Assert.assertNotNull(savedDeviceProfile.getId());
@ -76,7 +75,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
@Test
public void testFindDeviceProfileById() {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");
DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
DeviceProfile foundDeviceProfile = deviceProfileService.findDeviceProfileById(tenantId, savedDeviceProfile.getId());
Assert.assertNotNull(foundDeviceProfile);
@ -85,7 +84,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
@Test
public void testFindDeviceProfileInfoById() {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");
DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
EntityInfo foundDeviceProfileInfo = deviceProfileService.findDeviceProfileInfoById(tenantId, savedDeviceProfile.getId());
Assert.assertNotNull(foundDeviceProfileInfo);
@ -111,8 +110,8 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
@Test
public void testSetDefaultDeviceProfile() {
DeviceProfile deviceProfile1 = this.createDeviceProfile("Device Profile 1");
DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile 2");
DeviceProfile deviceProfile1 = this.createDeviceProfile(tenantId,"Device Profile 1");
DeviceProfile deviceProfile2 = this.createDeviceProfile(tenantId,"Device Profile 2");
DeviceProfile savedDeviceProfile1 = deviceProfileService.saveDeviceProfile(deviceProfile1);
DeviceProfile savedDeviceProfile2 = deviceProfileService.saveDeviceProfile(deviceProfile2);
@ -138,15 +137,36 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
@Test(expected = DataValidationException.class)
public void testSaveDeviceProfileWithSameName() {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");
deviceProfileService.saveDeviceProfile(deviceProfile);
DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile");
DeviceProfile deviceProfile2 = this.createDeviceProfile(tenantId,"Device Profile");
deviceProfileService.saveDeviceProfile(deviceProfile2);
}
@Test(expected = DataValidationException.class)
public void testSaveSameDeviceProfileWithDifferentType() {
DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");
DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
savedDeviceProfile.setType(DeviceProfileType.LWM2M);
deviceProfileService.saveDeviceProfile(savedDeviceProfile);
}
@Test(expected = DataValidationException.class)
public void testDeleteDeviceProfileWithExistingDevice() {
DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");
DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
Device device = new Device();
device.setTenantId(tenantId);
device.setName("Test device");
device.setType("default");
device.setDeviceProfileId(savedDeviceProfile.getId());
deviceService.saveDevice(device);
deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId());
}
@Test
public void testDeleteDeviceProfile() {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");
DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId());
DeviceProfile foundDeviceProfile = deviceProfileService.findDeviceProfileById(tenantId, savedDeviceProfile.getId());
@ -164,7 +184,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
deviceProfiles.addAll(pageData.getData());
for (int i=0;i<28;i++) {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i);
DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile"+i);
deviceProfiles.add(deviceProfileService.saveDeviceProfile(deviceProfile));
}
@ -206,7 +226,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
deviceProfiles.addAll(deviceProfilePageData.getData());
for (int i=0;i<28;i++) {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i);
DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile"+i);
deviceProfiles.add(deviceProfileService.saveDeviceProfile(deviceProfile));
}
@ -242,15 +262,6 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
Assert.assertEquals(1, pageData.getTotalElements());
}
private DeviceProfile createDeviceProfile(String name) {
DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setTenantId(tenantId);
deviceProfile.setName(name);
deviceProfile.setDescription(name + " Test");
deviceProfile.setProfileData(JacksonUtil.OBJECT_MAPPER.createObjectNode());
deviceProfile.setDefault(false);
deviceProfile.setDefaultRuleChainId(new RuleChainId(Uuids.timeBased()));
return deviceProfile;
}
}

17
dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java

@ -127,6 +127,23 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
deviceService.deleteDevice(tenantId, device.getId());
}
}
@Test(expected = DataValidationException.class)
public void testSaveSameDeviceWithDifferentDeviceProfileId() {
Device device = new Device();
device.setName("My device");
device.setType("default");
device.setTenantId(tenantId);
device = deviceService.saveDevice(device);
DeviceProfile deviceProfile2 = this.createDeviceProfile(tenantId,"Device Profile 2");
DeviceProfile savedDeviceProfile2 = deviceProfileService.saveDeviceProfile(deviceProfile2);
device.setDeviceProfileId(savedDeviceProfile2.getId());
try {
deviceService.saveDevice(device);
} finally {
deviceService.deleteDevice(tenantId, device.getId());
}
}
@Test(expected = DataValidationException.class)
public void testAssignDeviceToCustomerFromDifferentTenant() {

35
dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java

@ -19,7 +19,9 @@ import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.TenantProfileData;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.page.PageData;
@ -136,6 +138,37 @@ public class BaseTenantProfileServiceTest extends AbstractServiceTest {
tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile2);
}
@Test(expected = DataValidationException.class)
public void testSaveSameTenantProfileWithDifferentIsolatedTbRuleEngine() {
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
TenantProfile savedTenantProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile);
savedTenantProfile.setIsolatedTbRuleEngine(true);
tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, savedTenantProfile);
}
@Test(expected = DataValidationException.class)
public void testSaveSameTenantProfileWithDifferentIsolatedTbCore() {
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
TenantProfile savedTenantProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile);
savedTenantProfile.setIsolatedTbCore(true);
tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, savedTenantProfile);
}
@Test(expected = DataValidationException.class)
public void testDeleteTenantProfileWithExistingTenant() {
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
TenantProfile savedTenantProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile);
Tenant tenant = new Tenant();
tenant.setTitle("Test tenant");
tenant.setTenantProfileId(savedTenantProfile.getId());
tenant = tenantService.saveTenant(tenant);
try {
tenantProfileService.deleteTenantProfile(TenantId.SYS_TENANT_ID, savedTenantProfile.getId());
} finally {
tenantService.deleteTenant(tenant.getId());
}
}
@Test
public void testDeleteTenantProfile() {
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
@ -230,7 +263,7 @@ public class BaseTenantProfileServiceTest extends AbstractServiceTest {
TenantProfile tenantProfile = new TenantProfile();
tenantProfile.setName(name);
tenantProfile.setDescription(name + " Test");
tenantProfile.setProfileData(JacksonUtil.OBJECT_MAPPER.createObjectNode());
tenantProfile.setProfileData(new TenantProfileData());
tenantProfile.setDefault(false);
tenantProfile.setIsolatedTbCore(false);
tenantProfile.setIsolatedTbRuleEngine(false);

Loading…
Cancel
Save