Commit 8a8695f260e0b98615c711a4c0d6b77819a2c26a

Authored by zbeacon
1 parent 15be6d60

Working version for provision feature with provision credentials on device level

Showing 19 changed files with 267 additions and 105 deletions
@@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileC @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileC
34 import org.thingsboard.server.common.data.device.profile.ProvisionRequestValidationStrategyType; 34 import org.thingsboard.server.common.data.device.profile.ProvisionRequestValidationStrategyType;
35 import org.thingsboard.server.common.data.id.CustomerId; 35 import org.thingsboard.server.common.data.id.CustomerId;
36 import org.thingsboard.server.common.data.id.TenantId; 36 import org.thingsboard.server.common.data.id.TenantId;
  37 +import org.thingsboard.server.common.data.id.UserId;
37 import org.thingsboard.server.common.data.kv.AttributeKvEntry; 38 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
38 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; 39 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
39 import org.thingsboard.server.common.data.kv.StringDataEntry; 40 import org.thingsboard.server.common.data.kv.StringDataEntry;
@@ -60,6 +61,7 @@ import org.thingsboard.server.queue.TbQueueCallback; @@ -60,6 +61,7 @@ import org.thingsboard.server.queue.TbQueueCallback;
60 import org.thingsboard.server.queue.TbQueueProducer; 61 import org.thingsboard.server.queue.TbQueueProducer;
61 import org.thingsboard.server.queue.common.TbProtoQueueMsg; 62 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
62 import org.thingsboard.server.queue.discovery.PartitionService; 63 import org.thingsboard.server.queue.discovery.PartitionService;
  64 +import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
63 import org.thingsboard.server.service.state.DeviceStateService; 65 import org.thingsboard.server.service.state.DeviceStateService;
64 66
65 import java.util.Collections; 67 import java.util.Collections;
@@ -103,55 +105,88 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { @@ -103,55 +105,88 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService {
103 @Autowired 105 @Autowired
104 PartitionService partitionService; 106 PartitionService partitionService;
105 107
  108 + public DeviceProvisionServiceImpl(TbQueueProducerProvider producerProvider) {
  109 + ruleEngineMsgProducer = producerProvider.getRuleEngineMsgProducer();
  110 + }
106 111
107 @Override 112 @Override
108 public ListenableFuture<ProvisionResponse> provisionDevice(ProvisionRequest provisionRequest) { 113 public ListenableFuture<ProvisionResponse> provisionDevice(ProvisionRequest provisionRequest) {
109 - Device targetDevice = deviceDao.findDeviceByTenantIdAndDeviceDataProvisionConfigurationPair(  
110 - TenantId.SYS_TENANT_ID,  
111 - provisionRequest.getCredentials().getProvisionDeviceKey(),  
112 - provisionRequest.getCredentials().getProvisionDeviceSecret()); 114 + String provisionRequestKey = provisionRequest.getCredentials().getProvisionDeviceKey();
  115 + String provisionRequestSecret = provisionRequest.getCredentials().getProvisionDeviceSecret();
113 116
114 - if (targetDevice != null) {  
115 - if (targetDevice.getDeviceData().getConfiguration().getType() != DeviceProfileType.PROVISION) {  
116 - return Futures.immediateFuture(new ProvisionResponse(null, ProvisionResponseStatus.NOT_FOUND));  
117 - } 117 + if (StringUtils.isEmpty(provisionRequestKey) || StringUtils.isEmpty(provisionRequestSecret)) {
  118 + return Futures.immediateFuture(new ProvisionResponse(null, ProvisionResponseStatus.NOT_FOUND));
  119 + }
118 120
119 - DeviceProfile targetProfile = deviceProfileDao.findById(TenantId.SYS_TENANT_ID, targetDevice.getDeviceProfileId().getId()); 121 + Device targetDevice = deviceDao.findDeviceByProfileNameAndDeviceDataProvisionConfigurationPair(
  122 + provisionRequest.getDeviceType(),
  123 + provisionRequestKey,
  124 + provisionRequestSecret
  125 + ).orElse(null);
120 126
121 - ProvisionDeviceConfiguration currentProfileConfiguration = (ProvisionDeviceConfiguration) targetDevice.getDeviceData().getConfiguration();  
122 - if (!new ProvisionDeviceConfiguration(provisionRequest.getCredentials().getProvisionDeviceKey(), provisionRequest.getCredentials().getProvisionDeviceSecret()).equals(currentProfileConfiguration)) {  
123 - return Futures.immediateFuture(new ProvisionResponse(null, ProvisionResponseStatus.NOT_FOUND));  
124 - }  
125 - ProvisionRequestValidationStrategyType targetStrategy = getStrategy(targetProfile);  
126 - switch (targetStrategy) {  
127 - case CHECK_NEW_DEVICE:  
128 - log.warn("[{}] The device is present and could not be provisioned once more!", targetDevice.getName());  
129 - notify(targetDevice, provisionRequest, DataConstants.PROVISION_FAILURE, false);  
130 - return Futures.immediateFuture(new ProvisionResponse(null, ProvisionResponseStatus.FAILURE));  
131 - case CHECK_PRE_PROVISIONED_DEVICE:  
132 - return processProvision(targetDevice, provisionRequest);  
133 - default:  
134 - throw new RuntimeException("Strategy is not supported - " + targetStrategy.name());  
135 - } 127 + if (targetDevice != null) {
  128 + return processProvisionDeviceWithKeySecretPairExists(provisionRequest, provisionRequestKey, provisionRequestSecret, targetDevice);
136 } else { 129 } else {
137 - DeviceProfile targetProfile = deviceProfileDao.findProfileByTenantIdAndProfileDataProvisionConfigurationPair(  
138 - TenantId.SYS_TENANT_ID,  
139 - provisionRequest.getCredentials().getProvisionDeviceKey(),  
140 - provisionRequest.getCredentials().getProvisionDeviceSecret()  
141 - );  
142 - if (targetProfile.getProfileData().getConfiguration().getType() != DeviceProfileType.PROVISION) {  
143 - return Futures.immediateFuture(new ProvisionResponse(null, ProvisionResponseStatus.NOT_FOUND));  
144 - }  
145 - ProvisionRequestValidationStrategyType targetStrategy = getStrategy(targetProfile);  
146 - switch (targetStrategy) {  
147 - case CHECK_NEW_DEVICE:  
148 - return createDevice(provisionRequest, targetProfile);  
149 - case CHECK_PRE_PROVISIONED_DEVICE:  
150 - log.warn("[{}] Failed to find pre provisioned device!", provisionRequest.getDeviceName());  
151 - return Futures.immediateFuture(new ProvisionResponse(null, ProvisionResponseStatus.FAILURE));  
152 - default:  
153 - throw new RuntimeException("Strategy is not supported - " + targetStrategy.name());  
154 - } 130 + return processProvisionDeviceWithKeySecretPairNotExists(provisionRequest, provisionRequestKey, provisionRequestSecret);
  131 + }
  132 + }
  133 +
  134 + private ListenableFuture<ProvisionResponse> processProvisionDeviceWithKeySecretPairExists(ProvisionRequest provisionRequest, String provisionRequestKey, String provisionRequestSecret, Device targetDevice) {
  135 + if (targetDevice.getDeviceData().getConfiguration().getType() != DeviceProfileType.PROVISION) {
  136 + return Futures.immediateFuture(new ProvisionResponse(null, ProvisionResponseStatus.NOT_FOUND));
  137 + }
  138 +
  139 + DeviceProfile targetProfile = deviceProfileDao.findById(targetDevice.getTenantId(), targetDevice.getDeviceProfileId().getId());
  140 +
  141 + if (targetProfile == null || targetProfile.getProfileData().getConfiguration().getType() != DeviceProfileType.PROVISION) {
  142 + return Futures.immediateFuture(new ProvisionResponse(null, ProvisionResponseStatus.NOT_FOUND));
  143 + }
  144 +
  145 + ProvisionDeviceConfiguration currentDeviceConfiguration = (ProvisionDeviceConfiguration) targetDevice.getDeviceData().getConfiguration();
  146 +
  147 + if (!new ProvisionDeviceConfiguration(provisionRequestKey, provisionRequestSecret).equals(currentDeviceConfiguration)) {
  148 + return Futures.immediateFuture(new ProvisionResponse(null, ProvisionResponseStatus.NOT_FOUND));
  149 + }
  150 +
  151 + ProvisionRequestValidationStrategyType targetStrategy = getStrategy(targetProfile);
  152 + switch (targetStrategy) {
  153 + case CHECK_NEW_DEVICE:
  154 + log.warn("[{}] The device is present and could not be provisioned once more!", targetDevice.getName());
  155 + notify(targetDevice, provisionRequest, DataConstants.PROVISION_FAILURE, false);
  156 + return Futures.immediateFuture(new ProvisionResponse(null, ProvisionResponseStatus.FAILURE));
  157 + case CHECK_PRE_PROVISIONED_DEVICE:
  158 + return processProvision(targetDevice, provisionRequest);
  159 + default:
  160 + throw new RuntimeException("Strategy is not supported - " + targetStrategy.name());
  161 + }
  162 + }
  163 +
  164 + private ListenableFuture<ProvisionResponse> processProvisionDeviceWithKeySecretPairNotExists(ProvisionRequest provisionRequest, String provisionRequestKey, String provisionRequestSecret){
  165 + DeviceProfile targetProfile = deviceProfileDao.findProfileByProfileNameAndProfileDataProvisionConfigurationPair(
  166 + provisionRequest.getDeviceType(),
  167 + provisionRequestKey,
  168 + provisionRequestSecret
  169 + );
  170 +
  171 + if (targetProfile == null || targetProfile.getProfileData().getConfiguration().getType() != DeviceProfileType.PROVISION) {
  172 + return Futures.immediateFuture(new ProvisionResponse(null, ProvisionResponseStatus.NOT_FOUND));
  173 + }
  174 + ProvisionRequestValidationStrategyType targetStrategy = getStrategy(targetProfile);
  175 + switch (targetStrategy) {
  176 + case CHECK_NEW_DEVICE:
  177 + return createDevice(provisionRequest, targetProfile);
  178 + case CHECK_PRE_PROVISIONED_DEVICE:
  179 + ProvisionDeviceProfileConfiguration currentDeviceProfileConfiguration = (ProvisionDeviceProfileConfiguration) targetProfile.getProfileData().getConfiguration();
  180 + if(new ProvisionDeviceProfileConfiguration(provisionRequestKey, provisionRequestSecret).equals(currentDeviceProfileConfiguration)) {
  181 + Optional<Device> optionalDevice = deviceDao.findDeviceByTenantIdAndName(targetProfile.getTenantId().getId(), provisionRequest.getDeviceName());
  182 + if (optionalDevice.isPresent()) {
  183 + return processProvision(optionalDevice.get(), provisionRequest);
  184 + }
  185 + }
  186 + log.warn("[{}] Failed to find pre provisioned device!", provisionRequest.getDeviceName());
  187 + return Futures.immediateFuture(new ProvisionResponse(null, ProvisionResponseStatus.FAILURE));
  188 + default:
  189 + throw new RuntimeException("Strategy is not supported - " + targetStrategy.name());
155 } 190 }
156 } 191 }
157 192
@@ -281,6 +316,6 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { @@ -281,6 +316,6 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService {
281 316
282 private void logAction(TenantId tenantId, CustomerId customerId, Device device, boolean success, ProvisionRequest provisionRequest) { 317 private void logAction(TenantId tenantId, CustomerId customerId, Device device, boolean success, ProvisionRequest provisionRequest) {
283 ActionType actionType = success ? ActionType.PROVISION_SUCCESS : ActionType.PROVISION_FAILURE; 318 ActionType actionType = success ? ActionType.PROVISION_SUCCESS : ActionType.PROVISION_FAILURE;
284 - auditLogService.logEntityAction(tenantId, customerId, null, device.getName(), device.getId(), device, actionType, null, provisionRequest); 319 + auditLogService.logEntityAction(tenantId, customerId, new UserId(UserId.NULL_UUID), device.getName(), device.getId(), device, actionType, null, provisionRequest);
285 } 320 }
286 } 321 }
@@ -22,6 +22,7 @@ import com.google.common.util.concurrent.Futures; @@ -22,6 +22,7 @@ import com.google.common.util.concurrent.Futures;
22 import com.google.common.util.concurrent.ListenableFuture; 22 import com.google.common.util.concurrent.ListenableFuture;
23 import com.google.common.util.concurrent.MoreExecutors; 23 import com.google.common.util.concurrent.MoreExecutors;
24 import com.google.protobuf.ByteString; 24 import com.google.protobuf.ByteString;
  25 +import com.google.protobuf.InvalidProtocolBufferException;
25 import lombok.extern.slf4j.Slf4j; 26 import lombok.extern.slf4j.Slf4j;
26 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 27 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
27 import org.springframework.stereotype.Service; 28 import org.springframework.stereotype.Service;
@@ -31,6 +32,7 @@ import org.thingsboard.server.common.data.Device; @@ -31,6 +32,7 @@ import org.thingsboard.server.common.data.Device;
31 import org.thingsboard.server.common.data.DeviceProfile; 32 import org.thingsboard.server.common.data.DeviceProfile;
32 import org.thingsboard.server.common.data.TenantProfile; 33 import org.thingsboard.server.common.data.TenantProfile;
33 import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; 34 import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
  35 +import org.thingsboard.server.common.data.device.data.ProvisionDeviceConfiguration;
34 import org.thingsboard.server.common.data.id.CustomerId; 36 import org.thingsboard.server.common.data.id.CustomerId;
35 import org.thingsboard.server.common.data.id.DeviceId; 37 import org.thingsboard.server.common.data.id.DeviceId;
36 import org.thingsboard.server.common.data.id.DeviceProfileId; 38 import org.thingsboard.server.common.data.id.DeviceProfileId;
@@ -45,17 +47,24 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -45,17 +47,24 @@ import org.thingsboard.server.common.msg.TbMsgMetaData;
45 import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; 47 import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
46 import org.thingsboard.server.dao.device.DeviceCredentialsService; 48 import org.thingsboard.server.dao.device.DeviceCredentialsService;
47 import org.thingsboard.server.dao.device.DeviceProfileService; 49 import org.thingsboard.server.dao.device.DeviceProfileService;
  50 +import org.thingsboard.server.dao.device.DeviceProvisionService;
48 import org.thingsboard.server.dao.device.DeviceService; 51 import org.thingsboard.server.dao.device.DeviceService;
  52 +import org.thingsboard.server.dao.device.provision.ProvisionRequest;
  53 +import org.thingsboard.server.dao.device.provision.ProvisionResponse;
  54 +import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus;
49 import org.thingsboard.server.dao.relation.RelationService; 55 import org.thingsboard.server.dao.relation.RelationService;
50 import org.thingsboard.server.dao.tenant.TenantProfileService; 56 import org.thingsboard.server.dao.tenant.TenantProfileService;
51 import org.thingsboard.server.dao.tenant.TenantService; 57 import org.thingsboard.server.dao.tenant.TenantService;
52 import org.thingsboard.server.dao.util.mapping.JacksonUtil; 58 import org.thingsboard.server.dao.util.mapping.JacksonUtil;
53 import org.thingsboard.server.gen.transport.TransportProtos; 59 import org.thingsboard.server.gen.transport.TransportProtos;
  60 +import org.thingsboard.server.gen.transport.TransportProtos.CredentialsType;
54 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; 61 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto;
55 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; 62 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg;
56 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; 63 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg;
57 import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoRequestMsg; 64 import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoRequestMsg;
58 import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoResponseMsg; 65 import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoResponseMsg;
  66 +import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceCredentialsMsg;
  67 +import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
59 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; 68 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg;
60 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; 69 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
61 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; 70 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
@@ -94,6 +103,7 @@ public class DefaultTransportApiService implements TransportApiService { @@ -94,6 +103,7 @@ public class DefaultTransportApiService implements TransportApiService {
94 private final DbCallbackExecutorService dbCallbackExecutorService; 103 private final DbCallbackExecutorService dbCallbackExecutorService;
95 private final TbClusterService tbClusterService; 104 private final TbClusterService tbClusterService;
96 private final DataDecodingEncodingService dataDecodingEncodingService; 105 private final DataDecodingEncodingService dataDecodingEncodingService;
  106 + private final DeviceProvisionService deviceProvisionService;
97 107
98 108
99 private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>(); 109 private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>();
@@ -102,7 +112,8 @@ public class DefaultTransportApiService implements TransportApiService { @@ -102,7 +112,8 @@ public class DefaultTransportApiService implements TransportApiService {
102 TenantProfileService tenantProfileService, DeviceService deviceService, 112 TenantProfileService tenantProfileService, DeviceService deviceService,
103 RelationService relationService, DeviceCredentialsService deviceCredentialsService, 113 RelationService relationService, DeviceCredentialsService deviceCredentialsService,
104 DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService, 114 DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService,
105 - TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService) { 115 + TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService,
  116 + DeviceProvisionService deviceProvisionService) {
106 this.deviceProfileService = deviceProfileService; 117 this.deviceProfileService = deviceProfileService;
107 this.tenantService = tenantService; 118 this.tenantService = tenantService;
108 this.tenantProfileService = tenantProfileService; 119 this.tenantProfileService = tenantProfileService;
@@ -113,6 +124,7 @@ public class DefaultTransportApiService implements TransportApiService { @@ -113,6 +124,7 @@ public class DefaultTransportApiService implements TransportApiService {
113 this.dbCallbackExecutorService = dbCallbackExecutorService; 124 this.dbCallbackExecutorService = dbCallbackExecutorService;
114 this.tbClusterService = tbClusterService; 125 this.tbClusterService = tbClusterService;
115 this.dataDecodingEncodingService = dataDecodingEncodingService; 126 this.dataDecodingEncodingService = dataDecodingEncodingService;
  127 + this.deviceProvisionService = deviceProvisionService;
116 } 128 }
117 129
118 @Override 130 @Override
@@ -139,6 +151,9 @@ public class DefaultTransportApiService implements TransportApiService { @@ -139,6 +151,9 @@ public class DefaultTransportApiService implements TransportApiService {
139 } else if (transportApiRequestMsg.hasGetDeviceProfileRequestMsg()) { 151 } else if (transportApiRequestMsg.hasGetDeviceProfileRequestMsg()) {
140 return Futures.transform(handle(transportApiRequestMsg.getGetDeviceProfileRequestMsg()), 152 return Futures.transform(handle(transportApiRequestMsg.getGetDeviceProfileRequestMsg()),
141 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 153 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
  154 + } else if (transportApiRequestMsg.hasProvisionDeviceRequestMsg()) {
  155 + return Futures.transform(handle(transportApiRequestMsg.getProvisionDeviceRequestMsg()),
  156 + value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
142 } 157 }
143 return Futures.transform(getEmptyTransportApiResponseFuture(), 158 return Futures.transform(getEmptyTransportApiResponseFuture(),
144 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 159 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
@@ -261,6 +276,47 @@ public class DefaultTransportApiService implements TransportApiService { @@ -261,6 +276,47 @@ public class DefaultTransportApiService implements TransportApiService {
261 }, dbCallbackExecutorService); 276 }, dbCallbackExecutorService);
262 } 277 }
263 278
  279 +
  280 + private ListenableFuture<TransportApiResponseMsg> handle(ProvisionDeviceRequestMsg requestMsg) {
  281 + ListenableFuture<ProvisionResponse> provisionResponseFuture = null;
  282 + provisionResponseFuture = deviceProvisionService.provisionDevice(
  283 + new ProvisionRequest(
  284 + requestMsg.getDeviceName(),
  285 + requestMsg.getDeviceType(),
  286 + requestMsg.getX509CertPubKey(),
  287 + new ProvisionDeviceConfiguration(
  288 + requestMsg.getProvisionDeviceCredentialsMsg().getProvisionDeviceKey(),
  289 + requestMsg.getProvisionDeviceCredentialsMsg().getProvisionDeviceSecret())));
  290 + return Futures.transform(provisionResponseFuture, provisionResponse -> {
  291 + if (provisionResponse.getResponseStatus() == ProvisionResponseStatus.NOT_FOUND) {
  292 + return getTransportApiResponseMsg(TransportProtos.DeviceCredentialsProto.getDefaultInstance(), TransportProtos.ProvisionResponseStatus.NOT_FOUND);
  293 + } else if (provisionResponse.getResponseStatus() == ProvisionResponseStatus.FAILURE) {
  294 + return getTransportApiResponseMsg(TransportProtos.DeviceCredentialsProto.getDefaultInstance(), TransportProtos.ProvisionResponseStatus.FAILURE);
  295 + } else {
  296 + return getTransportApiResponseMsg(getDeviceCredentials(provisionResponse.getDeviceCredentials()), TransportProtos.ProvisionResponseStatus.SUCCESS);
  297 + }
  298 + }, dbCallbackExecutorService);
  299 + }
  300 +
  301 + private TransportApiResponseMsg getTransportApiResponseMsg(TransportProtos.DeviceCredentialsProto deviceCredentials, TransportProtos.ProvisionResponseStatus status) {
  302 + return TransportApiResponseMsg.newBuilder()
  303 + .setProvisionDeviceResponseMsg(TransportProtos.ProvisionDeviceResponseMsg.newBuilder()
  304 + .setDeviceCredentials(deviceCredentials)
  305 + .setProvisionResponseStatus(status)
  306 + .build())
  307 + .build();
  308 + }
  309 +
  310 + private TransportProtos.DeviceCredentialsProto getDeviceCredentials(DeviceCredentials deviceCredentials) {
  311 + return TransportProtos.DeviceCredentialsProto.newBuilder()
  312 + .setDeviceIdMSB(deviceCredentials.getDeviceId().getId().getMostSignificantBits())
  313 + .setDeviceIdLSB(deviceCredentials.getDeviceId().getId().getLeastSignificantBits())
  314 + .setCredentialsType(deviceCredentials.getCredentialsType() == DeviceCredentialsType.ACCESS_TOKEN ?
  315 + CredentialsType.ACCESS_TOKEN : CredentialsType.X509_CERTIFICATE)
  316 + .setCredentialsId(deviceCredentials.getCredentialsId())
  317 + .setCredentialsValue(deviceCredentials.getCredentialsValue() != null ? deviceCredentials.getCredentialsValue() : "")
  318 + .build();
  319 + }
264 private ListenableFuture<TransportApiResponseMsg> handle(GetTenantRoutingInfoRequestMsg requestMsg) { 320 private ListenableFuture<TransportApiResponseMsg> handle(GetTenantRoutingInfoRequestMsg requestMsg) {
265 TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB())); 321 TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB()));
266 // TODO: Tenant Profile from cache 322 // TODO: Tenant Profile from cache
@@ -473,7 +473,9 @@ spring: @@ -473,7 +473,9 @@ spring:
473 enabled: "true" 473 enabled: "true"
474 jpa: 474 jpa:
475 open-in-view: "false" 475 open-in-view: "false"
  476 + show-sql: "true"
476 hibernate: 477 hibernate:
  478 + format_sql: "true"
477 ddl-auto: "none" 479 ddl-auto: "none"
478 database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.PostgreSQLDialect}" 480 database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.PostgreSQLDialect}"
479 datasource: 481 datasource:
@@ -27,7 +27,8 @@ import org.thingsboard.server.common.data.DeviceProfileType; @@ -27,7 +27,8 @@ import org.thingsboard.server.common.data.DeviceProfileType;
27 include = JsonTypeInfo.As.PROPERTY, 27 include = JsonTypeInfo.As.PROPERTY,
28 property = "type") 28 property = "type")
29 @JsonSubTypes({ 29 @JsonSubTypes({
30 - @JsonSubTypes.Type(value = DefaultDeviceConfiguration.class, name = "DEFAULT")}) 30 + @JsonSubTypes.Type(value = DefaultDeviceConfiguration.class, name = "DEFAULT"),
  31 + @JsonSubTypes.Type(value = ProvisionDeviceConfiguration.class, name = "PROVISION")})
31 public interface DeviceConfiguration { 32 public interface DeviceConfiguration {
32 33
33 @JsonIgnore 34 @JsonIgnore
@@ -16,5 +16,5 @@ @@ -16,5 +16,5 @@
16 package org.thingsboard.server.common.msg.session; 16 package org.thingsboard.server.common.msg.session;
17 17
18 public enum FeatureType { 18 public enum FeatureType {
19 - ATTRIBUTES, TELEMETRY, RPC, CLAIM 19 + ATTRIBUTES, TELEMETRY, RPC, CLAIM, PROVISION
20 } 20 }
@@ -477,7 +477,7 @@ message TransportApiRequestMsg { @@ -477,7 +477,7 @@ message TransportApiRequestMsg {
477 GetTenantRoutingInfoRequestMsg getTenantRoutingInfoRequestMsg = 4; 477 GetTenantRoutingInfoRequestMsg getTenantRoutingInfoRequestMsg = 4;
478 GetDeviceProfileRequestMsg getDeviceProfileRequestMsg = 5; 478 GetDeviceProfileRequestMsg getDeviceProfileRequestMsg = 5;
479 ValidateBasicMqttCredRequestMsg validateBasicMqttCredRequestMsg = 6; 479 ValidateBasicMqttCredRequestMsg validateBasicMqttCredRequestMsg = 6;
480 -// ProvisionDeviceRequestMsg provisionDeviceRequestMsg = 7; 480 + ProvisionDeviceRequestMsg provisionDeviceRequestMsg = 7;
481 } 481 }
482 482
483 /* Response from ThingsBoard Core Service to Transport Service */ 483 /* Response from ThingsBoard Core Service to Transport Service */
@@ -486,7 +486,7 @@ message TransportApiResponseMsg { @@ -486,7 +486,7 @@ message TransportApiResponseMsg {
486 GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 2; 486 GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 2;
487 GetTenantRoutingInfoResponseMsg getTenantRoutingInfoResponseMsg = 4; 487 GetTenantRoutingInfoResponseMsg getTenantRoutingInfoResponseMsg = 4;
488 GetDeviceProfileResponseMsg getDeviceProfileResponseMsg = 5; 488 GetDeviceProfileResponseMsg getDeviceProfileResponseMsg = 5;
489 -// ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 6; 489 + ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 6;
490 } 490 }
491 491
492 /* Messages that are handled by ThingsBoard Core Service */ 492 /* Messages that are handled by ThingsBoard Core Service */
@@ -24,6 +24,7 @@ import org.eclipse.californium.core.network.ExchangeObserver; @@ -24,6 +24,7 @@ import org.eclipse.californium.core.network.ExchangeObserver;
24 import org.eclipse.californium.core.server.resources.CoapExchange; 24 import org.eclipse.californium.core.server.resources.CoapExchange;
25 import org.eclipse.californium.core.server.resources.Resource; 25 import org.eclipse.californium.core.server.resources.Resource;
26 import org.springframework.util.ReflectionUtils; 26 import org.springframework.util.ReflectionUtils;
  27 +import org.thingsboard.server.common.data.DataConstants;
27 import org.thingsboard.server.common.data.DeviceTransportType; 28 import org.thingsboard.server.common.data.DeviceTransportType;
28 import org.thingsboard.server.common.data.security.DeviceTokenCredentials; 29 import org.thingsboard.server.common.data.security.DeviceTokenCredentials;
29 import org.thingsboard.server.common.msg.session.FeatureType; 30 import org.thingsboard.server.common.msg.session.FeatureType;
@@ -33,9 +34,11 @@ import org.thingsboard.server.common.transport.TransportContext; @@ -33,9 +34,11 @@ import org.thingsboard.server.common.transport.TransportContext;
33 import org.thingsboard.server.common.transport.TransportService; 34 import org.thingsboard.server.common.transport.TransportService;
34 import org.thingsboard.server.common.transport.TransportServiceCallback; 35 import org.thingsboard.server.common.transport.TransportServiceCallback;
35 import org.thingsboard.server.common.transport.adaptor.AdaptorException; 36 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
  37 +import org.thingsboard.server.common.transport.adaptor.JsonConverter;
36 import org.thingsboard.server.common.transport.auth.SessionInfoCreator; 38 import org.thingsboard.server.common.transport.auth.SessionInfoCreator;
37 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; 39 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
38 import org.thingsboard.server.gen.transport.TransportProtos; 40 import org.thingsboard.server.gen.transport.TransportProtos;
  41 +import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg;
39 42
40 import java.lang.reflect.Field; 43 import java.lang.reflect.Field;
41 import java.util.List; 44 import java.util.List;
@@ -130,10 +133,25 @@ public class CoapTransportResource extends CoapResource { @@ -130,10 +133,25 @@ public class CoapTransportResource extends CoapResource {
130 case CLAIM: 133 case CLAIM:
131 processRequest(exchange, SessionMsgType.CLAIM_REQUEST); 134 processRequest(exchange, SessionMsgType.CLAIM_REQUEST);
132 break; 135 break;
  136 + case PROVISION:
  137 + processProvision(exchange);
  138 + break;
133 } 139 }
134 } 140 }
135 } 141 }
136 142
  143 + private void processProvision(CoapExchange exchange) {
  144 + log.trace("Processing {}", exchange.advanced().getRequest());
  145 + exchange.accept();
  146 + try {
  147 + transportService.process(transportContext.getAdaptor().convertToProvisionRequestMsg(UUID.randomUUID(), exchange.advanced().getRequest()),
  148 + new DeviceProvisionCallback(exchange));
  149 + } catch (AdaptorException e) {
  150 + log.trace("Failed to decode message: ", e);
  151 + exchange.respond(ResponseCode.BAD_REQUEST);
  152 + }
  153 + }
  154 +
137 private void processRequest(CoapExchange exchange, SessionMsgType type) { 155 private void processRequest(CoapExchange exchange, SessionMsgType type) {
138 log.trace("Processing {}", exchange.advanced().getRequest()); 156 log.trace("Processing {}", exchange.advanced().getRequest());
139 exchange.accept(); 157 exchange.accept();
@@ -274,6 +292,8 @@ public class CoapTransportResource extends CoapResource { @@ -274,6 +292,8 @@ public class CoapTransportResource extends CoapResource {
274 try { 292 try {
275 if (uriPath.size() >= FEATURE_TYPE_POSITION) { 293 if (uriPath.size() >= FEATURE_TYPE_POSITION) {
276 return Optional.of(FeatureType.valueOf(uriPath.get(FEATURE_TYPE_POSITION - 1).toUpperCase())); 294 return Optional.of(FeatureType.valueOf(uriPath.get(FEATURE_TYPE_POSITION - 1).toUpperCase()));
  295 + } else if (uriPath.size() == 3 && uriPath.contains(DataConstants.PROVISION)) {
  296 + return Optional.of(FeatureType.valueOf(DataConstants.PROVISION.toUpperCase()));
277 } 297 }
278 } catch (RuntimeException e) { 298 } catch (RuntimeException e) {
279 log.warn("Failed to decode feature type: {}", uriPath); 299 log.warn("Failed to decode feature type: {}", uriPath);
@@ -325,6 +345,25 @@ public class CoapTransportResource extends CoapResource { @@ -325,6 +345,25 @@ public class CoapTransportResource extends CoapResource {
325 } 345 }
326 } 346 }
327 347
  348 + private static class DeviceProvisionCallback implements TransportServiceCallback<ProvisionDeviceResponseMsg> {
  349 + private final CoapExchange exchange;
  350 +
  351 + DeviceProvisionCallback(CoapExchange exchange) {
  352 + this.exchange = exchange;
  353 + }
  354 +
  355 + @Override
  356 + public void onSuccess(TransportProtos.ProvisionDeviceResponseMsg msg) {
  357 + exchange.respond(JsonConverter.toJson(msg).toString());
  358 + }
  359 +
  360 + @Override
  361 + public void onError(Throwable e) {
  362 + log.warn("Failed to process request", e);
  363 + exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR);
  364 + }
  365 + }
  366 +
328 private static class CoapOkCallback implements TransportServiceCallback<Void> { 367 private static class CoapOkCallback implements TransportServiceCallback<Void> {
329 private final CoapExchange exchange; 368 private final CoapExchange exchange;
330 369
@@ -19,6 +19,7 @@ import org.eclipse.californium.core.coap.Request; @@ -19,6 +19,7 @@ import org.eclipse.californium.core.coap.Request;
19 import org.eclipse.californium.core.coap.Response; 19 import org.eclipse.californium.core.coap.Response;
20 import org.thingsboard.server.common.transport.adaptor.AdaptorException; 20 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
21 import org.thingsboard.server.gen.transport.TransportProtos; 21 import org.thingsboard.server.gen.transport.TransportProtos;
  22 +import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
22 import org.thingsboard.server.transport.coap.CoapTransportResource; 23 import org.thingsboard.server.transport.coap.CoapTransportResource;
23 24
24 import java.util.UUID; 25 import java.util.UUID;
@@ -45,4 +46,6 @@ public interface CoapTransportAdaptor { @@ -45,4 +46,6 @@ public interface CoapTransportAdaptor {
45 46
46 Response convertToPublish(CoapTransportResource.CoapSessionListener coapSessionListener, TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException; 47 Response convertToPublish(CoapTransportResource.CoapSessionListener coapSessionListener, TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException;
47 48
  49 + ProvisionDeviceRequestMsg convertToProvisionRequestMsg(UUID sessionId, Request inbound) throws AdaptorException;
  50 +
48 } 51 }
@@ -124,6 +124,16 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor { @@ -124,6 +124,16 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor {
124 } 124 }
125 125
126 @Override 126 @Override
  127 + public TransportProtos.ProvisionDeviceRequestMsg convertToProvisionRequestMsg(UUID sessionId, Request inbound) throws AdaptorException {
  128 + String payload = validatePayload(sessionId, inbound, false);
  129 + try {
  130 + return JsonConverter.convertToProvisionRequestMsg(payload);
  131 + } catch (IllegalStateException | JsonSyntaxException ex) {
  132 + throw new AdaptorException(ex);
  133 + }
  134 + }
  135 +
  136 + @Override
127 public Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.GetAttributeResponseMsg msg) throws AdaptorException { 137 public Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.GetAttributeResponseMsg msg) throws AdaptorException {
128 if (msg.getClientAttributeListCount() == 0 && msg.getSharedAttributeListCount() == 0) { 138 if (msg.getClientAttributeListCount() == 0 && msg.getSharedAttributeListCount() == 0) {
129 return new Response(CoAP.ResponseCode.NOT_FOUND); 139 return new Response(CoAP.ResponseCode.NOT_FOUND);
@@ -44,6 +44,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotif @@ -44,6 +44,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotif
44 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; 44 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto;
45 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; 45 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg;
46 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; 46 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg;
  47 +import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg;
47 import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto; 48 import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto;
48 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; 49 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
49 import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg; 50 import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg;
@@ -203,6 +204,14 @@ public class DeviceApiController { @@ -203,6 +204,14 @@ public class DeviceApiController {
203 return responseWriter; 204 return responseWriter;
204 } 205 }
205 206
  207 + @RequestMapping(value = "/provision", method = RequestMethod.POST)
  208 + public DeferredResult<ResponseEntity> provisionDevice(@RequestBody String json, HttpServletRequest httpRequest) {
  209 + DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>();
  210 + transportContext.getTransportService().process(JsonConverter.convertToProvisionRequestMsg(json),
  211 + new DeviceProvisionCallback(responseWriter));
  212 + return responseWriter;
  213 + }
  214 +
206 private static class DeviceAuthCallback implements TransportServiceCallback<ValidateDeviceCredentialsResponse> { 215 private static class DeviceAuthCallback implements TransportServiceCallback<ValidateDeviceCredentialsResponse> {
207 private final TransportContext transportContext; 216 private final TransportContext transportContext;
208 private final DeferredResult<ResponseEntity> responseWriter; 217 private final DeferredResult<ResponseEntity> responseWriter;
@@ -230,6 +239,25 @@ public class DeviceApiController { @@ -230,6 +239,25 @@ public class DeviceApiController {
230 } 239 }
231 } 240 }
232 241
  242 + private static class DeviceProvisionCallback implements TransportServiceCallback<ProvisionDeviceResponseMsg> {
  243 + private final DeferredResult<ResponseEntity> responseWriter;
  244 +
  245 + DeviceProvisionCallback(DeferredResult<ResponseEntity> responseWriter) {
  246 + this.responseWriter = responseWriter;
  247 + }
  248 +
  249 + @Override
  250 + public void onSuccess(ProvisionDeviceResponseMsg msg) {
  251 + responseWriter.setResult(new ResponseEntity<>(JsonConverter.toJson(msg).toString(), HttpStatus.OK));
  252 + }
  253 +
  254 + @Override
  255 + public void onError(Throwable e) {
  256 + log.warn("Failed to process request", e);
  257 + responseWriter.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR));
  258 + }
  259 + }
  260 +
233 private static class SessionCloseOnErrorCallback implements TransportServiceCallback<Void> { 261 private static class SessionCloseOnErrorCallback implements TransportServiceCallback<Void> {
234 private final TransportService transportService; 262 private final TransportService transportService;
235 private final SessionInfoProto sessionInfo; 263 private final SessionInfoProto sessionInfo;
@@ -154,7 +154,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @@ -154,7 +154,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
154 try { 154 try {
155 if (topicName.equals(MqttTopics.DEVICE_PROVISION_REQUEST_TOPIC)) { 155 if (topicName.equals(MqttTopics.DEVICE_PROVISION_REQUEST_TOPIC)) {
156 TransportProtos.ProvisionDeviceRequestMsg provisionRequestMsg = adaptor.convertToProvisionRequestMsg(deviceSessionCtx, mqttMsg); 156 TransportProtos.ProvisionDeviceRequestMsg provisionRequestMsg = adaptor.convertToProvisionRequestMsg(deviceSessionCtx, mqttMsg);
157 - transportService.process(deviceSessionCtx.getSessionInfo(), provisionRequestMsg, (TransportServiceCallback) new DeviceProvisionCallback(ctx, msgId, provisionRequestMsg)); 157 + transportService.process(provisionRequestMsg, new DeviceProvisionCallback(ctx, msgId, provisionRequestMsg));
158 log.trace("[{}][{}] Processing publish msg [{}][{}]!", sessionId, deviceSessionCtx.getDeviceId(), topicName, msgId); 158 log.trace("[{}][{}] Processing publish msg [{}][{}]!", sessionId, deviceSessionCtx.getDeviceId(), topicName, msgId);
159 } else { 159 } else {
160 throw new RuntimeException("Unsupported topic for provisioning requests!"); 160 throw new RuntimeException("Unsupported topic for provisioning requests!");
@@ -167,6 +167,10 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @@ -167,6 +167,10 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
167 case PINGREQ: 167 case PINGREQ:
168 ctx.writeAndFlush(new MqttMessage(new MqttFixedHeader(PINGRESP, false, AT_MOST_ONCE, false, 0))); 168 ctx.writeAndFlush(new MqttMessage(new MqttFixedHeader(PINGRESP, false, AT_MOST_ONCE, false, 0)));
169 break; 169 break;
  170 +// case SUBSCRIBE:
  171 +// deviceSessionCtx.setDeviceInfo(TransportDeviceInfo);
  172 +// processSubscribe(ctx, (MqttSubscribeMessage) msg);
  173 +// break;
170 case DISCONNECT: 174 case DISCONNECT:
171 ctx.close(); 175 ctx.close();
172 break; 176 break;
@@ -425,7 +429,6 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @@ -425,7 +429,6 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
425 log.info("[{}] Processing connect msg for client: {}!", sessionId, msg.payload().clientIdentifier()); 429 log.info("[{}] Processing connect msg for client: {}!", sessionId, msg.payload().clientIdentifier());
426 String userName = msg.payload().userName(); 430 String userName = msg.payload().userName();
427 if (DataConstants.PROVISION.equals(userName)) { 431 if (DataConstants.PROVISION.equals(userName)) {
428 - deviceSessionCtx.setDeviceInfo(new TransportDeviceInfo());  
429 deviceSessionCtx.setProvisionOnly(true); 432 deviceSessionCtx.setProvisionOnly(true);
430 ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED)); 433 ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED));
431 } else { 434 } else {
@@ -28,6 +28,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfo @@ -28,6 +28,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfo
28 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; 28 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
29 import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; 29 import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;
30 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; 30 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
  31 +import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg;
31 import org.thingsboard.server.gen.transport.TransportProtos.SessionEventMsg; 32 import org.thingsboard.server.gen.transport.TransportProtos.SessionEventMsg;
32 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; 33 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
33 import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg; 34 import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg;
@@ -58,6 +59,9 @@ public interface TransportService { @@ -58,6 +59,9 @@ public interface TransportService {
58 void process(GetOrCreateDeviceFromGatewayRequestMsg msg, 59 void process(GetOrCreateDeviceFromGatewayRequestMsg msg,
59 TransportServiceCallback<GetOrCreateDeviceFromGatewayResponse> callback); 60 TransportServiceCallback<GetOrCreateDeviceFromGatewayResponse> callback);
60 61
  62 + void process(ProvisionDeviceRequestMsg msg,
  63 + TransportServiceCallback<ProvisionDeviceResponseMsg> callback);
  64 +
61 void getDeviceProfile(DeviceProfileId deviceProfileId, TransportServiceCallback<DeviceProfile> callback); 65 void getDeviceProfile(DeviceProfileId deviceProfileId, TransportServiceCallback<DeviceProfile> callback);
62 66
63 void onProfileUpdate(DeviceProfile deviceProfile); 67 void onProfileUpdate(DeviceProfile deviceProfile);
@@ -84,8 +88,6 @@ public interface TransportService { @@ -84,8 +88,6 @@ public interface TransportService {
84 88
85 void process(SessionInfoProto sessionInfo, ClaimDeviceMsg msg, TransportServiceCallback<Void> callback); 89 void process(SessionInfoProto sessionInfo, ClaimDeviceMsg msg, TransportServiceCallback<Void> callback);
86 90
87 - void process(SessionInfoProto sessionInfo, ProvisionDeviceRequestMsg msg, TransportServiceCallback<Void> deviceProvisionCallback);  
88 -  
89 void registerAsyncSession(SessionInfoProto sessionInfo, SessionMsgListener listener); 91 void registerAsyncSession(SessionInfoProto sessionInfo, SessionMsgListener listener);
90 92
91 void registerSyncSession(SessionInfoProto sessionInfo, SessionMsgListener listener, long timeout); 93 void registerSyncSession(SessionInfoProto sessionInfo, SessionMsgListener listener, long timeout);
@@ -52,6 +52,8 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes @@ -52,6 +52,8 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes
52 import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; 52 import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
53 import org.thingsboard.server.common.transport.util.JsonUtils; 53 import org.thingsboard.server.common.transport.util.JsonUtils;
54 import org.thingsboard.server.gen.transport.TransportProtos; 54 import org.thingsboard.server.gen.transport.TransportProtos;
  55 +import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
  56 +import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg;
55 import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; 57 import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
56 import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; 58 import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
57 import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; 59 import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
@@ -333,6 +335,16 @@ public class DefaultTransportService implements TransportService { @@ -333,6 +335,16 @@ public class DefaultTransportService implements TransportService {
333 } 335 }
334 336
335 @Override 337 @Override
  338 + public void process(ProvisionDeviceRequestMsg requestMsg, TransportServiceCallback<ProvisionDeviceResponseMsg> callback) {
  339 + log.trace("Processing msg: {}", requestMsg);
  340 + TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setProvisionDeviceRequestMsg(requestMsg).build());
  341 + ListenableFuture<ProvisionDeviceResponseMsg> response = Futures.transform(transportApiRequestTemplate.send(protoMsg), tmp ->
  342 + tmp.getValue().getProvisionDeviceResponseMsg()
  343 + , MoreExecutors.directExecutor());
  344 + AsyncCallbackTemplate.withCallback(response, callback::onSuccess, callback::onError, transportCallbackExecutor);
  345 + }
  346 +
  347 + @Override
336 public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.SubscriptionInfoProto msg, TransportServiceCallback<Void> callback) { 348 public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.SubscriptionInfoProto msg, TransportServiceCallback<Void> callback) {
337 if (log.isTraceEnabled()) { 349 if (log.isTraceEnabled()) {
338 log.trace("[{}] Processing msg: {}", toSessionId(sessionInfo), msg); 350 log.trace("[{}] Processing msg: {}", toSessionId(sessionInfo), msg);
@@ -485,15 +497,6 @@ public class DefaultTransportService implements TransportService { @@ -485,15 +497,6 @@ public class DefaultTransportService implements TransportService {
485 } 497 }
486 498
487 @Override 499 @Override
488 - public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ProvisionDeviceRequestMsg msg, TransportServiceCallback<Void> callback) {  
489 - if (checkLimits(sessionInfo, msg, callback)) {  
490 - reportActivityInternal(sessionInfo);  
491 - sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo)  
492 - .setProvisionDevice(msg).build(), callback);  
493 - }  
494 - }  
495 -  
496 - @Override  
497 public void reportActivity(TransportProtos.SessionInfoProto sessionInfo) { 500 public void reportActivity(TransportProtos.SessionInfoProto sessionInfo) {
498 reportActivityInternal(sessionInfo); 501 reportActivityInternal(sessionInfo);
499 } 502 }
@@ -215,6 +215,6 @@ public interface DeviceDao extends Dao<Device> { @@ -215,6 +215,6 @@ public interface DeviceDao extends Dao<Device> {
215 */ 215 */
216 PageData<Device> findDevicesByTenantIdAndProfileId(UUID tenantId, UUID profileId, PageLink pageLink); 216 PageData<Device> findDevicesByTenantIdAndProfileId(UUID tenantId, UUID profileId, PageLink pageLink);
217 217
218 - Device findDeviceByTenantIdAndDeviceDataProvisionConfigurationPair(TenantId tenantId, String provisionDeviceKey, String provisionDeviceSecret); 218 + Optional<Device> findDeviceByProfileNameAndDeviceDataProvisionConfigurationPair(String profileName, String provisionDeviceKey, String provisionDeviceSecret);
219 219
220 } 220 }
@@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.page.PageData; @@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.page.PageData;
22 import org.thingsboard.server.common.data.page.PageLink; 22 import org.thingsboard.server.common.data.page.PageLink;
23 import org.thingsboard.server.dao.Dao; 23 import org.thingsboard.server.dao.Dao;
24 24
  25 +import java.util.Optional;
25 import java.util.UUID; 26 import java.util.UUID;
26 27
27 public interface DeviceProfileDao extends Dao<DeviceProfile> { 28 public interface DeviceProfileDao extends Dao<DeviceProfile> {
@@ -38,9 +39,7 @@ public interface DeviceProfileDao extends Dao<DeviceProfile> { @@ -38,9 +39,7 @@ public interface DeviceProfileDao extends Dao<DeviceProfile> {
38 39
39 DeviceProfileInfo findDefaultDeviceProfileInfo(TenantId tenantId); 40 DeviceProfileInfo findDefaultDeviceProfileInfo(TenantId tenantId);
40 41
41 - DeviceProfileInfo findProfileInfoByTenantIdAndProfileDataProvisionConfigurationPair(TenantId tenantId, String provisionDeviceKey, String provisionDeviceSecret);  
42 -  
43 - DeviceProfile findProfileByTenantIdAndProfileDataProvisionConfigurationPair(TenantId tenantId, String provisionDeviceKey, String provisionDeviceSecret); 42 + DeviceProfile findProfileByProfileNameAndProfileDataProvisionConfigurationPair(String profileName, String provisionDeviceKey, String provisionDeviceSecret);
44 43
45 DeviceProfile findByName(TenantId tenantId, String profileName); 44 DeviceProfile findByName(TenantId tenantId, String profileName);
46 } 45 }
@@ -20,9 +20,7 @@ import org.springframework.data.domain.Pageable; @@ -20,9 +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;  
24 import org.thingsboard.server.common.data.DeviceProfileInfo; 23 import org.thingsboard.server.common.data.DeviceProfileInfo;
25 -import org.thingsboard.server.common.data.DeviceProfileType;  
26 import org.thingsboard.server.dao.model.sql.DeviceProfileEntity; 24 import org.thingsboard.server.dao.model.sql.DeviceProfileEntity;
27 25
28 import java.util.UUID; 26 import java.util.UUID;
@@ -58,23 +56,14 @@ public interface DeviceProfileRepository extends PagingAndSortingRepository<Devi @@ -58,23 +56,14 @@ public interface DeviceProfileRepository extends PagingAndSortingRepository<Devi
58 56
59 DeviceProfileEntity findByTenantIdAndName(UUID id, String profileName); 57 DeviceProfileEntity findByTenantIdAndName(UUID id, String profileName);
60 58
61 - @Query(value = "SELECT d FROM DeviceProfileEntity d " +  
62 - "WHERE d.tenantId = :tenantId " +  
63 - "AND d.profileData::jsonb->>{'configuration', 'provisionDeviceKey'} = :provisionDeviceKey " +  
64 - "AND d.profileData::jsonb->>{'configuration', 'provisionDeviceSecret' = :provisionDeviceSecret}", 59 + @Query(value = "SELECT d.* FROM device_profile as d " +
  60 + "WHERE d.name = :profileName " +
  61 + "AND d.profile_data->'configuration'->>'provisionDeviceKey' IS NOT NULL " +
  62 + "AND d.profile_data->'configuration'->>'provisionDeviceSecret' IS NOT NULL " +
  63 + "AND d.profile_data->'configuration'->>'provisionDeviceKey' = :provisionDeviceKey " +
  64 + "AND d.profile_data->'configuration'->>'provisionDeviceSecret' = :provisionDeviceSecret",
65 nativeQuery = true) 65 nativeQuery = true)
66 - DeviceProfileEntity findProfileByTenantIdAndProfileDataProvisionConfigurationPair(@Param("tenantId") UUID tenantId,  
67 - @Param("provisionDeviceKey") String provisionDeviceKey,  
68 - @Param("provisionDeviceSecret") String provisionDeviceSecret);  
69 -  
70 - @Query(value = "SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.type, d.transportType) " +  
71 - " FROM DeviceProfileEntity d " +  
72 - "WHERE d.tenantId = :tenantId " +  
73 - "AND d.profileData::jsonb->>{'configuration', 'provisionDeviceKey'} = :provisionDeviceKey " +  
74 - "AND d.profileData::jsonb->>{'configuration', 'provisionDeviceSecret' = :provisionDeviceSecret}",  
75 - nativeQuery = true)  
76 - DeviceProfileInfo findProfileInfoByTenantIdAndProfileDataProvisionConfigurationPair(@Param("tenantId") UUID tenantId,  
77 - @Param("provisionDeviceKey") String provisionDeviceKey,  
78 - @Param("provisionDeviceSecret") String provisionDeviceSecret);  
79 - 66 + DeviceProfileEntity findProfileByProfileNameAndProfileDataProvisionConfigurationPair(@Param("profileName") String profileName,
  67 + @Param("provisionDeviceKey") String provisionDeviceKey,
  68 + @Param("provisionDeviceSecret") String provisionDeviceSecret);
80 } 69 }
@@ -20,10 +20,8 @@ import org.springframework.data.domain.Pageable; @@ -20,10 +20,8 @@ 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.DeviceProfileInfo;  
24 import org.thingsboard.server.dao.model.sql.DeviceEntity; 23 import org.thingsboard.server.dao.model.sql.DeviceEntity;
25 import org.thingsboard.server.dao.model.sql.DeviceInfoEntity; 24 import org.thingsboard.server.dao.model.sql.DeviceInfoEntity;
26 -import org.thingsboard.server.dao.model.sql.DeviceProfileEntity;  
27 25
28 import java.util.List; 26 import java.util.List;
29 import java.util.UUID; 27 import java.util.UUID;
@@ -171,12 +169,12 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit @@ -171,12 +169,12 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit
171 169
172 Long countByDeviceProfileId(UUID deviceProfileId); 170 Long countByDeviceProfileId(UUID deviceProfileId);
173 171
174 - @Query(value = "SELECT d FROM Device d " +  
175 - "WHERE d.tenant_id = :tenantId " +  
176 - "AND d.device_data::jsonb->>('configuration', 'provisionDeviceKey') = :provisionDeviceKey " +  
177 - "AND d.device_data::jsonb->>('configuration', 'provisionDeviceSecret') = :provisionDeviceSecret", 172 + @Query(value = "SELECT * FROM Device as d " +
  173 + "WHERE d.device_data->'configuration'->>'provisionDeviceKey' = :provisionDeviceKey " +
  174 + "AND d.device_data->'configuration'->>'provisionDeviceSecret' = :provisionDeviceSecret " +
  175 + "AND d.type = :profileName",
178 nativeQuery = true) 176 nativeQuery = true)
179 - DeviceEntity findDeviceByTenantIdAndDeviceDataProvisionConfigurationPair(@Param("tenantId") UUID tenantId,  
180 - @Param("provisionDeviceKey") String provisionDeviceKey,  
181 - @Param("provisionDeviceSecret") String provisionDeviceSecret); 177 + DeviceEntity findDeviceByProfileNameAndDeviceDataProvisionConfigurationPair(@Param("profileName") String profileName,
  178 + @Param("provisionDeviceKey") String provisionDeviceKey,
  179 + @Param("provisionDeviceSecret") String provisionDeviceSecret);
182 } 180 }
@@ -22,8 +22,6 @@ import org.springframework.stereotype.Component; @@ -22,8 +22,6 @@ import org.springframework.stereotype.Component;
22 import org.springframework.util.StringUtils; 22 import org.springframework.util.StringUtils;
23 import org.thingsboard.server.common.data.Device; 23 import org.thingsboard.server.common.data.Device;
24 import org.thingsboard.server.common.data.DeviceInfo; 24 import org.thingsboard.server.common.data.DeviceInfo;
25 -import org.thingsboard.server.common.data.DeviceProfile;  
26 -import org.thingsboard.server.common.data.DeviceProfileInfo;  
27 import org.thingsboard.server.common.data.EntitySubtype; 25 import org.thingsboard.server.common.data.EntitySubtype;
28 import org.thingsboard.server.common.data.EntityType; 26 import org.thingsboard.server.common.data.EntityType;
29 import org.thingsboard.server.common.data.id.TenantId; 27 import org.thingsboard.server.common.data.id.TenantId;
@@ -222,8 +220,8 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device> @@ -222,8 +220,8 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device>
222 } 220 }
223 221
224 @Override 222 @Override
225 - public Device findDeviceByTenantIdAndDeviceDataProvisionConfigurationPair(TenantId tenantId, String provisionDeviceKey, String provisionDeviceSecret) {  
226 - return DaoUtil.getData(deviceRepository.findDeviceByTenantIdAndDeviceDataProvisionConfigurationPair(tenantId.getId(), provisionDeviceKey, provisionDeviceSecret)); 223 + public Optional<Device> findDeviceByProfileNameAndDeviceDataProvisionConfigurationPair(String profileName, String provisionDeviceKey, String provisionDeviceSecret) {
  224 + return Optional.ofNullable(DaoUtil.getData(deviceRepository.findDeviceByProfileNameAndDeviceDataProvisionConfigurationPair(profileName, provisionDeviceKey, provisionDeviceSecret)));
227 } 225 }
228 226
229 private List<EntitySubtype> convertTenantDeviceTypesToDto(UUID tenantId, List<String> types) { 227 private List<EntitySubtype> convertTenantDeviceTypesToDto(UUID tenantId, List<String> types) {
@@ -29,6 +29,7 @@ import org.thingsboard.server.dao.model.sql.DeviceProfileEntity; @@ -29,6 +29,7 @@ import org.thingsboard.server.dao.model.sql.DeviceProfileEntity;
29 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; 29 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
30 30
31 import java.util.Objects; 31 import java.util.Objects;
  32 +import java.util.Optional;
32 import java.util.UUID; 33 import java.util.UUID;
33 34
34 @Component 35 @Component
@@ -81,13 +82,8 @@ public class JpaDeviceProfileDao extends JpaAbstractSearchTextDao<DeviceProfileE @@ -81,13 +82,8 @@ public class JpaDeviceProfileDao extends JpaAbstractSearchTextDao<DeviceProfileE
81 } 82 }
82 83
83 @Override 84 @Override
84 - public DeviceProfile findProfileByTenantIdAndProfileDataProvisionConfigurationPair(TenantId tenantId, String provisionDeviceKey, String provisionDeviceSecret) {  
85 - return DaoUtil.getData(deviceProfileRepository.findProfileByTenantIdAndProfileDataProvisionConfigurationPair(tenantId.getId(), provisionDeviceKey, provisionDeviceSecret));  
86 - }  
87 -  
88 - @Override  
89 - public DeviceProfileInfo findProfileInfoByTenantIdAndProfileDataProvisionConfigurationPair(TenantId tenantId, String provisionDeviceKey, String provisionDeviceSecret) {  
90 - return deviceProfileRepository.findProfileInfoByTenantIdAndProfileDataProvisionConfigurationPair(tenantId.getId(), provisionDeviceKey, provisionDeviceSecret); 85 + public DeviceProfile findProfileByProfileNameAndProfileDataProvisionConfigurationPair(String profileName, String provisionDeviceKey, String provisionDeviceSecret) {
  86 + return DaoUtil.getData(deviceProfileRepository.findProfileByProfileNameAndProfileDataProvisionConfigurationPair(profileName, provisionDeviceKey, provisionDeviceSecret));
91 } 87 }
92 88
93 @Override 89 @Override