Commit 43596ec5ce8e60e639cda86bc8414fe17b41587d

Authored by Vladyslav_Prykhodko
2 parents ed725c4a 8090e520

Merge branch 'develop/3.2' of github.com:thingsboard/thingsboard into develop/3.2

Showing 19 changed files with 256 additions and 87 deletions
@@ -355,10 +355,12 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService @@ -355,10 +355,12 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
355 pageData = tenantService.findTenants(pageLink); 355 pageData = tenantService.findTenants(pageLink);
356 for (Tenant tenant : pageData.getData()) { 356 for (Tenant tenant : pageData.getData()) {
357 List<EntitySubtype> deviceTypes = deviceService.findDeviceTypesByTenantId(tenant.getId()).get(); 357 List<EntitySubtype> deviceTypes = deviceService.findDeviceTypesByTenantId(tenant.getId()).get();
358 - deviceProfileService.findOrCreateDefaultDeviceProfile(tenant.getId()); 358 + try {
  359 + deviceProfileService.createDefaultDeviceProfile(tenant.getId());
  360 + } catch (Exception e){}
359 for (EntitySubtype deviceType : deviceTypes) { 361 for (EntitySubtype deviceType : deviceTypes) {
360 try { 362 try {
361 - deviceProfileService.createDeviceProfile(tenant.getId(), deviceType.getType()); 363 + deviceProfileService.findOrCreateDeviceProfile(tenant.getId(), deviceType.getType());
362 } catch (Exception e) { 364 } catch (Exception e) {
363 } 365 }
364 } 366 }
@@ -186,9 +186,8 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { @@ -186,9 +186,8 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
186 public void testSaveDeviceWithEmptyType() throws Exception { 186 public void testSaveDeviceWithEmptyType() throws Exception {
187 Device device = new Device(); 187 Device device = new Device();
188 device.setName("My device"); 188 device.setName("My device");
189 - doPost("/api/device", device)  
190 - .andExpect(status().isBadRequest())  
191 - .andExpect(statusReason(containsString("Device type should be specified"))); 189 + Device savedDevice = doPost("/api/device", device, Device.class);
  190 + Assert.assertEquals("default", savedDevice.getType());
192 } 191 }
193 192
194 @Test 193 @Test
@@ -121,7 +121,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -121,7 +121,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
121 Assert.assertNotNull(foundDefaultDeviceProfileInfo.getName()); 121 Assert.assertNotNull(foundDefaultDeviceProfileInfo.getName());
122 Assert.assertNotNull(foundDefaultDeviceProfileInfo.getType()); 122 Assert.assertNotNull(foundDefaultDeviceProfileInfo.getType());
123 Assert.assertEquals(DeviceProfileType.DEFAULT, foundDefaultDeviceProfileInfo.getType()); 123 Assert.assertEquals(DeviceProfileType.DEFAULT, foundDefaultDeviceProfileInfo.getType());
124 - Assert.assertEquals("Default", foundDefaultDeviceProfileInfo.getName()); 124 + Assert.assertEquals("default", foundDefaultDeviceProfileInfo.getName());
125 } 125 }
126 126
127 @Test 127 @Test
@@ -27,6 +27,8 @@ public interface DeviceProfileService { @@ -27,6 +27,8 @@ public interface DeviceProfileService {
27 27
28 DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId); 28 DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId);
29 29
  30 + DeviceProfile findDeviceProfileByName(TenantId tenantId, String profileName);
  31 +
30 DeviceProfileInfo findDeviceProfileInfoById(TenantId tenantId, DeviceProfileId deviceProfileId); 32 DeviceProfileInfo findDeviceProfileInfoById(TenantId tenantId, DeviceProfileId deviceProfileId);
31 33
32 DeviceProfile saveDeviceProfile(DeviceProfile deviceProfile); 34 DeviceProfile saveDeviceProfile(DeviceProfile deviceProfile);
@@ -37,12 +39,10 @@ public interface DeviceProfileService { @@ -37,12 +39,10 @@ public interface DeviceProfileService {
37 39
38 PageData<DeviceProfileInfo> findDeviceProfileInfos(TenantId tenantId, PageLink pageLink); 40 PageData<DeviceProfileInfo> findDeviceProfileInfos(TenantId tenantId, PageLink pageLink);
39 41
40 - DeviceProfile findOrCreateDefaultDeviceProfile(TenantId tenantId); 42 + DeviceProfile findOrCreateDeviceProfile(TenantId tenantId, String profileName);
41 43
42 DeviceProfile createDefaultDeviceProfile(TenantId tenantId); 44 DeviceProfile createDefaultDeviceProfile(TenantId tenantId);
43 45
44 - DeviceProfile createDeviceProfile(TenantId tenantId, String profileName);  
45 -  
46 DeviceProfile findDefaultDeviceProfile(TenantId tenantId); 46 DeviceProfile findDefaultDeviceProfile(TenantId tenantId);
47 47
48 DeviceProfileInfo findDefaultDeviceProfileInfo(TenantId tenantId); 48 DeviceProfileInfo findDefaultDeviceProfileInfo(TenantId tenantId);
@@ -39,6 +39,7 @@ import io.netty.util.concurrent.Future; @@ -39,6 +39,7 @@ import io.netty.util.concurrent.Future;
39 import io.netty.util.concurrent.GenericFutureListener; 39 import io.netty.util.concurrent.GenericFutureListener;
40 import lombok.extern.slf4j.Slf4j; 40 import lombok.extern.slf4j.Slf4j;
41 import org.springframework.util.StringUtils; 41 import org.springframework.util.StringUtils;
  42 +import org.thingsboard.server.common.data.DeviceProfile;
42 import org.thingsboard.server.common.data.DeviceTransportType; 43 import org.thingsboard.server.common.data.DeviceTransportType;
43 import org.thingsboard.server.common.data.device.profile.MqttTopics; 44 import org.thingsboard.server.common.data.device.profile.MqttTopics;
44 import org.thingsboard.server.common.msg.EncryptionUtil; 45 import org.thingsboard.server.common.msg.EncryptionUtil;
@@ -574,7 +575,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @@ -574,7 +575,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
574 try { 575 try {
575 adaptor.convertToPublish(deviceSessionCtx, rpcResponse).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); 576 adaptor.convertToPublish(deviceSessionCtx, rpcResponse).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush);
576 } catch (Exception e) { 577 } catch (Exception e) {
577 - log.trace("[{}] Failed to convert device RPC commandto MQTT msg", sessionId, e); 578 + log.trace("[{}] Failed to convert device RPC command to MQTT msg", sessionId, e);
578 } 579 }
579 } 580 }
  581 +
  582 + @Override
  583 + public void onProfileUpdate(DeviceProfile deviceProfile) {
  584 + deviceSessionCtx.getDeviceInfo().setDeviceType(deviceProfile.getName());
  585 + sessionInfo = SessionInfoProto.newBuilder().mergeFrom(sessionInfo).setDeviceType(deviceProfile.getName()).build();
  586 + }
580 } 587 }
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 package org.thingsboard.server.transport.mqtt.session; 16 package org.thingsboard.server.transport.mqtt.session;
17 17
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
  19 +import org.thingsboard.server.common.data.DeviceProfile;
19 import org.thingsboard.server.common.transport.SessionMsgListener; 20 import org.thingsboard.server.common.transport.SessionMsgListener;
20 import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; 21 import org.thingsboard.server.common.transport.auth.TransportDeviceInfo;
21 import org.thingsboard.server.gen.transport.TransportProtos; 22 import org.thingsboard.server.gen.transport.TransportProtos;
@@ -32,7 +33,7 @@ import java.util.concurrent.ConcurrentMap; @@ -32,7 +33,7 @@ import java.util.concurrent.ConcurrentMap;
32 public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext implements SessionMsgListener { 33 public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext implements SessionMsgListener {
33 34
34 private final GatewaySessionHandler parent; 35 private final GatewaySessionHandler parent;
35 - private final SessionInfoProto sessionInfo; 36 + private volatile SessionInfoProto sessionInfo;
36 37
37 public GatewayDeviceSessionCtx(GatewaySessionHandler parent, TransportDeviceInfo deviceInfo, ConcurrentMap<MqttTopicMatcher, Integer> mqttQoSMap) { 38 public GatewayDeviceSessionCtx(GatewaySessionHandler parent, TransportDeviceInfo deviceInfo, ConcurrentMap<MqttTopicMatcher, Integer> mqttQoSMap) {
38 super(UUID.randomUUID(), mqttQoSMap); 39 super(UUID.randomUUID(), mqttQoSMap);
@@ -105,4 +106,10 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple @@ -105,4 +106,10 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple
105 public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse) { 106 public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse) {
106 // This feature is not supported in the TB IoT Gateway yet. 107 // This feature is not supported in the TB IoT Gateway yet.
107 } 108 }
  109 +
  110 + @Override
  111 + public void onProfileUpdate(DeviceProfile deviceProfile) {
  112 + deviceInfo.setDeviceType(deviceProfile.getName());
  113 + sessionInfo = SessionInfoProto.newBuilder().mergeFrom(sessionInfo).setDeviceType(deviceProfile.getName()).build();
  114 + }
108 } 115 }
  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.transport;
  17 +
  18 +import com.google.protobuf.ByteString;
  19 +import org.thingsboard.server.common.data.DeviceProfile;
  20 +import org.thingsboard.server.common.data.id.DeviceProfileId;
  21 +
  22 +import java.util.Optional;
  23 +
  24 +public interface TransportProfileCache {
  25 +
  26 +
  27 + DeviceProfile getOrCreate(DeviceProfileId id, ByteString profileBody);
  28 +
  29 + DeviceProfile get(DeviceProfileId id);
  30 +
  31 + void put(DeviceProfile profile);
  32 +
  33 + DeviceProfile put(ByteString profileBody);
  34 +
  35 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.transport.service;
  17 +
  18 +import com.google.protobuf.ByteString;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
  21 +import org.springframework.stereotype.Component;
  22 +import org.thingsboard.server.common.data.DeviceProfile;
  23 +import org.thingsboard.server.common.data.id.DeviceProfileId;
  24 +import org.thingsboard.server.common.transport.TransportProfileCache;
  25 +import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
  26 +
  27 +import java.util.Optional;
  28 +import java.util.concurrent.ConcurrentHashMap;
  29 +import java.util.concurrent.ConcurrentMap;
  30 +
  31 +@Slf4j
  32 +@Component
  33 +@ConditionalOnExpression("('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport'")
  34 +public class DefaultTransportProfileCache implements TransportProfileCache {
  35 +
  36 + private final ConcurrentMap<DeviceProfileId, DeviceProfile> deviceProfiles = new ConcurrentHashMap<>();
  37 +
  38 + private final DataDecodingEncodingService dataDecodingEncodingService;
  39 +
  40 + public DefaultTransportProfileCache(DataDecodingEncodingService dataDecodingEncodingService) {
  41 + this.dataDecodingEncodingService = dataDecodingEncodingService;
  42 + }
  43 +
  44 + @Override
  45 + public DeviceProfile getOrCreate(DeviceProfileId id, ByteString profileBody) {
  46 + DeviceProfile profile = deviceProfiles.get(id);
  47 + if (profile == null) {
  48 + Optional<DeviceProfile> deviceProfile = dataDecodingEncodingService.decode(profileBody.toByteArray());
  49 + if (deviceProfile.isPresent()) {
  50 + profile = deviceProfile.get();
  51 + deviceProfiles.put(id, profile);
  52 + }
  53 + }
  54 + return profile;
  55 + }
  56 +
  57 + @Override
  58 + public DeviceProfile get(DeviceProfileId id) {
  59 + return deviceProfiles.get(id);
  60 + }
  61 +
  62 + @Override
  63 + public void put(DeviceProfile profile) {
  64 + deviceProfiles.put(profile.getId(), profile);
  65 + }
  66 +
  67 + @Override
  68 + public DeviceProfile put(ByteString profileBody) {
  69 + Optional<DeviceProfile> deviceProfile = dataDecodingEncodingService.decode(profileBody.toByteArray());
  70 + if (deviceProfile.isPresent()) {
  71 + put(deviceProfile.get());
  72 + return deviceProfile.get();
  73 + } else {
  74 + return null;
  75 + }
  76 + }
  77 +}
@@ -43,6 +43,7 @@ import org.thingsboard.server.common.msg.session.SessionMsgType; @@ -43,6 +43,7 @@ import org.thingsboard.server.common.msg.session.SessionMsgType;
43 import org.thingsboard.server.common.msg.tools.TbRateLimits; 43 import org.thingsboard.server.common.msg.tools.TbRateLimits;
44 import org.thingsboard.server.common.msg.tools.TbRateLimitsException; 44 import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
45 import org.thingsboard.server.common.transport.SessionMsgListener; 45 import org.thingsboard.server.common.transport.SessionMsgListener;
  46 +import org.thingsboard.server.common.transport.TransportProfileCache;
46 import org.thingsboard.server.common.transport.TransportService; 47 import org.thingsboard.server.common.transport.TransportService;
47 import org.thingsboard.server.common.transport.TransportServiceCallback; 48 import org.thingsboard.server.common.transport.TransportServiceCallback;
48 import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; 49 import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse;
@@ -121,8 +122,7 @@ public class DefaultTransportService implements TransportService { @@ -121,8 +122,7 @@ public class DefaultTransportService implements TransportService {
121 private final PartitionService partitionService; 122 private final PartitionService partitionService;
122 private final TbServiceInfoProvider serviceInfoProvider; 123 private final TbServiceInfoProvider serviceInfoProvider;
123 private final StatsFactory statsFactory; 124 private final StatsFactory statsFactory;
124 - private final DataDecodingEncodingService dataDecodingEncodingService;  
125 - 125 + private final TransportProfileCache transportProfileCache;
126 126
127 protected TbQueueRequestTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> transportApiRequestTemplate; 127 protected TbQueueRequestTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> transportApiRequestTemplate;
128 protected TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> ruleEngineMsgProducer; 128 protected TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> ruleEngineMsgProducer;
@@ -141,7 +141,6 @@ public class DefaultTransportService implements TransportService { @@ -141,7 +141,6 @@ public class DefaultTransportService implements TransportService {
141 //TODO 3.2: @ybondarenko Implement cleanup of this maps. 141 //TODO 3.2: @ybondarenko Implement cleanup of this maps.
142 private final ConcurrentMap<TenantId, TbRateLimits> perTenantLimits = new ConcurrentHashMap<>(); 142 private final ConcurrentMap<TenantId, TbRateLimits> perTenantLimits = new ConcurrentHashMap<>();
143 private final ConcurrentMap<DeviceId, TbRateLimits> perDeviceLimits = new ConcurrentHashMap<>(); 143 private final ConcurrentMap<DeviceId, TbRateLimits> perDeviceLimits = new ConcurrentHashMap<>();
144 - private final ConcurrentMap<DeviceProfileId, DeviceProfile> deviceProfiles = new ConcurrentHashMap<>();  
145 144
146 private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("transport-consumer")); 145 private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("transport-consumer"));
147 private volatile boolean stopped = false; 146 private volatile boolean stopped = false;
@@ -151,13 +150,13 @@ public class DefaultTransportService implements TransportService { @@ -151,13 +150,13 @@ public class DefaultTransportService implements TransportService {
151 TbQueueProducerProvider producerProvider, 150 TbQueueProducerProvider producerProvider,
152 PartitionService partitionService, 151 PartitionService partitionService,
153 StatsFactory statsFactory, 152 StatsFactory statsFactory,
154 - DataDecodingEncodingService dataDecodingEncodingService) { 153 + TransportProfileCache transportProfileCache) {
155 this.serviceInfoProvider = serviceInfoProvider; 154 this.serviceInfoProvider = serviceInfoProvider;
156 this.queueProvider = queueProvider; 155 this.queueProvider = queueProvider;
157 this.producerProvider = producerProvider; 156 this.producerProvider = producerProvider;
158 this.partitionService = partitionService; 157 this.partitionService = partitionService;
159 this.statsFactory = statsFactory; 158 this.statsFactory = statsFactory;
160 - this.dataDecodingEncodingService = dataDecodingEncodingService; 159 + this.transportProfileCache = transportProfileCache;
161 } 160 }
162 161
163 @PostConstruct 162 @PostConstruct
@@ -276,14 +275,7 @@ public class DefaultTransportService implements TransportService { @@ -276,14 +275,7 @@ public class DefaultTransportService implements TransportService {
276 result.deviceInfo(tdi); 275 result.deviceInfo(tdi);
277 ByteString profileBody = msg.getProfileBody(); 276 ByteString profileBody = msg.getProfileBody();
278 if (profileBody != null && !profileBody.isEmpty()) { 277 if (profileBody != null && !profileBody.isEmpty()) {
279 - DeviceProfile profile = deviceProfiles.get(tdi.getDeviceProfileId());  
280 - if (profile == null) {  
281 - Optional<DeviceProfile> deviceProfile = dataDecodingEncodingService.decode(profileBody.toByteArray());  
282 - if (deviceProfile.isPresent()) {  
283 - profile = deviceProfile.get();  
284 - deviceProfiles.put(tdi.getDeviceProfileId(), profile);  
285 - }  
286 - } 278 + DeviceProfile profile = transportProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody);
287 if (transportType != DeviceTransportType.DEFAULT 279 if (transportType != DeviceTransportType.DEFAULT
288 && profile != null && profile.getTransportType() != DeviceTransportType.DEFAULT && profile.getTransportType() != transportType) { 280 && profile != null && profile.getTransportType() != DeviceTransportType.DEFAULT && profile.getTransportType() != transportType) {
289 log.debug("[{}] Device profile [{}] has different transport type: {}, expected: {}", tdi.getDeviceId(), tdi.getDeviceProfileId(), profile.getTransportType(), transportType); 281 log.debug("[{}] Device profile [{}] has different transport type: {}, expected: {}", tdi.getDeviceId(), tdi.getDeviceProfileId(), profile.getTransportType(), transportType);
@@ -309,15 +301,7 @@ public class DefaultTransportService implements TransportService { @@ -309,15 +301,7 @@ public class DefaultTransportService implements TransportService {
309 result.deviceInfo(tdi); 301 result.deviceInfo(tdi);
310 ByteString profileBody = msg.getProfileBody(); 302 ByteString profileBody = msg.getProfileBody();
311 if (profileBody != null && !profileBody.isEmpty()) { 303 if (profileBody != null && !profileBody.isEmpty()) {
312 - DeviceProfile profile = deviceProfiles.get(tdi.getDeviceProfileId());  
313 - if (profile == null) {  
314 - Optional<DeviceProfile> deviceProfile = dataDecodingEncodingService.decode(profileBody.toByteArray());  
315 - if (deviceProfile.isPresent()) {  
316 - profile = deviceProfile.get();  
317 - deviceProfiles.put(tdi.getDeviceProfileId(), profile);  
318 - }  
319 - }  
320 - result.deviceProfile(profile); 304 + result.deviceProfile(transportProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody));
321 } 305 }
322 } 306 }
323 return result.build(); 307 return result.build();
@@ -629,8 +613,10 @@ public class DefaultTransportService implements TransportService { @@ -629,8 +613,10 @@ public class DefaultTransportService implements TransportService {
629 } 613 }
630 } else { 614 } else {
631 if (toSessionMsg.hasDeviceProfileUpdateMsg()) { 615 if (toSessionMsg.hasDeviceProfileUpdateMsg()) {
632 - Optional<DeviceProfile> deviceProfile = dataDecodingEncodingService.decode(toSessionMsg.getDeviceProfileUpdateMsg().getData().toByteArray());  
633 - deviceProfile.ifPresent(this::onProfileUpdate); 616 + DeviceProfile deviceProfile = transportProfileCache.put(toSessionMsg.getDeviceProfileUpdateMsg().getData());
  617 + if (deviceProfile != null) {
  618 + onProfileUpdate(deviceProfile);
  619 + }
634 } else { 620 } else {
635 //TODO: should we notify the device actor about missed session? 621 //TODO: should we notify the device actor about missed session?
636 log.debug("[{}] Missing session.", sessionId); 622 log.debug("[{}] Missing session.", sessionId);
@@ -640,7 +626,7 @@ public class DefaultTransportService implements TransportService { @@ -640,7 +626,7 @@ public class DefaultTransportService implements TransportService {
640 626
641 @Override 627 @Override
642 public void getDeviceProfile(DeviceProfileId deviceProfileId, TransportServiceCallback<DeviceProfile> callback) { 628 public void getDeviceProfile(DeviceProfileId deviceProfileId, TransportServiceCallback<DeviceProfile> callback) {
643 - DeviceProfile deviceProfile = deviceProfiles.get(deviceProfileId); 629 + DeviceProfile deviceProfile = transportProfileCache.get(deviceProfileId);
644 if (deviceProfile != null) { 630 if (deviceProfile != null) {
645 callback.onSuccess(deviceProfile); 631 callback.onSuccess(deviceProfile);
646 } else { 632 } else {
@@ -653,14 +639,13 @@ public class DefaultTransportService implements TransportService { @@ -653,14 +639,13 @@ public class DefaultTransportService implements TransportService {
653 TransportApiRequestMsg.newBuilder().setGetDeviceProfileRequestMsg(msg).build()); 639 TransportApiRequestMsg.newBuilder().setGetDeviceProfileRequestMsg(msg).build());
654 AsyncCallbackTemplate.withCallback(transportApiRequestTemplate.send(protoMsg), 640 AsyncCallbackTemplate.withCallback(transportApiRequestTemplate.send(protoMsg),
655 response -> { 641 response -> {
656 - byte[] devProfileBody = response.getValue().getGetDeviceProfileResponseMsg().getData().toByteArray();  
657 - if (devProfileBody != null && devProfileBody.length > 0) {  
658 - Optional<DeviceProfile> deviceProfileOpt = dataDecodingEncodingService.decode(devProfileBody);  
659 - if (deviceProfileOpt.isPresent()) {  
660 - deviceProfiles.put(deviceProfileOpt.get().getId(), deviceProfile);  
661 - callback.onSuccess(deviceProfileOpt.get()); 642 + ByteString devProfileBody = response.getValue().getGetDeviceProfileResponseMsg().getData();
  643 + if (devProfileBody != null && !devProfileBody.isEmpty()) {
  644 + DeviceProfile profile = transportProfileCache.put(devProfileBody);
  645 + if (profile != null) {
  646 + callback.onSuccess(profile);
662 } else { 647 } else {
663 - log.warn("Failed to decode device profile: {}", Arrays.toString(devProfileBody)); 648 + log.warn("Failed to decode device profile: {}", devProfileBody);
664 callback.onError(new IllegalArgumentException("Failed to decode device profile!")); 649 callback.onError(new IllegalArgumentException("Failed to decode device profile!"));
665 } 650 }
666 } else { 651 } else {
@@ -673,7 +658,6 @@ public class DefaultTransportService implements TransportService { @@ -673,7 +658,6 @@ public class DefaultTransportService implements TransportService {
673 658
674 @Override 659 @Override
675 public void onProfileUpdate(DeviceProfile deviceProfile) { 660 public void onProfileUpdate(DeviceProfile deviceProfile) {
676 - deviceProfiles.put(deviceProfile.getId(), deviceProfile);  
677 long deviceProfileIdMSB = deviceProfile.getId().getId().getMostSignificantBits(); 661 long deviceProfileIdMSB = deviceProfile.getId().getId().getMostSignificantBits();
678 long deviceProfileIdLSB = deviceProfile.getId().getId().getLeastSignificantBits(); 662 long deviceProfileIdLSB = deviceProfile.getId().getId().getLeastSignificantBits();
679 sessions.forEach((id, md) -> { 663 sessions.forEach((id, md) -> {
@@ -736,7 +720,7 @@ public class DefaultTransportService implements TransportService { @@ -736,7 +720,7 @@ public class DefaultTransportService implements TransportService {
736 720
737 private RuleChainId resolveRuleChainId(TransportProtos.SessionInfoProto sessionInfo) { 721 private RuleChainId resolveRuleChainId(TransportProtos.SessionInfoProto sessionInfo) {
738 DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); 722 DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
739 - DeviceProfile deviceProfile = deviceProfiles.get(deviceProfileId); 723 + DeviceProfile deviceProfile = transportProfileCache.get(deviceProfileId);
740 RuleChainId ruleChainId; 724 RuleChainId ruleChainId;
741 if (deviceProfile == null) { 725 if (deviceProfile == null) {
742 log.warn("[{}] Device profile is null!", deviceProfileId); 726 log.warn("[{}] Device profile is null!", deviceProfileId);
@@ -747,27 +731,6 @@ public class DefaultTransportService implements TransportService { @@ -747,27 +731,6 @@ public class DefaultTransportService implements TransportService {
747 return ruleChainId; 731 return ruleChainId;
748 } 732 }
749 733
750 - private <T extends com.google.protobuf.GeneratedMessageV3> ListenableFuture<TbProtoQueueMsg<T>> extractProfile(ListenableFuture<TbProtoQueueMsg<T>> send,  
751 - Function<T, Boolean> hasDeviceInfo,  
752 - Function<T, TransportProtos.DeviceInfoProto> deviceInfoF,  
753 - Function<T, ByteString> profileBodyF) {  
754 - return Futures.transform(send, response -> {  
755 - T value = response.getValue();  
756 - if (hasDeviceInfo.apply(value)) {  
757 - TransportProtos.DeviceInfoProto deviceInfo = deviceInfoF.apply(value);  
758 - ByteString profileBody = profileBodyF.apply(value);  
759 - if (profileBody != null && !profileBody.isEmpty()) {  
760 - DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(deviceInfo.getDeviceProfileIdMSB(), deviceInfo.getDeviceProfileIdLSB()));  
761 - if (!deviceProfiles.containsKey(deviceProfileId)) {  
762 - Optional<DeviceProfile> deviceProfile = dataDecodingEncodingService.decode(profileBody.toByteArray());  
763 - deviceProfile.ifPresent(profile -> deviceProfiles.put(deviceProfileId, profile));  
764 - }  
765 - }  
766 - }  
767 - return response;  
768 - }, transportCallbackExecutor);  
769 - }  
770 -  
771 private class TransportTbQueueCallback implements TbQueueCallback { 734 private class TransportTbQueueCallback implements TbQueueCallback {
772 private final TransportServiceCallback<Void> callback; 735 private final TransportServiceCallback<Void> callback;
773 736
@@ -35,7 +35,7 @@ public abstract class DeviceAwareSessionContext implements SessionContext { @@ -35,7 +35,7 @@ public abstract class DeviceAwareSessionContext implements SessionContext {
35 @Getter 35 @Getter
36 private volatile DeviceId deviceId; 36 private volatile DeviceId deviceId;
37 @Getter 37 @Getter
38 - private volatile TransportDeviceInfo deviceInfo; 38 + protected volatile TransportDeviceInfo deviceInfo;
39 private volatile boolean connected; 39 private volatile boolean connected;
40 40
41 public DeviceId getDeviceId() { 41 public DeviceId getDeviceId() {
@@ -184,4 +184,15 @@ public interface DeviceDao extends Dao<Device> { @@ -184,4 +184,15 @@ public interface DeviceDao extends Dao<Device> {
184 ListenableFuture<Device> findDeviceByTenantIdAndIdAsync(TenantId tenantId, UUID id); 184 ListenableFuture<Device> findDeviceByTenantIdAndIdAsync(TenantId tenantId, UUID id);
185 185
186 Long countDevicesByDeviceProfileId(TenantId tenantId, UUID deviceProfileId); 186 Long countDevicesByDeviceProfileId(TenantId tenantId, UUID deviceProfileId);
  187 +
  188 + /**
  189 + * Find devices by tenantId, profileId and page link.
  190 + *
  191 + * @param tenantId the tenantId
  192 + * @param profileId the profileId
  193 + * @param pageLink the page link
  194 + * @return the list of device objects
  195 + */
  196 + PageData<Device> findDevicesByTenantIdAndProfileId(UUID tenantId, UUID profileId, PageLink pageLink);
  197 +
187 } 198 }
@@ -37,4 +37,6 @@ public interface DeviceProfileDao extends Dao<DeviceProfile> { @@ -37,4 +37,6 @@ public interface DeviceProfileDao extends Dao<DeviceProfile> {
37 DeviceProfile findDefaultDeviceProfile(TenantId tenantId); 37 DeviceProfile findDefaultDeviceProfile(TenantId tenantId);
38 38
39 DeviceProfileInfo findDefaultDeviceProfileInfo(TenantId tenantId); 39 DeviceProfileInfo findDefaultDeviceProfileInfo(TenantId tenantId);
  40 +
  41 + DeviceProfile findByName(TenantId tenantId, String profileName);
40 } 42 }
@@ -23,10 +23,12 @@ import org.springframework.cache.Cache; @@ -23,10 +23,12 @@ 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.Device;
26 import org.thingsboard.server.common.data.DeviceProfile; 27 import org.thingsboard.server.common.data.DeviceProfile;
27 import org.thingsboard.server.common.data.DeviceProfileInfo; 28 import org.thingsboard.server.common.data.DeviceProfileInfo;
28 import org.thingsboard.server.common.data.DeviceProfileType; 29 import org.thingsboard.server.common.data.DeviceProfileType;
29 import org.thingsboard.server.common.data.DeviceTransportType; 30 import org.thingsboard.server.common.data.DeviceTransportType;
  31 +import org.thingsboard.server.common.data.EntitySubtype;
30 import org.thingsboard.server.common.data.Tenant; 32 import org.thingsboard.server.common.data.Tenant;
31 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; 33 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
32 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration; 34 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration;
@@ -44,6 +46,7 @@ import org.thingsboard.server.dao.tenant.TenantDao; @@ -44,6 +46,7 @@ import org.thingsboard.server.dao.tenant.TenantDao;
44 46
45 import java.util.Arrays; 47 import java.util.Arrays;
46 import java.util.Collections; 48 import java.util.Collections;
  49 +import java.util.List;
47 50
48 import static org.thingsboard.server.common.data.CacheConstants.DEVICE_PROFILE_CACHE; 51 import static org.thingsboard.server.common.data.CacheConstants.DEVICE_PROFILE_CACHE;
49 import static org.thingsboard.server.dao.service.Validator.validateId; 52 import static org.thingsboard.server.dao.service.Validator.validateId;
@@ -54,6 +57,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -54,6 +57,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
54 57
55 private static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; 58 private static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
56 private static final String INCORRECT_DEVICE_PROFILE_ID = "Incorrect deviceProfileId "; 59 private static final String INCORRECT_DEVICE_PROFILE_ID = "Incorrect deviceProfileId ";
  60 + private static final String INCORRECT_DEVICE_PROFILE_NAME = "Incorrect deviceProfileName ";
57 61
58 @Autowired 62 @Autowired
59 private DeviceProfileDao deviceProfileDao; 63 private DeviceProfileDao deviceProfileDao;
@@ -62,6 +66,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -62,6 +66,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
62 private DeviceDao deviceDao; 66 private DeviceDao deviceDao;
63 67
64 @Autowired 68 @Autowired
  69 + private DeviceService deviceService;
  70 +
  71 + @Autowired
65 private TenantDao tenantDao; 72 private TenantDao tenantDao;
66 73
67 @Autowired 74 @Autowired
@@ -75,6 +82,13 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -75,6 +82,13 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
75 return deviceProfileDao.findById(tenantId, deviceProfileId.getId()); 82 return deviceProfileDao.findById(tenantId, deviceProfileId.getId());
76 } 83 }
77 84
  85 + @Override
  86 + public DeviceProfile findDeviceProfileByName(TenantId tenantId, String profileName) {
  87 + log.trace("Executing findDeviceProfileByName [{}][{}]", tenantId, profileName);
  88 + Validator.validateString(profileName, INCORRECT_DEVICE_PROFILE_NAME + profileName);
  89 + return deviceProfileDao.findByName(tenantId, profileName);
  90 + }
  91 +
78 @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{'info', #deviceProfileId.id}") 92 @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{'info', #deviceProfileId.id}")
79 @Override 93 @Override
80 public DeviceProfileInfo findDeviceProfileInfoById(TenantId tenantId, DeviceProfileId deviceProfileId) { 94 public DeviceProfileInfo findDeviceProfileInfoById(TenantId tenantId, DeviceProfileId deviceProfileId) {
@@ -87,6 +101,10 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -87,6 +101,10 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
87 public DeviceProfile saveDeviceProfile(DeviceProfile deviceProfile) { 101 public DeviceProfile saveDeviceProfile(DeviceProfile deviceProfile) {
88 log.trace("Executing saveDeviceProfile [{}]", deviceProfile); 102 log.trace("Executing saveDeviceProfile [{}]", deviceProfile);
89 deviceProfileValidator.validate(deviceProfile, DeviceProfile::getTenantId); 103 deviceProfileValidator.validate(deviceProfile, DeviceProfile::getTenantId);
  104 + DeviceProfile oldDeviceProfile = null;
  105 + if (deviceProfile.getId() != null) {
  106 + oldDeviceProfile = deviceProfileDao.findById(deviceProfile.getTenantId(), deviceProfile.getId().getId());
  107 + }
90 DeviceProfile savedDeviceProfile; 108 DeviceProfile savedDeviceProfile;
91 try { 109 try {
92 savedDeviceProfile = deviceProfileDao.save(deviceProfile.getTenantId(), deviceProfile); 110 savedDeviceProfile = deviceProfileDao.save(deviceProfile.getTenantId(), deviceProfile);
@@ -101,10 +119,23 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -101,10 +119,23 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
101 Cache cache = cacheManager.getCache(DEVICE_PROFILE_CACHE); 119 Cache cache = cacheManager.getCache(DEVICE_PROFILE_CACHE);
102 cache.evict(Collections.singletonList(savedDeviceProfile.getId().getId())); 120 cache.evict(Collections.singletonList(savedDeviceProfile.getId().getId()));
103 cache.evict(Arrays.asList("info", savedDeviceProfile.getId().getId())); 121 cache.evict(Arrays.asList("info", savedDeviceProfile.getId().getId()));
  122 + cache.evict(Arrays.asList(deviceProfile.getTenantId().getId(), deviceProfile.getName()));
104 if (savedDeviceProfile.isDefault()) { 123 if (savedDeviceProfile.isDefault()) {
105 cache.evict(Arrays.asList("default", savedDeviceProfile.getTenantId().getId())); 124 cache.evict(Arrays.asList("default", savedDeviceProfile.getTenantId().getId()));
106 cache.evict(Arrays.asList("default", "info", savedDeviceProfile.getTenantId().getId())); 125 cache.evict(Arrays.asList("default", "info", savedDeviceProfile.getTenantId().getId()));
107 } 126 }
  127 + if (oldDeviceProfile != null && !oldDeviceProfile.getName().equals(deviceProfile.getName())) {
  128 + PageLink pageLink = new PageLink(100);
  129 + PageData<Device> pageData;
  130 + do {
  131 + pageData = deviceDao.findDevicesByTenantIdAndProfileId(deviceProfile.getTenantId().getId(), deviceProfile.getUuidId(), pageLink);
  132 + for (Device device : pageData.getData()) {
  133 + device.setType(deviceProfile.getName());
  134 + deviceService.saveDevice(device);
  135 + }
  136 + pageLink = pageLink.nextPageLink();
  137 + } while (pageData.hasNext());
  138 + }
108 return savedDeviceProfile; 139 return savedDeviceProfile;
109 } 140 }
110 141
@@ -116,10 +147,11 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -116,10 +147,11 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
116 if (deviceProfile != null && deviceProfile.isDefault()) { 147 if (deviceProfile != null && deviceProfile.isDefault()) {
117 throw new DataValidationException("Deletion of Default Device Profile is prohibited!"); 148 throw new DataValidationException("Deletion of Default Device Profile is prohibited!");
118 } 149 }
119 - this.removeDeviceProfile(tenantId, deviceProfileId); 150 + this.removeDeviceProfile(tenantId, deviceProfile);
120 } 151 }
121 152
122 - private void removeDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId) { 153 + private void removeDeviceProfile(TenantId tenantId, DeviceProfile deviceProfile) {
  154 + DeviceProfileId deviceProfileId = deviceProfile.getId();
123 try { 155 try {
124 deviceProfileDao.removeById(tenantId, deviceProfileId.getId()); 156 deviceProfileDao.removeById(tenantId, deviceProfileId.getId());
125 } catch (Exception t) { 157 } catch (Exception t) {
@@ -134,6 +166,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -134,6 +166,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
134 Cache cache = cacheManager.getCache(DEVICE_PROFILE_CACHE); 166 Cache cache = cacheManager.getCache(DEVICE_PROFILE_CACHE);
135 cache.evict(Collections.singletonList(deviceProfileId.getId())); 167 cache.evict(Collections.singletonList(deviceProfileId.getId()));
136 cache.evict(Arrays.asList("info", deviceProfileId.getId())); 168 cache.evict(Arrays.asList("info", deviceProfileId.getId()));
  169 + cache.evict(Arrays.asList(tenantId.getId(), deviceProfile.getName()));
137 } 170 }
138 171
139 @Override 172 @Override
@@ -152,12 +185,13 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -152,12 +185,13 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
152 return deviceProfileDao.findDeviceProfileInfos(tenantId, pageLink); 185 return deviceProfileDao.findDeviceProfileInfos(tenantId, pageLink);
153 } 186 }
154 187
  188 + @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#tenantId.id, #name}")
155 @Override 189 @Override
156 - public DeviceProfile findOrCreateDefaultDeviceProfile(TenantId tenantId) { 190 + public DeviceProfile findOrCreateDeviceProfile(TenantId tenantId, String name) {
157 log.trace("Executing findOrCreateDefaultDeviceProfile"); 191 log.trace("Executing findOrCreateDefaultDeviceProfile");
158 - DeviceProfile deviceProfile = findDefaultDeviceProfile(tenantId); 192 + DeviceProfile deviceProfile = findDeviceProfileByName(tenantId, name);
159 if (deviceProfile == null) { 193 if (deviceProfile == null) {
160 - deviceProfile = this.createDefaultDeviceProfile(tenantId); 194 + deviceProfile = this.doCreateDefaultDeviceProfile(tenantId, name, name.equals("default"));
161 } 195 }
162 return deviceProfile; 196 return deviceProfile;
163 } 197 }
@@ -168,12 +202,6 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -168,12 +202,6 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
168 return doCreateDefaultDeviceProfile(tenantId, "default", true); 202 return doCreateDefaultDeviceProfile(tenantId, "default", true);
169 } 203 }
170 204
171 - @Override  
172 - public DeviceProfile createDeviceProfile(TenantId tenantId, String profileName) {  
173 - log.trace("Executing createDefaultDeviceProfile tenantId [{}], profileName [{}]", tenantId, profileName);  
174 - return doCreateDefaultDeviceProfile(tenantId, profileName, false);  
175 - }  
176 -  
177 private DeviceProfile doCreateDefaultDeviceProfile(TenantId tenantId, String profileName, boolean defaultProfile) { 205 private DeviceProfile doCreateDefaultDeviceProfile(TenantId tenantId, String profileName, boolean defaultProfile) {
178 validateId(tenantId, INCORRECT_TENANT_ID + tenantId); 206 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
179 DeviceProfile deviceProfile = new DeviceProfile(); 207 DeviceProfile deviceProfile = new DeviceProfile();
@@ -227,6 +255,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -227,6 +255,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
227 deviceProfileDao.save(tenantId, deviceProfile); 255 deviceProfileDao.save(tenantId, deviceProfile);
228 cache.evict(Collections.singletonList(previousDefaultDeviceProfile.getId().getId())); 256 cache.evict(Collections.singletonList(previousDefaultDeviceProfile.getId().getId()));
229 cache.evict(Arrays.asList("info", previousDefaultDeviceProfile.getId().getId())); 257 cache.evict(Arrays.asList("info", previousDefaultDeviceProfile.getId().getId()));
  258 + cache.evict(Arrays.asList(tenantId.getId(), previousDefaultDeviceProfile.getName()));
230 changed = true; 259 changed = true;
231 } 260 }
232 if (changed) { 261 if (changed) {
@@ -234,6 +263,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -234,6 +263,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
234 cache.evict(Arrays.asList("info", deviceProfile.getId().getId())); 263 cache.evict(Arrays.asList("info", deviceProfile.getId().getId()));
235 cache.evict(Arrays.asList("default", tenantId.getId())); 264 cache.evict(Arrays.asList("default", tenantId.getId()));
236 cache.evict(Arrays.asList("default", "info", tenantId.getId())); 265 cache.evict(Arrays.asList("default", "info", tenantId.getId()));
  266 + cache.evict(Arrays.asList(tenantId.getId(), deviceProfile.getName()));
237 } 267 }
238 return changed; 268 return changed;
239 } 269 }
@@ -309,7 +339,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -309,7 +339,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
309 339
310 @Override 340 @Override
311 protected void removeEntity(TenantId tenantId, DeviceProfile entity) { 341 protected void removeEntity(TenantId tenantId, DeviceProfile entity) {
312 - removeDeviceProfile(tenantId, entity.getId()); 342 + removeDeviceProfile(tenantId, entity);
313 } 343 }
314 }; 344 };
315 345
@@ -169,8 +169,14 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -169,8 +169,14 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
169 deviceValidator.validate(device, Device::getTenantId); 169 deviceValidator.validate(device, Device::getTenantId);
170 Device savedDevice; 170 Device savedDevice;
171 try { 171 try {
  172 + DeviceProfile deviceProfile;
172 if (device.getDeviceProfileId() == null) { 173 if (device.getDeviceProfileId() == null) {
173 - DeviceProfile deviceProfile = this.deviceProfileService.findOrCreateDefaultDeviceProfile(device.getTenantId()); 174 + if (!StringUtils.isEmpty(device.getType())) {
  175 + deviceProfile = this.deviceProfileService.findOrCreateDeviceProfile(device.getTenantId(), device.getType());
  176 + } else {
  177 + deviceProfile = this.deviceProfileService.findDefaultDeviceProfile(device.getTenantId());
  178 + device.setType(deviceProfile.getName());
  179 + }
174 device.setDeviceProfileId(new DeviceProfileId(deviceProfile.getId().getId())); 180 device.setDeviceProfileId(new DeviceProfileId(deviceProfile.getId().getId()));
175 DeviceData deviceData = new DeviceData(); 181 DeviceData deviceData = new DeviceData();
176 switch (deviceProfile.getType()) { 182 switch (deviceProfile.getType()) {
@@ -178,7 +184,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -178,7 +184,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
178 deviceData.setConfiguration(new DefaultDeviceConfiguration()); 184 deviceData.setConfiguration(new DefaultDeviceConfiguration());
179 break; 185 break;
180 } 186 }
181 - switch (deviceProfile.getTransportType()){ 187 + switch (deviceProfile.getTransportType()) {
182 case DEFAULT: 188 case DEFAULT:
183 deviceData.setTransportConfiguration(new DefaultDeviceTransportConfiguration()); 189 deviceData.setTransportConfiguration(new DefaultDeviceTransportConfiguration());
184 break; 190 break;
@@ -190,7 +196,14 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -190,7 +196,14 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
190 break; 196 break;
191 } 197 }
192 device.setDeviceData(deviceData); 198 device.setDeviceData(deviceData);
  199 + } else {
  200 + deviceProfile = this.deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId());
  201 + if (deviceProfile == null) {
  202 + throw new DataValidationException("Device is referencing non existing device profile!");
  203 + }
193 } 204 }
  205 + device.setType(deviceProfile.getName());
  206 +
194 savedDevice = deviceDao.save(device.getTenantId(), device); 207 savedDevice = deviceDao.save(device.getTenantId(), device);
195 } catch (Exception t) { 208 } catch (Exception t) {
196 ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); 209 ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
@@ -441,9 +454,6 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -441,9 +454,6 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
441 454
442 @Override 455 @Override
443 protected void validateDataImpl(TenantId tenantId, Device device) { 456 protected void validateDataImpl(TenantId tenantId, Device device) {
444 - if (StringUtils.isEmpty(device.getType())) {  
445 - throw new DataValidationException("Device type should be specified!");  
446 - }  
447 if (StringUtils.isEmpty(device.getName())) { 457 if (StringUtils.isEmpty(device.getName())) {
448 throw new DataValidationException("Device name should be specified!"); 458 throw new DataValidationException("Device name should be specified!");
449 } 459 }
@@ -20,6 +20,7 @@ import org.springframework.data.domain.Pageable; @@ -20,6 +20,7 @@ import org.springframework.data.domain.Pageable;
20 import org.springframework.data.jpa.repository.Query; 20 import org.springframework.data.jpa.repository.Query;
21 import org.springframework.data.repository.PagingAndSortingRepository; 21 import org.springframework.data.repository.PagingAndSortingRepository;
22 import org.springframework.data.repository.query.Param; 22 import org.springframework.data.repository.query.Param;
  23 +import org.thingsboard.server.common.data.DeviceProfile;
23 import org.thingsboard.server.common.data.DeviceProfileInfo; 24 import org.thingsboard.server.common.data.DeviceProfileInfo;
24 import org.thingsboard.server.dao.model.sql.DeviceProfileEntity; 25 import org.thingsboard.server.dao.model.sql.DeviceProfileEntity;
25 26
@@ -53,4 +54,7 @@ public interface DeviceProfileRepository extends PagingAndSortingRepository<Devi @@ -53,4 +54,7 @@ public interface DeviceProfileRepository extends PagingAndSortingRepository<Devi
53 "FROM DeviceProfileEntity d " + 54 "FROM DeviceProfileEntity d " +
54 "WHERE d.tenantId = :tenantId AND d.isDefault = true") 55 "WHERE d.tenantId = :tenantId AND d.isDefault = true")
55 DeviceProfileInfo findDefaultDeviceProfileInfo(@Param("tenantId") UUID tenantId); 56 DeviceProfileInfo findDefaultDeviceProfileInfo(@Param("tenantId") UUID tenantId);
  57 +
  58 + DeviceProfileEntity findByTenantIdAndName(UUID id, String profileName);
  59 +
56 } 60 }
@@ -46,6 +46,14 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit @@ -46,6 +46,14 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit
46 @Param("searchText") String searchText, 46 @Param("searchText") String searchText,
47 Pageable pageable); 47 Pageable pageable);
48 48
  49 + @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " +
  50 + "AND d.deviceProfileId = :profileId " +
  51 + "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
  52 + Page<DeviceEntity> findByTenantIdAndProfileId(@Param("tenantId") UUID tenantId,
  53 + @Param("profileId") UUID profileId,
  54 + @Param("searchText") String searchText,
  55 + Pageable pageable);
  56 +
49 @Query("SELECT new org.thingsboard.server.dao.model.sql.DeviceInfoEntity(d, c.title, c.additionalInfo, p.name) " + 57 @Query("SELECT new org.thingsboard.server.dao.model.sql.DeviceInfoEntity(d, c.title, c.additionalInfo, p.name) " +
50 "FROM DeviceEntity d " + 58 "FROM DeviceEntity d " +
51 "LEFT JOIN CustomerEntity c on c.id = d.customerId " + 59 "LEFT JOIN CustomerEntity c on c.id = d.customerId " +
@@ -105,6 +105,16 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device> @@ -105,6 +105,16 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device>
105 } 105 }
106 106
107 @Override 107 @Override
  108 + public PageData<Device> findDevicesByTenantIdAndProfileId(UUID tenantId, UUID profileId, PageLink pageLink) {
  109 + return DaoUtil.toPageData(
  110 + deviceRepository.findByTenantIdAndProfileId(
  111 + tenantId,
  112 + profileId,
  113 + Objects.toString(pageLink.getTextSearch(), ""),
  114 + DaoUtil.toPageable(pageLink)));
  115 + }
  116 +
  117 + @Override
108 public PageData<DeviceInfo> findDeviceInfosByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink) { 118 public PageData<DeviceInfo> findDeviceInfosByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink) {
109 return DaoUtil.toPageData( 119 return DaoUtil.toPageData(
110 deviceRepository.findDeviceInfosByTenantIdAndCustomerId( 120 deviceRepository.findDeviceInfosByTenantIdAndCustomerId(
@@ -80,4 +80,8 @@ public class JpaDeviceProfileDao extends JpaAbstractSearchTextDao<DeviceProfileE @@ -80,4 +80,8 @@ public class JpaDeviceProfileDao extends JpaAbstractSearchTextDao<DeviceProfileE
80 return deviceProfileRepository.findDefaultDeviceProfileInfo(tenantId.getId()); 80 return deviceProfileRepository.findDefaultDeviceProfileInfo(tenantId.getId());
81 } 81 }
82 82
  83 + @Override
  84 + public DeviceProfile findByName(TenantId tenantId, String profileName) {
  85 + return DaoUtil.getData(deviceProfileRepository.findByTenantIdAndName(tenantId.getId(), profileName));
  86 + }
83 } 87 }
@@ -270,7 +270,7 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { @@ -270,7 +270,7 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
270 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); 270 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
271 device.setName(name); 271 device.setName(name);
272 device.setType("default"); 272 device.setType("default");
273 - devicesTitle1.add(new DeviceInfo(deviceService.saveDevice(device), null, false, "Default")); 273 + devicesTitle1.add(new DeviceInfo(deviceService.saveDevice(device), null, false, "default"));
274 } 274 }
275 String title2 = "Device title 2"; 275 String title2 = "Device title 2";
276 List<DeviceInfo> devicesTitle2 = new ArrayList<>(); 276 List<DeviceInfo> devicesTitle2 = new ArrayList<>();
@@ -282,7 +282,7 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { @@ -282,7 +282,7 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
282 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); 282 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
283 device.setName(name); 283 device.setName(name);
284 device.setType("default"); 284 device.setType("default");
285 - devicesTitle2.add(new DeviceInfo(deviceService.saveDevice(device), null, false, "Default")); 285 + devicesTitle2.add(new DeviceInfo(deviceService.saveDevice(device), null, false, "default"));
286 } 286 }
287 287
288 List<DeviceInfo> loadedDevicesTitle1 = new ArrayList<>(); 288 List<DeviceInfo> loadedDevicesTitle1 = new ArrayList<>();
@@ -435,7 +435,7 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { @@ -435,7 +435,7 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
435 device.setName("Device"+i); 435 device.setName("Device"+i);
436 device.setType("default"); 436 device.setType("default");
437 device = deviceService.saveDevice(device); 437 device = deviceService.saveDevice(device);
438 - devices.add(new DeviceInfo(deviceService.assignDeviceToCustomer(tenantId, device.getId(), customerId), customer.getTitle(), customer.isPublic(), "Default")); 438 + devices.add(new DeviceInfo(deviceService.assignDeviceToCustomer(tenantId, device.getId(), customerId), customer.getTitle(), customer.isPublic(), "default"));
439 } 439 }
440 440
441 List<DeviceInfo> loadedDevices = new ArrayList<>(); 441 List<DeviceInfo> loadedDevices = new ArrayList<>();