Commit 350581028021897cf1a51ad6f5bcc2b81f5cc71d

Authored by Viacheslav Klimov
1 parent 41e57249

Bulk import device credentials handling refactoring

@@ -18,8 +18,6 @@ package org.thingsboard.server.service.device; @@ -18,8 +18,6 @@ package org.thingsboard.server.service.device;
18 import com.fasterxml.jackson.databind.node.BooleanNode; 18 import com.fasterxml.jackson.databind.node.BooleanNode;
19 import com.fasterxml.jackson.databind.node.ObjectNode; 19 import com.fasterxml.jackson.databind.node.ObjectNode;
20 import com.fasterxml.jackson.databind.node.TextNode; 20 import com.fasterxml.jackson.databind.node.TextNode;
21 -import com.google.gson.JsonObject;  
22 -import com.google.gson.JsonPrimitive;  
23 import lombok.SneakyThrows; 21 import lombok.SneakyThrows;
24 import org.apache.commons.collections.CollectionUtils; 22 import org.apache.commons.collections.CollectionUtils;
25 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
@@ -39,10 +37,10 @@ import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTrans @@ -39,10 +37,10 @@ import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTrans
39 import org.thingsboard.server.common.data.id.TenantId; 37 import org.thingsboard.server.common.data.id.TenantId;
40 import org.thingsboard.server.common.data.security.DeviceCredentials; 38 import org.thingsboard.server.common.data.security.DeviceCredentials;
41 import org.thingsboard.server.common.data.security.DeviceCredentialsType; 39 import org.thingsboard.server.common.data.security.DeviceCredentialsType;
42 -import org.thingsboard.server.common.transport.adaptor.JsonConverter;  
43 import org.thingsboard.server.dao.device.DeviceCredentialsService; 40 import org.thingsboard.server.dao.device.DeviceCredentialsService;
44 import org.thingsboard.server.dao.device.DeviceProfileService; 41 import org.thingsboard.server.dao.device.DeviceProfileService;
45 import org.thingsboard.server.dao.device.DeviceService; 42 import org.thingsboard.server.dao.device.DeviceService;
  43 +import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException;
46 import org.thingsboard.server.dao.tenant.TbTenantProfileCache; 44 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
47 import org.thingsboard.server.queue.util.TbCoreComponent; 45 import org.thingsboard.server.queue.util.TbCoreComponent;
48 import org.thingsboard.server.service.action.EntityActionService; 46 import org.thingsboard.server.service.action.EntityActionService;
@@ -63,8 +61,6 @@ import java.util.Set; @@ -63,8 +61,6 @@ import java.util.Set;
63 import java.util.stream.Collectors; 61 import java.util.stream.Collectors;
64 import java.util.stream.Stream; 62 import java.util.stream.Stream;
65 63
66 -import static org.thingsboard.server.dao.service.Validator.validateId;  
67 -  
68 @Service 64 @Service
69 @TbCoreComponent 65 @TbCoreComponent
70 public class DeviceBulkImportService extends AbstractBulkImportService<Device> { 66 public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
@@ -104,7 +100,18 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> { @@ -104,7 +100,18 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
104 if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) { 100 if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) {
105 setUpLwM2mDeviceProfile(user.getTenantId(), device); 101 setUpLwM2mDeviceProfile(user.getTenantId(), device);
106 } 102 }
107 - device = deviceService.saveDeviceWithCredentials(device, deviceCredentials); 103 + try {
  104 + device = deviceService.saveDeviceWithCredentials(device, deviceCredentials);
  105 + } catch (DeviceCredentialsValidationException e) {
  106 + if (deviceCredentials.getId() == null) {
  107 + device.setId(deviceCredentials.getDeviceId());
  108 + importedEntityInfo.setRelatedError("Failed to create " + deviceCredentials.getCredentialsType() + " credentials: "
  109 + + e.getMessage() + ". Falling back to access token creds");
  110 + deviceService.createAccessTokenCredentials(device, null);
  111 + } else {
  112 + importedEntityInfo.setRelatedError("Failed to update credentials: " + e.getMessage());
  113 + }
  114 + }
108 } else { 115 } else {
109 device = deviceService.saveDevice(device); 116 device = deviceService.saveDevice(device);
110 } 117 }
@@ -80,6 +80,10 @@ public abstract class AbstractBulkImportService<E extends BaseData<? extends Ent @@ -80,6 +80,10 @@ public abstract class AbstractBulkImportService<E extends BaseData<? extends Ent
80 80
81 saveKvs(user, entity, entityData); 81 saveKvs(user, entity, entityData);
82 82
  83 + if (importedEntityInfo.getRelatedError() != null) {
  84 + throw new RuntimeException(importedEntityInfo.getRelatedError());
  85 + }
  86 +
83 if (importedEntityInfo.isUpdated()) { 87 if (importedEntityInfo.isUpdated()) {
84 result.setUpdated(result.getUpdated() + 1); 88 result.setUpdated(result.getUpdated() + 1);
85 } else { 89 } else {
@@ -22,4 +22,5 @@ public class ImportedEntityInfo<E> { @@ -22,4 +22,5 @@ public class ImportedEntityInfo<E> {
22 private E entity; 22 private E entity;
23 private boolean isUpdated; 23 private boolean isUpdated;
24 private E oldEntity; 24 private E oldEntity;
  25 + private String relatedError;
25 } 26 }
@@ -54,6 +54,8 @@ public interface DeviceService { @@ -54,6 +54,8 @@ public interface DeviceService {
54 54
55 Device saveDeviceWithCredentials(Device device, DeviceCredentials deviceCredentials); 55 Device saveDeviceWithCredentials(Device device, DeviceCredentials deviceCredentials);
56 56
  57 + void createAccessTokenCredentials(Device device, String accessToken);
  58 +
57 Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, CustomerId customerId); 59 Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, CustomerId customerId);
58 60
59 Device unassignDeviceFromCustomer(TenantId tenantId, DeviceId deviceId); 61 Device unassignDeviceFromCustomer(TenantId tenantId, DeviceId deviceId);
@@ -15,7 +15,6 @@ @@ -15,7 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.common.transport.adaptor; 16 package org.thingsboard.server.common.transport.adaptor;
17 17
18 -import com.fasterxml.jackson.databind.JsonNode;  
19 import com.google.gson.Gson; 18 import com.google.gson.Gson;
20 import com.google.gson.JsonArray; 19 import com.google.gson.JsonArray;
21 import com.google.gson.JsonElement; 20 import com.google.gson.JsonElement;
@@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials; @@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials;
37 import org.thingsboard.server.common.msg.EncryptionUtil; 37 import org.thingsboard.server.common.msg.EncryptionUtil;
38 import org.thingsboard.server.dao.entity.AbstractEntityService; 38 import org.thingsboard.server.dao.entity.AbstractEntityService;
39 import org.thingsboard.server.dao.exception.DataValidationException; 39 import org.thingsboard.server.dao.exception.DataValidationException;
  40 +import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException;
40 import org.thingsboard.server.dao.service.DataValidator; 41 import org.thingsboard.server.dao.service.DataValidator;
41 42
42 import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CREDENTIALS_CACHE; 43 import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CREDENTIALS_CACHE;
@@ -117,10 +118,10 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen @@ -117,10 +118,10 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen
117 throw new IllegalArgumentException(); 118 throw new IllegalArgumentException();
118 } 119 }
119 } catch (IllegalArgumentException e) { 120 } catch (IllegalArgumentException e) {
120 - throw new DataValidationException("Invalid credentials body for simple mqtt credentials!"); 121 + throw new DeviceCredentialsValidationException("Invalid credentials body for simple mqtt credentials!");
121 } 122 }
122 if (StringUtils.isEmpty(mqttCredentials.getClientId()) && StringUtils.isEmpty(mqttCredentials.getUserName())) { 123 if (StringUtils.isEmpty(mqttCredentials.getClientId()) && StringUtils.isEmpty(mqttCredentials.getUserName())) {
123 - throw new DataValidationException("Both mqtt client id and user name are empty!"); 124 + throw new DeviceCredentialsValidationException("Both mqtt client id and user name are empty!");
124 } 125 }
125 if (StringUtils.isEmpty(mqttCredentials.getClientId())) { 126 if (StringUtils.isEmpty(mqttCredentials.getClientId())) {
126 deviceCredentials.setCredentialsId(mqttCredentials.getUserName()); 127 deviceCredentials.setCredentialsId(mqttCredentials.getUserName());
@@ -155,7 +156,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen @@ -155,7 +156,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen
155 throw new IllegalArgumentException(); 156 throw new IllegalArgumentException();
156 } 157 }
157 } catch (IllegalArgumentException e) { 158 } catch (IllegalArgumentException e) {
158 - throw new DataValidationException("Invalid credentials body for LwM2M credentials!"); 159 + throw new DeviceCredentialsValidationException("Invalid credentials body for LwM2M credentials!");
159 } 160 }
160 161
161 String credentialsId = null; 162 String credentialsId = null;
@@ -183,7 +184,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen @@ -183,7 +184,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen
183 break; 184 break;
184 } 185 }
185 if (credentialsId == null) { 186 if (credentialsId == null) {
186 - throw new DataValidationException("Invalid credentials body for LwM2M credentials!"); 187 + throw new DeviceCredentialsValidationException("Invalid credentials body for LwM2M credentials!");
187 } 188 }
188 deviceCredentials.setCredentialsId(credentialsId); 189 deviceCredentials.setCredentialsId(credentialsId);
189 } 190 }
@@ -201,38 +202,38 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen @@ -201,38 +202,38 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen
201 @Override 202 @Override
202 protected void validateCreate(TenantId tenantId, DeviceCredentials deviceCredentials) { 203 protected void validateCreate(TenantId tenantId, DeviceCredentials deviceCredentials) {
203 if (deviceCredentialsDao.findByDeviceId(tenantId, deviceCredentials.getDeviceId().getId()) != null) { 204 if (deviceCredentialsDao.findByDeviceId(tenantId, deviceCredentials.getDeviceId().getId()) != null) {
204 - throw new DataValidationException("Credentials for this device are already specified!"); 205 + throw new DeviceCredentialsValidationException("Credentials for this device are already specified!");
205 } 206 }
206 if (deviceCredentialsDao.findByCredentialsId(tenantId, deviceCredentials.getCredentialsId()) != null) { 207 if (deviceCredentialsDao.findByCredentialsId(tenantId, deviceCredentials.getCredentialsId()) != null) {
207 - throw new DataValidationException("Device credentials are already assigned to another device!"); 208 + throw new DeviceCredentialsValidationException("Device credentials are already assigned to another device!");
208 } 209 }
209 } 210 }
210 211
211 @Override 212 @Override
212 protected void validateUpdate(TenantId tenantId, DeviceCredentials deviceCredentials) { 213 protected void validateUpdate(TenantId tenantId, DeviceCredentials deviceCredentials) {
213 if (deviceCredentialsDao.findById(tenantId, deviceCredentials.getUuidId()) == null) { 214 if (deviceCredentialsDao.findById(tenantId, deviceCredentials.getUuidId()) == null) {
214 - throw new DataValidationException("Unable to update non-existent device credentials!"); 215 + throw new DeviceCredentialsValidationException("Unable to update non-existent device credentials!");
215 } 216 }
216 DeviceCredentials existingCredentials = deviceCredentialsDao.findByCredentialsId(tenantId, deviceCredentials.getCredentialsId()); 217 DeviceCredentials existingCredentials = deviceCredentialsDao.findByCredentialsId(tenantId, deviceCredentials.getCredentialsId());
217 if (existingCredentials != null && !existingCredentials.getId().equals(deviceCredentials.getId())) { 218 if (existingCredentials != null && !existingCredentials.getId().equals(deviceCredentials.getId())) {
218 - throw new DataValidationException("Device credentials are already assigned to another device!"); 219 + throw new DeviceCredentialsValidationException("Device credentials are already assigned to another device!");
219 } 220 }
220 } 221 }
221 222
222 @Override 223 @Override
223 protected void validateDataImpl(TenantId tenantId, DeviceCredentials deviceCredentials) { 224 protected void validateDataImpl(TenantId tenantId, DeviceCredentials deviceCredentials) {
224 if (deviceCredentials.getDeviceId() == null) { 225 if (deviceCredentials.getDeviceId() == null) {
225 - throw new DataValidationException("Device credentials should be assigned to device!"); 226 + throw new DeviceCredentialsValidationException("Device credentials should be assigned to device!");
226 } 227 }
227 if (deviceCredentials.getCredentialsType() == null) { 228 if (deviceCredentials.getCredentialsType() == null) {
228 - throw new DataValidationException("Device credentials type should be specified!"); 229 + throw new DeviceCredentialsValidationException("Device credentials type should be specified!");
229 } 230 }
230 if (StringUtils.isEmpty(deviceCredentials.getCredentialsId())) { 231 if (StringUtils.isEmpty(deviceCredentials.getCredentialsId())) {
231 - throw new DataValidationException("Device credentials id should be specified!"); 232 + throw new DeviceCredentialsValidationException("Device credentials id should be specified!");
232 } 233 }
233 Device device = deviceService.findDeviceById(tenantId, deviceCredentials.getDeviceId()); 234 Device device = deviceService.findDeviceById(tenantId, deviceCredentials.getDeviceId());
234 if (device == null) { 235 if (device == null) {
235 - throw new DataValidationException("Can't assign device credentials to non-existent device!"); 236 + throw new DeviceCredentialsValidationException("Can't assign device credentials to non-existent device!");
236 } 237 }
237 } 238 }
238 }; 239 };
@@ -230,15 +230,20 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -230,15 +230,20 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
230 private Device doSaveDevice(Device device, String accessToken, boolean doValidate) { 230 private Device doSaveDevice(Device device, String accessToken, boolean doValidate) {
231 Device savedDevice = this.saveDeviceWithoutCredentials(device, doValidate); 231 Device savedDevice = this.saveDeviceWithoutCredentials(device, doValidate);
232 if (device.getId() == null) { 232 if (device.getId() == null) {
233 - DeviceCredentials deviceCredentials = new DeviceCredentials();  
234 - deviceCredentials.setDeviceId(new DeviceId(savedDevice.getUuidId()));  
235 - deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);  
236 - deviceCredentials.setCredentialsId(!StringUtils.isEmpty(accessToken) ? accessToken : RandomStringUtils.randomAlphanumeric(20));  
237 - deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials); 233 + createAccessTokenCredentials(savedDevice, accessToken);
238 } 234 }
239 return savedDevice; 235 return savedDevice;
240 } 236 }
241 237
  238 + @Override
  239 + public void createAccessTokenCredentials(Device device, String accessToken) {
  240 + DeviceCredentials deviceCredentials = new DeviceCredentials();
  241 + deviceCredentials.setDeviceId(new DeviceId(device.getUuidId()));
  242 + deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
  243 + deviceCredentials.setCredentialsId(!StringUtils.isEmpty(accessToken) ? accessToken : RandomStringUtils.randomAlphanumeric(20));
  244 + deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials);
  245 + }
  246 +
242 private Device saveDeviceWithoutCredentials(Device device, boolean doValidate) { 247 private Device saveDeviceWithoutCredentials(Device device, boolean doValidate) {
243 log.trace("Executing saveDevice [{}]", device); 248 log.trace("Executing saveDevice [{}]", device);
244 if (doValidate) { 249 if (doValidate) {
  1 +/**
  2 + * Copyright © 2016-2021 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.dao.exception;
  17 +
  18 +public class DeviceCredentialsValidationException extends DataValidationException {
  19 + public DeviceCredentialsValidationException(String message) {
  20 + super(message);
  21 + }
  22 +}