Showing
8 changed files
with
199 additions
and
108 deletions
@@ -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()); |