Commit d14f6a4ddd4291e14b5d9d85ae9e95c1c9113166

Authored by Viacheslav Klimov
1 parent bd1cfa44

Refactor device bulk import

... ... @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
20 20 import com.fasterxml.jackson.databind.node.TextNode;
21 21 import lombok.SneakyThrows;
22 22 import org.apache.commons.collections.CollectionUtils;
  23 +import org.apache.commons.lang3.RandomStringUtils;
23 24 import org.apache.commons.lang3.StringUtils;
24 25 import org.springframework.stereotype.Service;
25 26 import org.thingsboard.common.util.JacksonUtil;
... ... @@ -31,6 +32,7 @@ import org.thingsboard.server.common.data.DeviceProfileType;
31 32 import org.thingsboard.server.common.data.DeviceTransportType;
32 33 import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
33 34 import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials;
  35 +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode;
34 36 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
35 37 import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
36 38 import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
... ... @@ -58,9 +60,9 @@ import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
58 60 import java.util.Collection;
59 61 import java.util.EnumSet;
60 62 import java.util.Map;
  63 +import java.util.Objects;
61 64 import java.util.Optional;
62 65 import java.util.Set;
63   -import java.util.stream.Stream;
64 66
65 67 @Service
66 68 @TbCoreComponent
... ... @@ -96,29 +98,21 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
96 98 device = existingDevice;
97 99 }
98 100
99   - DeviceCredentials deviceCredentials = createDeviceCredentials(fields);
100   - if (deviceCredentials.getCredentialsType() != null) {
101   - if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) {
102   - setUpLwM2mDeviceProfile(user.getTenantId(), device);
103   - }
104   - try {
105   - device = deviceService.saveDeviceWithCredentials(device, deviceCredentials);
106   - } catch (DeviceCredentialsValidationException e) {
107   - if (deviceCredentials.getId() == null) {
108   - device.setId(deviceCredentials.getDeviceId());
109   - importedEntityInfo.setRelatedError("Failed to create " + deviceCredentials.getCredentialsType() + " credentials: "
110   - + e.getMessage() + ". Falling back to access token creds");
111   - deviceService.createAccessTokenCredentials(device, null);
112   - } else {
113   - importedEntityInfo.setRelatedError("Failed to update credentials: " + e.getMessage());
114   - }
115   - }
116   - } else {
117   - device = deviceService.saveDevice(device);
  101 + DeviceCredentials deviceCredentials;
  102 + try {
  103 + deviceCredentials = createDeviceCredentials(fields);
  104 + deviceCredentialsService.formatCredentials(deviceCredentials);
  105 + } catch (Exception e) {
  106 + throw new DeviceCredentialsValidationException("Invalid device credentials: " + e.getMessage());
118 107 }
119 108
120   - importedEntityInfo.setEntity(device);
  109 + if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) {
  110 + setUpLwM2mDeviceProfile(user.getTenantId(), device);
  111 + }
  112 +
  113 + device = deviceService.saveDeviceWithCredentials(device, deviceCredentials);
121 114
  115 + importedEntityInfo.setEntity(device);
122 116 return importedEntityInfo;
123 117 }
124 118
... ... @@ -148,54 +142,79 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
148 142
149 143 @SneakyThrows
150 144 private DeviceCredentials createDeviceCredentials(Map<BulkImportColumnType, String> fields) {
151   - Set<BulkImportColumnType> columns = fields.keySet();
152   -
153 145 DeviceCredentials credentials = new DeviceCredentials();
154   -
155   - if (columns.contains(BulkImportColumnType.LWM2M_CLIENT_ENDPOINT)) {
  146 + if (fields.containsKey(BulkImportColumnType.LWM2M_CLIENT_ENDPOINT)) {
156 147 credentials.setCredentialsType(DeviceCredentialsType.LWM2M_CREDENTIALS);
157   - ObjectNode lwm2mCredentials = JacksonUtil.newObjectNode();
158   -
159   - ObjectNode client = JacksonUtil.newObjectNode();
160   - setValues(client, fields, Set.of(BulkImportColumnType.LWM2M_CLIENT_SECURITY_CONFIG_MODE,
161   - BulkImportColumnType.LWM2M_CLIENT_ENDPOINT, BulkImportColumnType.LWM2M_CLIENT_IDENTITY,
162   - BulkImportColumnType.LWM2M_CLIENT_KEY, BulkImportColumnType.LWM2M_CLIENT_CERT));
163   - LwM2MClientCredentials lwM2MClientCredentials = JacksonUtil.treeToValue(client, LwM2MClientCredentials.class);
164   - // so that only fields needed for specific type of lwM2MClientCredentials were saved in json
165   - lwm2mCredentials.set("client", JacksonUtil.valueToTree(lwM2MClientCredentials));
166   -
167   - ObjectNode bootstrapServer = JacksonUtil.newObjectNode();
168   - setValues(bootstrapServer, fields, Set.of(BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECURITY_MODE,
169   - BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_PUBLIC_KEY_OR_ID, BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECRET_KEY));
170   -
171   - ObjectNode lwm2mServer = JacksonUtil.newObjectNode();
172   - setValues(lwm2mServer, fields, Set.of(BulkImportColumnType.LWM2M_SERVER_SECURITY_MODE,
173   - BulkImportColumnType.LWM2M_SERVER_CLIENT_PUBLIC_KEY_OR_ID, BulkImportColumnType.LWM2M_SERVER_CLIENT_SECRET_KEY));
174   -
175   - ObjectNode bootstrap = JacksonUtil.newObjectNode();
176   - bootstrap.set("bootstrapServer", bootstrapServer);
177   - bootstrap.set("lwm2mServer", lwm2mServer);
178   - lwm2mCredentials.set("bootstrap", bootstrap);
179   -
180   - credentials.setCredentialsValue(lwm2mCredentials.toString());
181   - } else if (columns.contains(BulkImportColumnType.X509)) {
  148 + setUpLwm2mCredentials(fields, credentials);
  149 + } else if (fields.containsKey(BulkImportColumnType.X509)) {
182 150 credentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE);
183   - credentials.setCredentialsValue(fields.get(BulkImportColumnType.X509));
184   - } else if (CollectionUtils.containsAny(columns, EnumSet.of(BulkImportColumnType.MQTT_CLIENT_ID, BulkImportColumnType.MQTT_USER_NAME, BulkImportColumnType.MQTT_PASSWORD))) {
  151 + setUpX509CertificateCredentials(fields, credentials);
  152 + } else if (CollectionUtils.containsAny(fields.keySet(), EnumSet.of(BulkImportColumnType.MQTT_CLIENT_ID, BulkImportColumnType.MQTT_USER_NAME, BulkImportColumnType.MQTT_PASSWORD))) {
185 153 credentials.setCredentialsType(DeviceCredentialsType.MQTT_BASIC);
186   -
187   - BasicMqttCredentials basicMqttCredentials = new BasicMqttCredentials();
188   - basicMqttCredentials.setClientId(fields.get(BulkImportColumnType.MQTT_CLIENT_ID));
189   - basicMqttCredentials.setUserName(fields.get(BulkImportColumnType.MQTT_USER_NAME));
190   - basicMqttCredentials.setPassword(fields.get(BulkImportColumnType.MQTT_PASSWORD));
191   - credentials.setCredentialsValue(JacksonUtil.toString(basicMqttCredentials));
192   - } else if (columns.contains(BulkImportColumnType.ACCESS_TOKEN)) {
  154 + setUpBasicMqttCredentials(fields, credentials);
  155 + } else {
193 156 credentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
194   - credentials.setCredentialsId(fields.get(BulkImportColumnType.ACCESS_TOKEN));
  157 + setUpAccessTokenCredentials(fields, credentials);
195 158 }
196 159 return credentials;
197 160 }
198 161
  162 + private void setUpAccessTokenCredentials(Map<BulkImportColumnType, String> fields, DeviceCredentials credentials) {
  163 + credentials.setCredentialsValue(Optional.ofNullable(fields.get(BulkImportColumnType.ACCESS_TOKEN))
  164 + .orElseGet(() -> RandomStringUtils.randomAlphanumeric(20)));
  165 + }
  166 +
  167 + private void setUpBasicMqttCredentials(Map<BulkImportColumnType, String> fields, DeviceCredentials credentials) {
  168 + BasicMqttCredentials basicMqttCredentials = new BasicMqttCredentials();
  169 + basicMqttCredentials.setClientId(fields.get(BulkImportColumnType.MQTT_CLIENT_ID));
  170 + basicMqttCredentials.setUserName(fields.get(BulkImportColumnType.MQTT_USER_NAME));
  171 + basicMqttCredentials.setPassword(fields.get(BulkImportColumnType.MQTT_PASSWORD));
  172 + credentials.setCredentialsValue(JacksonUtil.toString(basicMqttCredentials));
  173 + }
  174 +
  175 + private void setUpX509CertificateCredentials(Map<BulkImportColumnType, String> fields, DeviceCredentials credentials) {
  176 + credentials.setCredentialsValue(fields.get(BulkImportColumnType.X509));
  177 + }
  178 +
  179 + private void setUpLwm2mCredentials(Map<BulkImportColumnType, String> fields, DeviceCredentials credentials) throws com.fasterxml.jackson.core.JsonProcessingException {
  180 + ObjectNode lwm2mCredentials = JacksonUtil.newObjectNode();
  181 +
  182 + Set.of(BulkImportColumnType.LWM2M_CLIENT_SECURITY_CONFIG_MODE, BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECURITY_MODE,
  183 + BulkImportColumnType.LWM2M_SERVER_SECURITY_MODE).stream()
  184 + .map(fields::get)
  185 + .filter(Objects::nonNull)
  186 + .forEach(securityMode -> {
  187 + try {
  188 + LwM2MSecurityMode.valueOf(securityMode);
  189 + } catch (IllegalArgumentException e) {
  190 + throw new DeviceCredentialsValidationException("Unknown LwM2M security mode: " + securityMode);
  191 + }
  192 + });
  193 +
  194 + ObjectNode client = JacksonUtil.newObjectNode();
  195 + setValues(client, fields, Set.of(BulkImportColumnType.LWM2M_CLIENT_SECURITY_CONFIG_MODE,
  196 + BulkImportColumnType.LWM2M_CLIENT_ENDPOINT, BulkImportColumnType.LWM2M_CLIENT_IDENTITY,
  197 + BulkImportColumnType.LWM2M_CLIENT_KEY, BulkImportColumnType.LWM2M_CLIENT_CERT));
  198 + LwM2MClientCredentials lwM2MClientCredentials = JacksonUtil.treeToValue(client, LwM2MClientCredentials.class);
  199 + // so that only fields needed for specific type of lwM2MClientCredentials were saved in json
  200 + lwm2mCredentials.set("client", JacksonUtil.valueToTree(lwM2MClientCredentials));
  201 +
  202 + ObjectNode bootstrapServer = JacksonUtil.newObjectNode();
  203 + setValues(bootstrapServer, fields, Set.of(BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECURITY_MODE,
  204 + BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_PUBLIC_KEY_OR_ID, BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECRET_KEY));
  205 +
  206 + ObjectNode lwm2mServer = JacksonUtil.newObjectNode();
  207 + setValues(lwm2mServer, fields, Set.of(BulkImportColumnType.LWM2M_SERVER_SECURITY_MODE,
  208 + BulkImportColumnType.LWM2M_SERVER_CLIENT_PUBLIC_KEY_OR_ID, BulkImportColumnType.LWM2M_SERVER_CLIENT_SECRET_KEY));
  209 +
  210 + ObjectNode bootstrap = JacksonUtil.newObjectNode();
  211 + bootstrap.set("bootstrapServer", bootstrapServer);
  212 + bootstrap.set("lwm2mServer", lwm2mServer);
  213 + lwm2mCredentials.set("bootstrap", bootstrap);
  214 +
  215 + credentials.setCredentialsValue(lwm2mCredentials.toString());
  216 + }
  217 +
199 218 private void setUpLwM2mDeviceProfile(TenantId tenantId, Device device) {
200 219 DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileByName(tenantId, device.getType());
201 220 if (deviceProfile != null) {
... ...
... ... @@ -29,5 +29,7 @@ public interface DeviceCredentialsService {
29 29
30 30 DeviceCredentials createDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials);
31 31
  32 + void formatCredentials(DeviceCredentials deviceCredentials);
  33 +
32 34 void deleteDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials);
33 35 }
... ...
... ... @@ -56,8 +56,6 @@ public interface DeviceService {
56 56
57 57 Device saveDevice(ProvisionRequest provisionRequest, DeviceProfile profile);
58 58
59   - void createAccessTokenCredentials(Device device, String accessToken);
60   -
61 59 Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, CustomerId customerId);
62 60
63 61 Device unassignDeviceFromCustomer(TenantId tenantId, DeviceId deviceId);
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.server.common.data.device.credentials.lwm2m;
17 17
18 18 import com.fasterxml.jackson.annotation.JsonIgnore;
  19 +import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
19 20 import com.fasterxml.jackson.annotation.JsonSubTypes;
20 21 import com.fasterxml.jackson.annotation.JsonTypeInfo;
21 22
... ... @@ -28,6 +29,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
28 29 @JsonSubTypes.Type(value = RPKClientCredentials.class, name = "RPK"),
29 30 @JsonSubTypes.Type(value = X509ClientCredentials.class, name = "X509")
30 31 })
  32 +@JsonIgnoreProperties(ignoreUnknown = true)
31 33 public interface LwM2MClientCredentials {
32 34
33 35 @JsonIgnore
... ...
... ... @@ -81,20 +81,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen
81 81 }
82 82
83 83 private DeviceCredentials saveOrUpdate(TenantId tenantId, DeviceCredentials deviceCredentials) {
84   - if (deviceCredentials.getCredentialsType() == null) {
85   - throw new DataValidationException("Device credentials type should be specified");
86   - }
87   - switch (deviceCredentials.getCredentialsType()) {
88   - case X509_CERTIFICATE:
89   - formatCertData(deviceCredentials);
90   - break;
91   - case MQTT_BASIC:
92   - formatSimpleMqttCredentials(deviceCredentials);
93   - break;
94   - case LWM2M_CREDENTIALS:
95   - formatSimpleLwm2mCredentials(deviceCredentials);
96   - break;
97   - }
  84 + formatCredentials(deviceCredentials);
98 85 log.trace("Executing updateDeviceCredentials [{}]", deviceCredentials);
99 86 credentialsValidator.validate(deviceCredentials, id -> tenantId);
100 87 try {
... ... @@ -110,6 +97,21 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen
110 97 }
111 98 }
112 99
  100 + @Override
  101 + public void formatCredentials(DeviceCredentials deviceCredentials) {
  102 + switch (deviceCredentials.getCredentialsType()) {
  103 + case X509_CERTIFICATE:
  104 + formatCertData(deviceCredentials);
  105 + break;
  106 + case MQTT_BASIC:
  107 + formatSimpleMqttCredentials(deviceCredentials);
  108 + break;
  109 + case LWM2M_CREDENTIALS:
  110 + formatSimpleLwm2mCredentials(deviceCredentials);
  111 + break;
  112 + }
  113 + }
  114 +
113 115 private void formatSimpleMqttCredentials(DeviceCredentials deviceCredentials) {
114 116 BasicMqttCredentials mqttCredentials;
115 117 try {
... ...
... ... @@ -238,20 +238,15 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
238 238 private Device doSaveDevice(Device device, String accessToken, boolean doValidate) {
239 239 Device savedDevice = this.saveDeviceWithoutCredentials(device, doValidate);
240 240 if (device.getId() == null) {
241   - createAccessTokenCredentials(savedDevice, accessToken);
  241 + DeviceCredentials deviceCredentials = new DeviceCredentials();
  242 + deviceCredentials.setDeviceId(new DeviceId(savedDevice.getUuidId()));
  243 + deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
  244 + deviceCredentials.setCredentialsId(!StringUtils.isEmpty(accessToken) ? accessToken : RandomStringUtils.randomAlphanumeric(20));
  245 + deviceCredentialsService.createDeviceCredentials(savedDevice.getTenantId(), deviceCredentials);
242 246 }
243 247 return savedDevice;
244 248 }
245 249
246   - @Override
247   - public void createAccessTokenCredentials(Device device, String accessToken) {
248   - DeviceCredentials deviceCredentials = new DeviceCredentials();
249   - deviceCredentials.setDeviceId(new DeviceId(device.getUuidId()));
250   - deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
251   - deviceCredentials.setCredentialsId(!StringUtils.isEmpty(accessToken) ? accessToken : RandomStringUtils.randomAlphanumeric(20));
252   - deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials);
253   - }
254   -
255 250 private Device saveDeviceWithoutCredentials(Device device, boolean doValidate) {
256 251 log.trace("Executing saveDevice [{}]", device);
257 252 if (doValidate) {
... ...