Commit 38f6e314b1000c8c7d8a1b58fd3a2f2aa8ba1107

Authored by Viacheslav Klimov
1 parent 5dc3d075

Refactor

@@ -26,6 +26,7 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache; @@ -26,6 +26,7 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
26 import org.thingsboard.server.queue.util.TbCoreComponent; 26 import org.thingsboard.server.queue.util.TbCoreComponent;
27 import org.thingsboard.server.service.action.EntityActionService; 27 import org.thingsboard.server.service.action.EntityActionService;
28 import org.thingsboard.server.service.importing.AbstractBulkImportService; 28 import org.thingsboard.server.service.importing.AbstractBulkImportService;
  29 +import org.thingsboard.server.service.importing.BulkImportColumnType;
29 import org.thingsboard.server.service.importing.BulkImportRequest; 30 import org.thingsboard.server.service.importing.BulkImportRequest;
30 import org.thingsboard.server.service.importing.ImportedEntityInfo; 31 import org.thingsboard.server.service.importing.ImportedEntityInfo;
31 import org.thingsboard.server.service.security.AccessValidator; 32 import org.thingsboard.server.service.security.AccessValidator;
@@ -49,12 +50,12 @@ public class AssetBulkImportService extends AbstractBulkImportService<Asset> { @@ -49,12 +50,12 @@ public class AssetBulkImportService extends AbstractBulkImportService<Asset> {
49 } 50 }
50 51
51 @Override 52 @Override
52 - protected ImportedEntityInfo<Asset> saveEntity(BulkImportRequest importRequest, Map<BulkImportRequest.ColumnMapping, String> entityData, SecurityUser user) { 53 + protected ImportedEntityInfo<Asset> saveEntity(BulkImportRequest importRequest, Map<BulkImportColumnType, String> fields, SecurityUser user) {
53 ImportedEntityInfo<Asset> importedEntityInfo = new ImportedEntityInfo<>(); 54 ImportedEntityInfo<Asset> importedEntityInfo = new ImportedEntityInfo<>();
54 55
55 Asset asset = new Asset(); 56 Asset asset = new Asset();
56 asset.setTenantId(user.getTenantId()); 57 asset.setTenantId(user.getTenantId());
57 - setAssetFields(asset, entityData); 58 + setAssetFields(asset, fields);
58 59
59 Asset existingAsset = assetService.findAssetByTenantIdAndName(user.getTenantId(), asset.getName()); 60 Asset existingAsset = assetService.findAssetByTenantIdAndName(user.getTenantId(), asset.getName());
60 if (existingAsset != null && importRequest.getMapping().getUpdate()) { 61 if (existingAsset != null && importRequest.getMapping().getUpdate()) {
@@ -69,10 +70,10 @@ public class AssetBulkImportService extends AbstractBulkImportService<Asset> { @@ -69,10 +70,10 @@ public class AssetBulkImportService extends AbstractBulkImportService<Asset> {
69 return importedEntityInfo; 70 return importedEntityInfo;
70 } 71 }
71 72
72 - private void setAssetFields(Asset asset, Map<BulkImportRequest.ColumnMapping, String> data) { 73 + private void setAssetFields(Asset asset, Map<BulkImportColumnType, String> fields) {
73 ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(asset.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); 74 ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(asset.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode);
74 - data.forEach((columnMapping, value) -> {  
75 - switch (columnMapping.getType()) { 75 + fields.forEach((columnType, value) -> {
  76 + switch (columnType) {
76 case NAME: 77 case NAME:
77 asset.setName(value); 78 asset.setName(value);
78 break; 79 break;
@@ -58,7 +58,6 @@ import java.util.EnumSet; @@ -58,7 +58,6 @@ import java.util.EnumSet;
58 import java.util.Map; 58 import java.util.Map;
59 import java.util.Optional; 59 import java.util.Optional;
60 import java.util.Set; 60 import java.util.Set;
61 -import java.util.stream.Collectors;  
62 import java.util.stream.Stream; 61 import java.util.stream.Stream;
63 62
64 @Service 63 @Service
@@ -80,12 +79,12 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> { @@ -80,12 +79,12 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
80 } 79 }
81 80
82 @Override 81 @Override
83 - protected ImportedEntityInfo<Device> saveEntity(BulkImportRequest importRequest, Map<BulkImportRequest.ColumnMapping, String> entityData, SecurityUser user) { 82 + protected ImportedEntityInfo<Device> saveEntity(BulkImportRequest importRequest, Map<BulkImportColumnType, String> fields, SecurityUser user) {
84 ImportedEntityInfo<Device> importedEntityInfo = new ImportedEntityInfo<>(); 83 ImportedEntityInfo<Device> importedEntityInfo = new ImportedEntityInfo<>();
85 84
86 Device device = new Device(); 85 Device device = new Device();
87 device.setTenantId(user.getTenantId()); 86 device.setTenantId(user.getTenantId());
88 - setDeviceFields(device, entityData); 87 + setDeviceFields(device, fields);
89 88
90 Device existingDevice = deviceService.findDeviceByTenantIdAndName(user.getTenantId(), device.getName()); 89 Device existingDevice = deviceService.findDeviceByTenantIdAndName(user.getTenantId(), device.getName());
91 if (existingDevice != null && importRequest.getMapping().getUpdate()) { 90 if (existingDevice != null && importRequest.getMapping().getUpdate()) {
@@ -95,7 +94,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> { @@ -95,7 +94,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
95 device = existingDevice; 94 device = existingDevice;
96 } 95 }
97 96
98 - DeviceCredentials deviceCredentials = createDeviceCredentials(entityData); 97 + DeviceCredentials deviceCredentials = createDeviceCredentials(fields);
99 if (deviceCredentials.getCredentialsType() != null) { 98 if (deviceCredentials.getCredentialsType() != null) {
100 if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) { 99 if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) {
101 setUpLwM2mDeviceProfile(user.getTenantId(), device); 100 setUpLwM2mDeviceProfile(user.getTenantId(), device);
@@ -121,10 +120,10 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> { @@ -121,10 +120,10 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
121 return importedEntityInfo; 120 return importedEntityInfo;
122 } 121 }
123 122
124 - private void setDeviceFields(Device device, Map<BulkImportRequest.ColumnMapping, String> data) { 123 + private void setDeviceFields(Device device, Map<BulkImportColumnType, String> fields) {
125 ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(device.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); 124 ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(device.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode);
126 - data.forEach((columnMapping, value) -> {  
127 - switch (columnMapping.getType()) { 125 + fields.forEach((columnType, value) -> {
  126 + switch (columnType) {
128 case NAME: 127 case NAME:
129 device.setName(value); 128 device.setName(value);
130 break; 129 break;
@@ -146,25 +145,25 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> { @@ -146,25 +145,25 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
146 } 145 }
147 146
148 @SneakyThrows 147 @SneakyThrows
149 - private DeviceCredentials createDeviceCredentials(Map<BulkImportRequest.ColumnMapping, String> data) {  
150 - Set<BulkImportColumnType> columns = data.keySet().stream().map(BulkImportRequest.ColumnMapping::getType).collect(Collectors.toSet()); 148 + private DeviceCredentials createDeviceCredentials(Map<BulkImportColumnType, String> fields) {
  149 + Set<BulkImportColumnType> columns = fields.keySet();
151 150
152 DeviceCredentials credentials = new DeviceCredentials(); 151 DeviceCredentials credentials = new DeviceCredentials();
153 152
154 if (columns.contains(BulkImportColumnType.ACCESS_TOKEN)) { 153 if (columns.contains(BulkImportColumnType.ACCESS_TOKEN)) {
155 credentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); 154 credentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
156 - credentials.setCredentialsId(getByColumnType(BulkImportColumnType.ACCESS_TOKEN, data)); 155 + credentials.setCredentialsId(fields.get(BulkImportColumnType.ACCESS_TOKEN));
157 } else if (CollectionUtils.containsAny(columns, EnumSet.of(BulkImportColumnType.MQTT_CLIENT_ID, BulkImportColumnType.MQTT_USER_NAME, BulkImportColumnType.MQTT_PASSWORD))) { 156 } else if (CollectionUtils.containsAny(columns, EnumSet.of(BulkImportColumnType.MQTT_CLIENT_ID, BulkImportColumnType.MQTT_USER_NAME, BulkImportColumnType.MQTT_PASSWORD))) {
158 credentials.setCredentialsType(DeviceCredentialsType.MQTT_BASIC); 157 credentials.setCredentialsType(DeviceCredentialsType.MQTT_BASIC);
159 158
160 BasicMqttCredentials basicMqttCredentials = new BasicMqttCredentials(); 159 BasicMqttCredentials basicMqttCredentials = new BasicMqttCredentials();
161 - basicMqttCredentials.setClientId(getByColumnType(BulkImportColumnType.MQTT_CLIENT_ID, data));  
162 - basicMqttCredentials.setUserName(getByColumnType(BulkImportColumnType.MQTT_USER_NAME, data));  
163 - basicMqttCredentials.setPassword(getByColumnType(BulkImportColumnType.MQTT_PASSWORD, data)); 160 + basicMqttCredentials.setClientId(fields.get(BulkImportColumnType.MQTT_CLIENT_ID));
  161 + basicMqttCredentials.setUserName(fields.get(BulkImportColumnType.MQTT_USER_NAME));
  162 + basicMqttCredentials.setPassword(fields.get(BulkImportColumnType.MQTT_PASSWORD));
164 credentials.setCredentialsValue(JacksonUtil.toString(basicMqttCredentials)); 163 credentials.setCredentialsValue(JacksonUtil.toString(basicMqttCredentials));
165 } else if (columns.contains(BulkImportColumnType.X509)) { 164 } else if (columns.contains(BulkImportColumnType.X509)) {
166 credentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE); 165 credentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE);
167 - credentials.setCredentialsValue(getByColumnType(BulkImportColumnType.X509, data)); 166 + credentials.setCredentialsValue(fields.get(BulkImportColumnType.X509));
168 } else if (columns.contains(BulkImportColumnType.LWM2M_CLIENT_ENDPOINT)) { 167 } else if (columns.contains(BulkImportColumnType.LWM2M_CLIENT_ENDPOINT)) {
169 credentials.setCredentialsType(DeviceCredentialsType.LWM2M_CREDENTIALS); 168 credentials.setCredentialsType(DeviceCredentialsType.LWM2M_CREDENTIALS);
170 ObjectNode lwm2mCredentials = JacksonUtil.newObjectNode(); 169 ObjectNode lwm2mCredentials = JacksonUtil.newObjectNode();
@@ -173,7 +172,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> { @@ -173,7 +172,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
173 Stream.of(BulkImportColumnType.LWM2M_CLIENT_ENDPOINT, BulkImportColumnType.LWM2M_CLIENT_SECURITY_CONFIG_MODE, 172 Stream.of(BulkImportColumnType.LWM2M_CLIENT_ENDPOINT, BulkImportColumnType.LWM2M_CLIENT_SECURITY_CONFIG_MODE,
174 BulkImportColumnType.LWM2M_CLIENT_IDENTITY, BulkImportColumnType.LWM2M_CLIENT_KEY, BulkImportColumnType.LWM2M_CLIENT_CERT) 173 BulkImportColumnType.LWM2M_CLIENT_IDENTITY, BulkImportColumnType.LWM2M_CLIENT_KEY, BulkImportColumnType.LWM2M_CLIENT_CERT)
175 .forEach(lwm2mClientProperty -> { 174 .forEach(lwm2mClientProperty -> {
176 - String value = getByColumnType(lwm2mClientProperty, data); 175 + String value = fields.get(lwm2mClientProperty);
177 if (value != null) { 176 if (value != null) {
178 client.set(lwm2mClientProperty.getKey(), new TextNode(value)); 177 client.set(lwm2mClientProperty.getKey(), new TextNode(value));
179 } 178 }
@@ -187,7 +186,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> { @@ -187,7 +186,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
187 Stream.of(BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECURITY_MODE, BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_PUBLIC_KEY_OR_ID, 186 Stream.of(BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECURITY_MODE, BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_PUBLIC_KEY_OR_ID,
188 BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECRET_KEY) 187 BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECRET_KEY)
189 .forEach(lwm2mBootstrapServerProperty -> { 188 .forEach(lwm2mBootstrapServerProperty -> {
190 - String value = getByColumnType(lwm2mBootstrapServerProperty, data); 189 + String value = fields.get(lwm2mBootstrapServerProperty);
191 if (value != null) { 190 if (value != null) {
192 bootstrapServer.set(lwm2mBootstrapServerProperty.getKey(), new TextNode(value)); 191 bootstrapServer.set(lwm2mBootstrapServerProperty.getKey(), new TextNode(value));
193 } 192 }
@@ -197,7 +196,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> { @@ -197,7 +196,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
197 Stream.of(BulkImportColumnType.LWM2M_SERVER_SECURITY_MODE, BulkImportColumnType.LWM2M_SERVER_CLIENT_PUBLIC_KEY_OR_ID, 196 Stream.of(BulkImportColumnType.LWM2M_SERVER_SECURITY_MODE, BulkImportColumnType.LWM2M_SERVER_CLIENT_PUBLIC_KEY_OR_ID,
198 BulkImportColumnType.LWM2M_SERVER_CLIENT_SECRET_KEY) 197 BulkImportColumnType.LWM2M_SERVER_CLIENT_SECRET_KEY)
199 .forEach(lwm2mServerProperty -> { 198 .forEach(lwm2mServerProperty -> {
200 - String value = getByColumnType(lwm2mServerProperty, data); 199 + String value = fields.get(lwm2mServerProperty);
201 if (value != null) { 200 if (value != null) {
202 lwm2mServer.set(lwm2mServerProperty.getKey(), new TextNode(value)); 201 lwm2mServer.set(lwm2mServerProperty.getKey(), new TextNode(value));
203 } 202 }
@@ -26,6 +26,7 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache; @@ -26,6 +26,7 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
26 import org.thingsboard.server.queue.util.TbCoreComponent; 26 import org.thingsboard.server.queue.util.TbCoreComponent;
27 import org.thingsboard.server.service.action.EntityActionService; 27 import org.thingsboard.server.service.action.EntityActionService;
28 import org.thingsboard.server.service.importing.AbstractBulkImportService; 28 import org.thingsboard.server.service.importing.AbstractBulkImportService;
  29 +import org.thingsboard.server.service.importing.BulkImportColumnType;
29 import org.thingsboard.server.service.importing.BulkImportRequest; 30 import org.thingsboard.server.service.importing.BulkImportRequest;
30 import org.thingsboard.server.service.importing.ImportedEntityInfo; 31 import org.thingsboard.server.service.importing.ImportedEntityInfo;
31 import org.thingsboard.server.service.security.AccessValidator; 32 import org.thingsboard.server.service.security.AccessValidator;
@@ -49,12 +50,12 @@ public class EdgeBulkImportService extends AbstractBulkImportService<Edge> { @@ -49,12 +50,12 @@ public class EdgeBulkImportService extends AbstractBulkImportService<Edge> {
49 } 50 }
50 51
51 @Override 52 @Override
52 - protected ImportedEntityInfo<Edge> saveEntity(BulkImportRequest importRequest, Map<BulkImportRequest.ColumnMapping, String> entityData, SecurityUser user) { 53 + protected ImportedEntityInfo<Edge> saveEntity(BulkImportRequest importRequest, Map<BulkImportColumnType, String> fields, SecurityUser user) {
53 ImportedEntityInfo<Edge> importedEntityInfo = new ImportedEntityInfo<>(); 54 ImportedEntityInfo<Edge> importedEntityInfo = new ImportedEntityInfo<>();
54 55
55 Edge edge = new Edge(); 56 Edge edge = new Edge();
56 edge.setTenantId(user.getTenantId()); 57 edge.setTenantId(user.getTenantId());
57 - setEdgeFields(edge, entityData); 58 + setEdgeFields(edge, fields);
58 59
59 Edge existingEdge = edgeService.findEdgeByTenantIdAndName(user.getTenantId(), edge.getName()); 60 Edge existingEdge = edgeService.findEdgeByTenantIdAndName(user.getTenantId(), edge.getName());
60 if (existingEdge != null && importRequest.getMapping().getUpdate()) { 61 if (existingEdge != null && importRequest.getMapping().getUpdate()) {
@@ -69,10 +70,10 @@ public class EdgeBulkImportService extends AbstractBulkImportService<Edge> { @@ -69,10 +70,10 @@ public class EdgeBulkImportService extends AbstractBulkImportService<Edge> {
69 return importedEntityInfo; 70 return importedEntityInfo;
70 } 71 }
71 72
72 - private void setEdgeFields(Edge edge, Map<BulkImportRequest.ColumnMapping, String> data) { 73 + private void setEdgeFields(Edge edge, Map<BulkImportColumnType, String> fields) {
73 ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(edge.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); 74 ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(edge.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode);
74 - data.forEach((columnMapping, value) -> {  
75 - switch (columnMapping.getType()) { 75 + fields.forEach((columnType, value) -> {
  76 + switch (columnType) {
76 case NAME: 77 case NAME:
77 edge.setName(value); 78 edge.setName(value);
78 break; 79 break;
@@ -18,6 +18,7 @@ package org.thingsboard.server.service.importing; @@ -18,6 +18,7 @@ package org.thingsboard.server.service.importing;
18 import com.google.common.util.concurrent.FutureCallback; 18 import com.google.common.util.concurrent.FutureCallback;
19 import com.google.gson.JsonObject; 19 import com.google.gson.JsonObject;
20 import com.google.gson.JsonPrimitive; 20 import com.google.gson.JsonPrimitive;
  21 +import lombok.Data;
21 import lombok.RequiredArgsConstructor; 22 import lombok.RequiredArgsConstructor;
22 import lombok.SneakyThrows; 23 import lombok.SneakyThrows;
23 import org.apache.commons.lang3.StringUtils; 24 import org.apache.commons.lang3.StringUtils;
@@ -29,6 +30,7 @@ import org.thingsboard.server.common.data.id.EntityId; @@ -29,6 +30,7 @@ import org.thingsboard.server.common.data.id.EntityId;
29 import org.thingsboard.server.common.data.id.UUIDBased; 30 import org.thingsboard.server.common.data.id.UUIDBased;
30 import org.thingsboard.server.common.data.kv.AttributeKvEntry; 31 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
31 import org.thingsboard.server.common.data.kv.BasicTsKvEntry; 32 import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
  33 +import org.thingsboard.server.common.data.kv.DataType;
32 import org.thingsboard.server.common.data.kv.TsKvEntry; 34 import org.thingsboard.server.common.data.kv.TsKvEntry;
33 import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; 35 import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
34 import org.thingsboard.server.common.transport.adaptor.JsonConverter; 36 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
@@ -42,9 +44,12 @@ import org.thingsboard.server.service.security.permission.AccessControlService; @@ -42,9 +44,12 @@ import org.thingsboard.server.service.security.permission.AccessControlService;
42 import org.thingsboard.server.service.security.permission.Operation; 44 import org.thingsboard.server.service.security.permission.Operation;
43 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; 45 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
44 import org.thingsboard.server.utils.CsvUtils; 46 import org.thingsboard.server.utils.CsvUtils;
  47 +import org.thingsboard.server.utils.TypeCastUtil;
45 48
46 import javax.annotation.Nullable; 49 import javax.annotation.Nullable;
47 import java.util.ArrayList; 50 import java.util.ArrayList;
  51 +import java.util.Arrays;
  52 +import java.util.HashMap;
48 import java.util.List; 53 import java.util.List;
49 import java.util.Map; 54 import java.util.Map;
50 import java.util.concurrent.TimeUnit; 55 import java.util.concurrent.TimeUnit;
@@ -73,12 +78,12 @@ public abstract class AbstractBulkImportService<E extends BaseData<? extends Ent @@ -73,12 +78,12 @@ public abstract class AbstractBulkImportService<E extends BaseData<? extends Ent
73 parseData(request).forEach(entityData -> { 78 parseData(request).forEach(entityData -> {
74 i.incrementAndGet(); 79 i.incrementAndGet();
75 try { 80 try {
76 - ImportedEntityInfo<E> importedEntityInfo = saveEntity(request, entityData, user); 81 + ImportedEntityInfo<E> importedEntityInfo = saveEntity(request, entityData.getFields(), user);
77 onEntityImported.accept(importedEntityInfo); 82 onEntityImported.accept(importedEntityInfo);
78 83
79 E entity = importedEntityInfo.getEntity(); 84 E entity = importedEntityInfo.getEntity();
80 85
81 - saveKvs(user, entity, entityData); 86 + saveKvs(user, entity, entityData.getKvs());
82 87
83 if (importedEntityInfo.getRelatedError() != null) { 88 if (importedEntityInfo.getRelatedError() != null) {
84 throw new RuntimeException(importedEntityInfo.getRelatedError()); 89 throw new RuntimeException(importedEntityInfo.getRelatedError());
@@ -98,20 +103,21 @@ public abstract class AbstractBulkImportService<E extends BaseData<? extends Ent @@ -98,20 +103,21 @@ public abstract class AbstractBulkImportService<E extends BaseData<? extends Ent
98 return result; 103 return result;
99 } 104 }
100 105
101 - protected abstract ImportedEntityInfo<E> saveEntity(BulkImportRequest importRequest, Map<ColumnMapping, String> entityData, SecurityUser user); 106 + protected abstract ImportedEntityInfo<E> saveEntity(BulkImportRequest importRequest, Map<BulkImportColumnType, String> fields, SecurityUser user);
102 107
103 /* 108 /*
104 * Attributes' values are firstly added to JsonObject in order to then make some type cast, 109 * Attributes' values are firstly added to JsonObject in order to then make some type cast,
105 * because we get all values as strings from CSV 110 * because we get all values as strings from CSV
106 * */ 111 * */
107 - private void saveKvs(SecurityUser user, E entity, Map<ColumnMapping, String> data) {  
108 - Stream.of(BulkImportColumnType.SHARED_ATTRIBUTE, BulkImportColumnType.SERVER_ATTRIBUTE, BulkImportColumnType.TIMESERIES) 112 + private void saveKvs(SecurityUser user, E entity, Map<ColumnMapping, ParsedValue> data) {
  113 + Arrays.stream(BulkImportColumnType.values())
  114 + .filter(BulkImportColumnType::isKv)
109 .map(kvType -> { 115 .map(kvType -> {
110 JsonObject kvs = new JsonObject(); 116 JsonObject kvs = new JsonObject();
111 data.entrySet().stream() 117 data.entrySet().stream()
112 .filter(dataEntry -> dataEntry.getKey().getType() == kvType && 118 .filter(dataEntry -> dataEntry.getKey().getType() == kvType &&
113 StringUtils.isNotEmpty(dataEntry.getKey().getKey())) 119 StringUtils.isNotEmpty(dataEntry.getKey().getKey()))
114 - .forEach(dataEntry -> kvs.add(dataEntry.getKey().getKey(), new JsonPrimitive(dataEntry.getValue()))); 120 + .forEach(dataEntry -> kvs.add(dataEntry.getKey().getKey(), dataEntry.getValue().toJsonPrimitive()));
115 return Map.entry(kvType, kvs); 121 return Map.entry(kvType, kvs);
116 }) 122 })
117 .filter(kvsEntry -> kvsEntry.getValue().entrySet().size() > 0) 123 .filter(kvsEntry -> kvsEntry.getValue().entrySet().size() > 0)
@@ -127,7 +133,7 @@ public abstract class AbstractBulkImportService<E extends BaseData<? extends Ent @@ -127,7 +133,7 @@ public abstract class AbstractBulkImportService<E extends BaseData<? extends Ent
127 133
128 @SneakyThrows 134 @SneakyThrows
129 private void saveTelemetry(SecurityUser user, E entity, Map.Entry<BulkImportColumnType, JsonObject> kvsEntry) { 135 private void saveTelemetry(SecurityUser user, E entity, Map.Entry<BulkImportColumnType, JsonObject> kvsEntry) {
130 - List<TsKvEntry> timeseries = JsonConverter.convertToTelemetry(kvsEntry.getValue(), System.currentTimeMillis(), false, true) 136 + List<TsKvEntry> timeseries = JsonConverter.convertToTelemetry(kvsEntry.getValue(), System.currentTimeMillis())
131 .entrySet().stream() 137 .entrySet().stream()
132 .flatMap(entry -> entry.getValue().stream().map(kvEntry -> new BasicTsKvEntry(entry.getKey(), kvEntry))) 138 .flatMap(entry -> entry.getValue().stream().map(kvEntry -> new BasicTsKvEntry(entry.getKey(), kvEntry)))
133 .collect(Collectors.toList()); 139 .collect(Collectors.toList());
@@ -155,7 +161,7 @@ public abstract class AbstractBulkImportService<E extends BaseData<? extends Ent @@ -155,7 +161,7 @@ public abstract class AbstractBulkImportService<E extends BaseData<? extends Ent
155 @SneakyThrows 161 @SneakyThrows
156 private void saveAttributes(SecurityUser user, E entity, Map.Entry<BulkImportColumnType, JsonObject> kvsEntry, BulkImportColumnType kvType) { 162 private void saveAttributes(SecurityUser user, E entity, Map.Entry<BulkImportColumnType, JsonObject> kvsEntry, BulkImportColumnType kvType) {
157 String scope = kvType.getKey(); 163 String scope = kvType.getKey();
158 - List<AttributeKvEntry> attributes = new ArrayList<>(JsonConverter.convertToAttributes(kvsEntry.getValue(), true)); 164 + List<AttributeKvEntry> attributes = new ArrayList<>(JsonConverter.convertToAttributes(kvsEntry.getValue()));
159 165
160 accessValidator.validateEntityAndCallback(user, Operation.WRITE_ATTRIBUTES, entity.getId(), (result, tenantId, entityId) -> { 166 accessValidator.validateEntityAndCallback(user, Operation.WRITE_ATTRIBUTES, entity.getId(), (result, tenantId, entityId) -> {
161 tsSubscriptionService.saveAndNotify(tenantId, entityId, scope, attributes, new FutureCallback<>() { 167 tsSubscriptionService.saveAndNotify(tenantId, entityId, scope, attributes, new FutureCallback<>() {
@@ -178,24 +184,62 @@ public abstract class AbstractBulkImportService<E extends BaseData<? extends Ent @@ -178,24 +184,62 @@ public abstract class AbstractBulkImportService<E extends BaseData<? extends Ent
178 }); 184 });
179 } 185 }
180 186
181 - protected final String getByColumnType(BulkImportColumnType bulkImportColumnType, Map<ColumnMapping, String> data) {  
182 - return data.entrySet().stream().filter(entry -> entry.getKey().getType() == bulkImportColumnType).findFirst().map(Map.Entry::getValue).orElse(null);  
183 - }  
184 -  
185 - private List<Map<ColumnMapping, String>> parseData(BulkImportRequest request) throws Exception { 187 + private List<EntityData> parseData(BulkImportRequest request) throws Exception {
186 List<List<String>> records = CsvUtils.parseCsv(request.getFile(), request.getMapping().getDelimiter()); 188 List<List<String>> records = CsvUtils.parseCsv(request.getFile(), request.getMapping().getDelimiter());
187 if (request.getMapping().getHeader()) { 189 if (request.getMapping().getHeader()) {
188 records.remove(0); 190 records.remove(0);
189 } 191 }
190 192
191 List<ColumnMapping> columnsMappings = request.getMapping().getColumns(); 193 List<ColumnMapping> columnsMappings = request.getMapping().getColumns();
192 -  
193 return records.stream() 194 return records.stream()
194 - .map(record -> Stream.iterate(0, i -> i < record.size(), i -> i + 1)  
195 - .map(i -> Map.entry(columnsMappings.get(i), record.get(i)))  
196 - .filter(entry -> StringUtils.isNotEmpty(entry.getValue()))  
197 - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))) 195 + .map(record -> {
  196 + EntityData entityData = new EntityData();
  197 + Stream.iterate(0, i -> i < record.size(), i -> i + 1)
  198 + .map(i -> Map.entry(columnsMappings.get(i), record.get(i)))
  199 + .filter(entry -> StringUtils.isNotEmpty(entry.getValue()))
  200 + .forEach(entry -> {
  201 + if (!entry.getKey().getType().isKv()) {
  202 + entityData.getFields().put(entry.getKey().getType(), entry.getValue());
  203 + } else {
  204 + Map.Entry<DataType, Object> castResult = TypeCastUtil.castValue(entry.getValue());
  205 + entityData.getKvs().put(entry.getKey(), new ParsedValue(castResult.getValue(), castResult.getKey()));
  206 + }
  207 + });
  208 + return entityData;
  209 + })
198 .collect(Collectors.toList()); 210 .collect(Collectors.toList());
199 } 211 }
200 212
  213 + @Data
  214 + protected static class EntityData {
  215 + private final Map<BulkImportColumnType, String> fields = new HashMap<>();
  216 + private final Map<ColumnMapping, ParsedValue> kvs = new HashMap<>();
  217 + }
  218 +
  219 + @Data
  220 + protected static class ParsedValue {
  221 + private final Object value;
  222 + private final DataType dataType;
  223 +
  224 + public JsonPrimitive toJsonPrimitive() {
  225 + switch (dataType) {
  226 + case STRING:
  227 + return new JsonPrimitive((String) value);
  228 + case LONG:
  229 + return new JsonPrimitive((Long) value);
  230 + case DOUBLE:
  231 + return new JsonPrimitive((Double) value);
  232 + case BOOLEAN:
  233 + return new JsonPrimitive((Boolean) value);
  234 + default:
  235 + return null;
  236 + }
  237 + }
  238 +
  239 + public String stringValue() {
  240 + return value.toString();
  241 + }
  242 +
  243 + }
  244 +
201 } 245 }
@@ -18,13 +18,14 @@ package org.thingsboard.server.service.importing; @@ -18,13 +18,14 @@ package org.thingsboard.server.service.importing;
18 import lombok.Getter; 18 import lombok.Getter;
19 import org.thingsboard.server.common.data.DataConstants; 19 import org.thingsboard.server.common.data.DataConstants;
20 20
  21 +@Getter
21 public enum BulkImportColumnType { 22 public enum BulkImportColumnType {
22 NAME, 23 NAME,
23 TYPE, 24 TYPE,
24 LABEL, 25 LABEL,
25 - SHARED_ATTRIBUTE(DataConstants.SHARED_SCOPE),  
26 - SERVER_ATTRIBUTE(DataConstants.SERVER_SCOPE),  
27 - TIMESERIES, 26 + SHARED_ATTRIBUTE(DataConstants.SHARED_SCOPE, true),
  27 + SERVER_ATTRIBUTE(DataConstants.SERVER_SCOPE, true),
  28 + TIMESERIES(true),
28 ACCESS_TOKEN, 29 ACCESS_TOKEN,
29 X509, 30 X509,
30 MQTT_CLIENT_ID, 31 MQTT_CLIENT_ID,
@@ -48,8 +49,8 @@ public enum BulkImportColumnType { @@ -48,8 +49,8 @@ public enum BulkImportColumnType {
48 ROUTING_KEY, 49 ROUTING_KEY,
49 SECRET; 50 SECRET;
50 51
51 - @Getter  
52 private String key; 52 private String key;
  53 + private boolean isKv = false;
53 54
54 BulkImportColumnType() { 55 BulkImportColumnType() {
55 } 56 }
@@ -57,4 +58,13 @@ public enum BulkImportColumnType { @@ -57,4 +58,13 @@ public enum BulkImportColumnType {
57 BulkImportColumnType(String key) { 58 BulkImportColumnType(String key) {
58 this.key = key; 59 this.key = key;
59 } 60 }
  61 +
  62 + BulkImportColumnType(boolean isKv) {
  63 + this.isKv = isKv;
  64 + }
  65 +
  66 + BulkImportColumnType(String key, boolean isKv) {
  67 + this.key = key;
  68 + this.isKv = isKv;
  69 + }
60 } 70 }
  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.utils;
  17 +
  18 +import org.apache.commons.lang3.math.NumberUtils;
  19 +import org.thingsboard.server.common.data.kv.DataType;
  20 +
  21 +import java.math.BigDecimal;
  22 +import java.util.Map;
  23 +
  24 +public class TypeCastUtil {
  25 +
  26 + private TypeCastUtil() {}
  27 +
  28 + public static Map.Entry<DataType, Object> castValue(String value) {
  29 + if (isNumber(value)) {
  30 + String formattedValue = value.replace(',', '.');
  31 + try {
  32 + BigDecimal bd = new BigDecimal(formattedValue);
  33 + if (bd.stripTrailingZeros().scale() > 0 || isSimpleDouble(formattedValue)) {
  34 + if (bd.scale() <= 16) {
  35 + return Map.entry(DataType.DOUBLE, bd.doubleValue());
  36 + }
  37 + } else {
  38 + return Map.entry(DataType.LONG, bd.longValueExact());
  39 + }
  40 + } catch (RuntimeException ignored) {}
  41 + } else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
  42 + return Map.entry(DataType.BOOLEAN, Boolean.parseBoolean(value));
  43 + }
  44 + return Map.entry(DataType.STRING, value);
  45 + }
  46 +
  47 + private static boolean isNumber(String value) {
  48 + return NumberUtils.isParsable(value.replace(',', '.'));
  49 + }
  50 +
  51 + private static boolean isSimpleDouble(String valueAsString) {
  52 + return valueAsString.contains(".") && !valueAsString.contains("E") && !valueAsString.contains("e");
  53 + }
  54 +
  55 +}
@@ -76,7 +76,7 @@ public class JsonConverter { @@ -76,7 +76,7 @@ public class JsonConverter {
76 76
77 public static PostTelemetryMsg convertToTelemetryProto(JsonElement jsonElement, long ts) throws JsonSyntaxException { 77 public static PostTelemetryMsg convertToTelemetryProto(JsonElement jsonElement, long ts) throws JsonSyntaxException {
78 PostTelemetryMsg.Builder builder = PostTelemetryMsg.newBuilder(); 78 PostTelemetryMsg.Builder builder = PostTelemetryMsg.newBuilder();
79 - convertToTelemetry(jsonElement, ts, null, builder, isTypeCastEnabled); 79 + convertToTelemetry(jsonElement, ts, null, builder);
80 return builder.build(); 80 return builder.build();
81 } 81 }
82 82
@@ -84,13 +84,13 @@ public class JsonConverter { @@ -84,13 +84,13 @@ public class JsonConverter {
84 return convertToTelemetryProto(jsonElement, System.currentTimeMillis()); 84 return convertToTelemetryProto(jsonElement, System.currentTimeMillis());
85 } 85 }
86 86
87 - private static void convertToTelemetry(JsonElement jsonElement, long systemTs, Map<Long, List<KvEntry>> result, PostTelemetryMsg.Builder builder, boolean typeCastEnabled) { 87 + private static void convertToTelemetry(JsonElement jsonElement, long systemTs, Map<Long, List<KvEntry>> result, PostTelemetryMsg.Builder builder) {
88 if (jsonElement.isJsonObject()) { 88 if (jsonElement.isJsonObject()) {
89 - parseObject(systemTs, result, builder, jsonElement.getAsJsonObject(), typeCastEnabled); 89 + parseObject(systemTs, result, builder, jsonElement.getAsJsonObject());
90 } else if (jsonElement.isJsonArray()) { 90 } else if (jsonElement.isJsonArray()) {
91 jsonElement.getAsJsonArray().forEach(je -> { 91 jsonElement.getAsJsonArray().forEach(je -> {
92 if (je.isJsonObject()) { 92 if (je.isJsonObject()) {
93 - parseObject(systemTs, result, builder, je.getAsJsonObject(), typeCastEnabled); 93 + parseObject(systemTs, result, builder, je.getAsJsonObject());
94 } else { 94 } else {
95 throw new JsonSyntaxException(CAN_T_PARSE_VALUE + je); 95 throw new JsonSyntaxException(CAN_T_PARSE_VALUE + je);
96 } 96 }
@@ -100,11 +100,11 @@ public class JsonConverter { @@ -100,11 +100,11 @@ public class JsonConverter {
100 } 100 }
101 } 101 }
102 102
103 - private static void parseObject(long systemTs, Map<Long, List<KvEntry>> result, PostTelemetryMsg.Builder builder, JsonObject jo, boolean typeCastEnabled) { 103 + private static void parseObject(long systemTs, Map<Long, List<KvEntry>> result, PostTelemetryMsg.Builder builder, JsonObject jo) {
104 if (result != null) { 104 if (result != null) {
105 - parseObject(result, systemTs, jo, typeCastEnabled); 105 + parseObject(result, systemTs, jo);
106 } else { 106 } else {
107 - parseObject(builder, systemTs, jo, typeCastEnabled); 107 + parseObject(builder, systemTs, jo);
108 } 108 }
109 } 109 }
110 110
@@ -146,7 +146,7 @@ public class JsonConverter { @@ -146,7 +146,7 @@ public class JsonConverter {
146 public static PostAttributeMsg convertToAttributesProto(JsonElement jsonObject) throws JsonSyntaxException { 146 public static PostAttributeMsg convertToAttributesProto(JsonElement jsonObject) throws JsonSyntaxException {
147 if (jsonObject.isJsonObject()) { 147 if (jsonObject.isJsonObject()) {
148 PostAttributeMsg.Builder result = PostAttributeMsg.newBuilder(); 148 PostAttributeMsg.Builder result = PostAttributeMsg.newBuilder();
149 - List<KeyValueProto> keyValueList = parseProtoValues(jsonObject.getAsJsonObject(), isTypeCastEnabled); 149 + List<KeyValueProto> keyValueList = parseProtoValues(jsonObject.getAsJsonObject());
150 result.addAllKv(keyValueList); 150 result.addAllKv(keyValueList);
151 return result.build(); 151 return result.build();
152 } else { 152 } else {
@@ -164,29 +164,29 @@ public class JsonConverter { @@ -164,29 +164,29 @@ public class JsonConverter {
164 return result; 164 return result;
165 } 165 }
166 166
167 - private static void parseObject(PostTelemetryMsg.Builder builder, long systemTs, JsonObject jo, boolean typeCastEnabled) { 167 + private static void parseObject(PostTelemetryMsg.Builder builder, long systemTs, JsonObject jo) {
168 if (jo.has("ts") && jo.has("values")) { 168 if (jo.has("ts") && jo.has("values")) {
169 - parseWithTs(builder, jo, typeCastEnabled); 169 + parseWithTs(builder, jo);
170 } else { 170 } else {
171 - parseWithoutTs(builder, systemTs, jo, typeCastEnabled); 171 + parseWithoutTs(builder, systemTs, jo);
172 } 172 }
173 } 173 }
174 174
175 - private static void parseWithoutTs(PostTelemetryMsg.Builder request, long systemTs, JsonObject jo, boolean typeCastEnabled) { 175 + private static void parseWithoutTs(PostTelemetryMsg.Builder request, long systemTs, JsonObject jo) {
176 TsKvListProto.Builder builder = TsKvListProto.newBuilder(); 176 TsKvListProto.Builder builder = TsKvListProto.newBuilder();
177 builder.setTs(systemTs); 177 builder.setTs(systemTs);
178 - builder.addAllKv(parseProtoValues(jo, typeCastEnabled)); 178 + builder.addAllKv(parseProtoValues(jo));
179 request.addTsKvList(builder.build()); 179 request.addTsKvList(builder.build());
180 } 180 }
181 181
182 - private static void parseWithTs(PostTelemetryMsg.Builder request, JsonObject jo, boolean typeCastEnabled) { 182 + private static void parseWithTs(PostTelemetryMsg.Builder request, JsonObject jo) {
183 TsKvListProto.Builder builder = TsKvListProto.newBuilder(); 183 TsKvListProto.Builder builder = TsKvListProto.newBuilder();
184 builder.setTs(jo.get("ts").getAsLong()); 184 builder.setTs(jo.get("ts").getAsLong());
185 - builder.addAllKv(parseProtoValues(jo.get("values").getAsJsonObject(), typeCastEnabled)); 185 + builder.addAllKv(parseProtoValues(jo.get("values").getAsJsonObject()));
186 request.addTsKvList(builder.build()); 186 request.addTsKvList(builder.build());
187 } 187 }
188 188
189 - private static List<KeyValueProto> parseProtoValues(JsonObject valuesObject, boolean typeCastEnabled) { 189 + private static List<KeyValueProto> parseProtoValues(JsonObject valuesObject) {
190 List<KeyValueProto> result = new ArrayList<>(); 190 List<KeyValueProto> result = new ArrayList<>();
191 for (Entry<String, JsonElement> valueEntry : valuesObject.entrySet()) { 191 for (Entry<String, JsonElement> valueEntry : valuesObject.entrySet()) {
192 JsonElement element = valueEntry.getValue(); 192 JsonElement element = valueEntry.getValue();
@@ -197,9 +197,9 @@ public class JsonConverter { @@ -197,9 +197,9 @@ public class JsonConverter {
197 String message = String.format("String value length [%d] for key [%s] is greater than maximum allowed [%d]", value.getAsString().length(), valueEntry.getKey(), maxStringValueLength); 197 String message = String.format("String value length [%d] for key [%s] is greater than maximum allowed [%d]", value.getAsString().length(), valueEntry.getKey(), maxStringValueLength);
198 throw new JsonSyntaxException(message); 198 throw new JsonSyntaxException(message);
199 } 199 }
200 - if (typeCastEnabled && isNumber(value)) { 200 + if (isTypeCastEnabled && NumberUtils.isParsable(value.getAsString())) {
201 try { 201 try {
202 - result.add(buildNumericKeyValueProto(value, valueEntry.getKey(), typeCastEnabled)); 202 + result.add(buildNumericKeyValueProto(value, valueEntry.getKey()));
203 } catch (RuntimeException th) { 203 } catch (RuntimeException th) {
204 result.add(KeyValueProto.newBuilder().setKey(valueEntry.getKey()).setType(KeyValueType.STRING_V) 204 result.add(KeyValueProto.newBuilder().setKey(valueEntry.getKey()).setType(KeyValueType.STRING_V)
205 .setStringV(value.getAsString()).build()); 205 .setStringV(value.getAsString()).build());
@@ -212,7 +212,7 @@ public class JsonConverter { @@ -212,7 +212,7 @@ public class JsonConverter {
212 result.add(KeyValueProto.newBuilder().setKey(valueEntry.getKey()).setType(KeyValueType.BOOLEAN_V) 212 result.add(KeyValueProto.newBuilder().setKey(valueEntry.getKey()).setType(KeyValueType.BOOLEAN_V)
213 .setBoolV(value.getAsBoolean()).build()); 213 .setBoolV(value.getAsBoolean()).build());
214 } else if (value.isNumber()) { 214 } else if (value.isNumber()) {
215 - result.add(buildNumericKeyValueProto(value, valueEntry.getKey(), typeCastEnabled)); 215 + result.add(buildNumericKeyValueProto(value, valueEntry.getKey()));
216 } else if (!value.isJsonNull()) { 216 } else if (!value.isJsonNull()) {
217 throw new JsonSyntaxException(CAN_T_PARSE_VALUE + value); 217 throw new JsonSyntaxException(CAN_T_PARSE_VALUE + value);
218 } 218 }
@@ -225,15 +225,15 @@ public class JsonConverter { @@ -225,15 +225,15 @@ public class JsonConverter {
225 return result; 225 return result;
226 } 226 }
227 227
228 - private static KeyValueProto buildNumericKeyValueProto(JsonPrimitive value, String key, boolean typeCastEnabled) {  
229 - String valueAsString = value.getAsString().replace(',', '.'); 228 + private static KeyValueProto buildNumericKeyValueProto(JsonPrimitive value, String key) {
  229 + String valueAsString = value.getAsString();
230 KeyValueProto.Builder builder = KeyValueProto.newBuilder().setKey(key); 230 KeyValueProto.Builder builder = KeyValueProto.newBuilder().setKey(key);
231 var bd = new BigDecimal(valueAsString); 231 var bd = new BigDecimal(valueAsString);
232 if (bd.stripTrailingZeros().scale() <= 0 && !isSimpleDouble(valueAsString)) { 232 if (bd.stripTrailingZeros().scale() <= 0 && !isSimpleDouble(valueAsString)) {
233 try { 233 try {
234 return builder.setType(KeyValueType.LONG_V).setLongV(bd.longValueExact()).build(); 234 return builder.setType(KeyValueType.LONG_V).setLongV(bd.longValueExact()).build();
235 } catch (ArithmeticException e) { 235 } catch (ArithmeticException e) {
236 - if (typeCastEnabled) { 236 + if (isTypeCastEnabled) {
237 return builder.setType(KeyValueType.STRING_V).setStringV(bd.toPlainString()).build(); 237 return builder.setType(KeyValueType.STRING_V).setStringV(bd.toPlainString()).build();
238 } else { 238 } else {
239 throw new JsonSyntaxException("Big integer values are not supported!"); 239 throw new JsonSyntaxException("Big integer values are not supported!");
@@ -242,7 +242,7 @@ public class JsonConverter { @@ -242,7 +242,7 @@ public class JsonConverter {
242 } else { 242 } else {
243 if (bd.scale() <= 16) { 243 if (bd.scale() <= 16) {
244 return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(bd.doubleValue()).build(); 244 return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(bd.doubleValue()).build();
245 - } else if (typeCastEnabled) { 245 + } else if (isTypeCastEnabled) {
246 return builder.setType(KeyValueType.STRING_V).setStringV(bd.toPlainString()).build(); 246 return builder.setType(KeyValueType.STRING_V).setStringV(bd.toPlainString()).build();
247 } else { 247 } else {
248 throw new JsonSyntaxException("Big integer values are not supported!"); 248 throw new JsonSyntaxException("Big integer values are not supported!");
@@ -260,15 +260,15 @@ public class JsonConverter { @@ -260,15 +260,15 @@ public class JsonConverter {
260 return TransportProtos.ToServerRpcRequestMsg.newBuilder().setRequestId(requestId).setMethodName(object.get("method").getAsString()).setParams(GSON.toJson(object.get("params"))).build(); 260 return TransportProtos.ToServerRpcRequestMsg.newBuilder().setRequestId(requestId).setMethodName(object.get("method").getAsString()).setParams(GSON.toJson(object.get("params"))).build();
261 } 261 }
262 262
263 - private static void parseNumericValue(List<KvEntry> result, Entry<String, JsonElement> valueEntry, JsonPrimitive value, boolean typeCastEnabled) {  
264 - String valueAsString = value.getAsString().replace(',', '.'); 263 + private static void parseNumericValue(List<KvEntry> result, Entry<String, JsonElement> valueEntry, JsonPrimitive value) {
  264 + String valueAsString = value.getAsString();
265 String key = valueEntry.getKey(); 265 String key = valueEntry.getKey();
266 var bd = new BigDecimal(valueAsString); 266 var bd = new BigDecimal(valueAsString);
267 if (bd.stripTrailingZeros().scale() <= 0 && !isSimpleDouble(valueAsString)) { 267 if (bd.stripTrailingZeros().scale() <= 0 && !isSimpleDouble(valueAsString)) {
268 try { 268 try {
269 result.add(new LongDataEntry(key, bd.longValueExact())); 269 result.add(new LongDataEntry(key, bd.longValueExact()));
270 } catch (ArithmeticException e) { 270 } catch (ArithmeticException e) {
271 - if (typeCastEnabled) { 271 + if (isTypeCastEnabled) {
272 result.add(new StringDataEntry(key, bd.toPlainString())); 272 result.add(new StringDataEntry(key, bd.toPlainString()));
273 } else { 273 } else {
274 throw new JsonSyntaxException("Big integer values are not supported!"); 274 throw new JsonSyntaxException("Big integer values are not supported!");
@@ -277,7 +277,7 @@ public class JsonConverter { @@ -277,7 +277,7 @@ public class JsonConverter {
277 } else { 277 } else {
278 if (bd.scale() <= 16) { 278 if (bd.scale() <= 16) {
279 result.add(new DoubleDataEntry(key, bd.doubleValue())); 279 result.add(new DoubleDataEntry(key, bd.doubleValue()));
280 - } else if (typeCastEnabled) { 280 + } else if (isTypeCastEnabled) {
281 result.add(new StringDataEntry(key, bd.toPlainString())); 281 result.add(new StringDataEntry(key, bd.toPlainString()));
282 } else { 282 } else {
283 throw new JsonSyntaxException("Big integer values are not supported!"); 283 throw new JsonSyntaxException("Big integer values are not supported!");
@@ -487,17 +487,13 @@ public class JsonConverter { @@ -487,17 +487,13 @@ public class JsonConverter {
487 } 487 }
488 488
489 public static Set<AttributeKvEntry> convertToAttributes(JsonElement element) { 489 public static Set<AttributeKvEntry> convertToAttributes(JsonElement element) {
490 - return convertToAttributes(element, isTypeCastEnabled);  
491 - }  
492 -  
493 - public static Set<AttributeKvEntry> convertToAttributes(JsonElement element, boolean typeCastEnabled) {  
494 Set<AttributeKvEntry> result = new HashSet<>(); 490 Set<AttributeKvEntry> result = new HashSet<>();
495 long ts = System.currentTimeMillis(); 491 long ts = System.currentTimeMillis();
496 - result.addAll(parseValues(element.getAsJsonObject(), typeCastEnabled).stream().map(kv -> new BaseAttributeKvEntry(kv, ts)).collect(Collectors.toList())); 492 + result.addAll(parseValues(element.getAsJsonObject()).stream().map(kv -> new BaseAttributeKvEntry(kv, ts)).collect(Collectors.toList()));
497 return result; 493 return result;
498 } 494 }
499 495
500 - private static List<KvEntry> parseValues(JsonObject valuesObject, boolean typeCastEnabled) { 496 + private static List<KvEntry> parseValues(JsonObject valuesObject) {
501 List<KvEntry> result = new ArrayList<>(); 497 List<KvEntry> result = new ArrayList<>();
502 for (Entry<String, JsonElement> valueEntry : valuesObject.entrySet()) { 498 for (Entry<String, JsonElement> valueEntry : valuesObject.entrySet()) {
503 JsonElement element = valueEntry.getValue(); 499 JsonElement element = valueEntry.getValue();
@@ -508,9 +504,9 @@ public class JsonConverter { @@ -508,9 +504,9 @@ public class JsonConverter {
508 String message = String.format("String value length [%d] for key [%s] is greater than maximum allowed [%d]", value.getAsString().length(), valueEntry.getKey(), maxStringValueLength); 504 String message = String.format("String value length [%d] for key [%s] is greater than maximum allowed [%d]", value.getAsString().length(), valueEntry.getKey(), maxStringValueLength);
509 throw new JsonSyntaxException(message); 505 throw new JsonSyntaxException(message);
510 } 506 }
511 - if (typeCastEnabled && isNumber(value)) { 507 + if (isTypeCastEnabled && NumberUtils.isParsable(value.getAsString())) {
512 try { 508 try {
513 - parseNumericValue(result, valueEntry, value, typeCastEnabled); 509 + parseNumericValue(result, valueEntry, value);
514 } catch (RuntimeException th) { 510 } catch (RuntimeException th) {
515 result.add(new StringDataEntry(valueEntry.getKey(), value.getAsString())); 511 result.add(new StringDataEntry(valueEntry.getKey(), value.getAsString()));
516 } 512 }
@@ -520,7 +516,7 @@ public class JsonConverter { @@ -520,7 +516,7 @@ public class JsonConverter {
520 } else if (value.isBoolean()) { 516 } else if (value.isBoolean()) {
521 result.add(new BooleanDataEntry(valueEntry.getKey(), value.getAsBoolean())); 517 result.add(new BooleanDataEntry(valueEntry.getKey(), value.getAsBoolean()));
522 } else if (value.isNumber()) { 518 } else if (value.isNumber()) {
523 - parseNumericValue(result, valueEntry, value, typeCastEnabled); 519 + parseNumericValue(result, valueEntry, value);
524 } else { 520 } else {
525 throw new JsonSyntaxException(CAN_T_PARSE_VALUE + value); 521 throw new JsonSyntaxException(CAN_T_PARSE_VALUE + value);
526 } 522 }
@@ -545,35 +541,30 @@ public class JsonConverter { @@ -545,35 +541,30 @@ public class JsonConverter {
545 541
546 public static Map<Long, List<KvEntry>> convertToTelemetry(JsonElement jsonElement, long systemTs, boolean sorted) throws 542 public static Map<Long, List<KvEntry>> convertToTelemetry(JsonElement jsonElement, long systemTs, boolean sorted) throws
547 JsonSyntaxException { 543 JsonSyntaxException {
548 - return convertToTelemetry(jsonElement, systemTs, sorted, isTypeCastEnabled);  
549 - }  
550 -  
551 - public static Map<Long, List<KvEntry>> convertToTelemetry(JsonElement jsonElement, long systemTs, boolean sorted, boolean typeCastEnabled) throws  
552 - JsonSyntaxException {  
553 Map<Long, List<KvEntry>> result = sorted ? new TreeMap<>() : new HashMap<>(); 544 Map<Long, List<KvEntry>> result = sorted ? new TreeMap<>() : new HashMap<>();
554 - convertToTelemetry(jsonElement, systemTs, result, null, typeCastEnabled); 545 + convertToTelemetry(jsonElement, systemTs, result, null);
555 return result; 546 return result;
556 } 547 }
557 548
558 549
559 - private static void parseObject(Map<Long, List<KvEntry>> result, long systemTs, JsonObject jo, boolean typeCastEnabled) { 550 + private static void parseObject(Map<Long, List<KvEntry>> result, long systemTs, JsonObject jo) {
560 if (jo.has("ts") && jo.has("values")) { 551 if (jo.has("ts") && jo.has("values")) {
561 - parseWithTs(result, jo, typeCastEnabled); 552 + parseWithTs(result, jo);
562 } else { 553 } else {
563 - parseWithoutTs(result, systemTs, jo, typeCastEnabled); 554 + parseWithoutTs(result, systemTs, jo);
564 } 555 }
565 } 556 }
566 557
567 - private static void parseWithoutTs(Map<Long, List<KvEntry>> result, long systemTs, JsonObject jo, boolean typeCastEnabled) {  
568 - for (KvEntry entry : parseValues(jo, typeCastEnabled)) { 558 + private static void parseWithoutTs(Map<Long, List<KvEntry>> result, long systemTs, JsonObject jo) {
  559 + for (KvEntry entry : parseValues(jo)) {
569 result.computeIfAbsent(systemTs, tmp -> new ArrayList<>()).add(entry); 560 result.computeIfAbsent(systemTs, tmp -> new ArrayList<>()).add(entry);
570 } 561 }
571 } 562 }
572 563
573 - public static void parseWithTs(Map<Long, List<KvEntry>> result, JsonObject jo, boolean typeCastEnabled) { 564 + public static void parseWithTs(Map<Long, List<KvEntry>> result, JsonObject jo) {
574 long ts = jo.get("ts").getAsLong(); 565 long ts = jo.get("ts").getAsLong();
575 JsonObject valuesObject = jo.get("values").getAsJsonObject(); 566 JsonObject valuesObject = jo.get("values").getAsJsonObject();
576 - for (KvEntry entry : parseValues(valuesObject, typeCastEnabled)) { 567 + for (KvEntry entry : parseValues(valuesObject)) {
577 result.computeIfAbsent(ts, tmp -> new ArrayList<>()).add(entry); 568 result.computeIfAbsent(ts, tmp -> new ArrayList<>()).add(entry);
578 } 569 }
579 } 570 }
@@ -643,10 +634,6 @@ public class JsonConverter { @@ -643,10 +634,6 @@ public class JsonConverter {
643 } 634 }
644 635
645 636
646 - private static boolean isNumber(JsonPrimitive value) {  
647 - return NumberUtils.isParsable(value.getAsString().replace(',', '.'));  
648 - }  
649 -  
650 private static String getStrValue(JsonObject jo, String field, boolean requiredField) { 637 private static String getStrValue(JsonObject jo, String field, boolean requiredField) {
651 if (jo.has(field)) { 638 if (jo.has(field)) {
652 return jo.get(field).getAsString(); 639 return jo.get(field).getAsString();
@@ -66,12 +66,6 @@ public class JsonConverterTest { @@ -66,12 +66,6 @@ public class JsonConverterTest {
66 } 66 }
67 67
68 @Test 68 @Test
69 - public void testParseAsDoubleWithCommaDecimalSeparatorAndTypeCast() {  
70 - var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": \"-1,1\"}"), 0L);  
71 - Assert.assertEquals(-1.1, result.get(0L).get(0).getDoubleValue().get(), 0.0);  
72 - }  
73 -  
74 - @Test  
75 public void testParseAsLong() { 69 public void testParseAsLong() {
76 var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 11}"), 0L); 70 var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 11}"), 0L);
77 Assert.assertEquals(11L, result.get(0L).get(0).getLongValue().get().longValue()); 71 Assert.assertEquals(11L, result.get(0L).get(0).getLongValue().get().longValue());