Commit 43596ec5ce8e60e639cda86bc8414fe17b41587d
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<>(); |