Showing
13 changed files
with
190 additions
and
39 deletions
@@ -168,12 +168,18 @@ public final class PluginProcessingContext implements PluginContext { | @@ -168,12 +168,18 @@ public final class PluginProcessingContext implements PluginContext { | ||
168 | 168 | ||
169 | @Override | 169 | @Override |
170 | public void saveTsData(final EntityId entityId, final List<TsKvEntry> entries, final PluginCallback<Void> callback) { | 170 | public void saveTsData(final EntityId entityId, final List<TsKvEntry> entries, final PluginCallback<Void> callback) { |
171 | + saveTsData(entityId, entries, 0L, callback); | ||
172 | + } | ||
173 | + | ||
174 | + @Override | ||
175 | + public void saveTsData(final EntityId entityId, final List<TsKvEntry> entries, long ttl, final PluginCallback<Void> callback) { | ||
171 | validate(entityId, new ValidationCallback(callback, ctx -> { | 176 | validate(entityId, new ValidationCallback(callback, ctx -> { |
172 | - ListenableFuture<List<ResultSet>> rsListFuture = pluginCtx.tsService.save(entityId, entries); | 177 | + ListenableFuture<List<ResultSet>> rsListFuture = pluginCtx.tsService.save(entityId, entries, ttl); |
173 | Futures.addCallback(rsListFuture, getListCallback(callback, v -> null), executor); | 178 | Futures.addCallback(rsListFuture, getListCallback(callback, v -> null), executor); |
174 | })); | 179 | })); |
175 | } | 180 | } |
176 | 181 | ||
182 | + | ||
177 | @Override | 183 | @Override |
178 | public void loadTimeseries(final EntityId entityId, final List<TsKvQuery> queries, final PluginCallback<List<TsKvEntry>> callback) { | 184 | public void loadTimeseries(final EntityId entityId, final List<TsKvQuery> queries, final PluginCallback<List<TsKvEntry>> callback) { |
179 | validate(entityId, new ValidationCallback(callback, ctx -> { | 185 | validate(entityId, new ValidationCallback(callback, ctx -> { |
@@ -19,7 +19,7 @@ akka { | @@ -19,7 +19,7 @@ akka { | ||
19 | # JVM shutdown, System.exit(-1), in case of a fatal error, | 19 | # JVM shutdown, System.exit(-1), in case of a fatal error, |
20 | # such as OutOfMemoryError | 20 | # such as OutOfMemoryError |
21 | jvm-exit-on-fatal-error = off | 21 | jvm-exit-on-fatal-error = off |
22 | - loglevel = "INFO" | 22 | + loglevel = "DEBUG" |
23 | loggers = ["akka.event.slf4j.Slf4jLogger"] | 23 | loggers = ["akka.event.slf4j.Slf4jLogger"] |
24 | } | 24 | } |
25 | 25 |
@@ -30,7 +30,6 @@ import org.thingsboard.server.common.data.id.EntityId; | @@ -30,7 +30,6 @@ import org.thingsboard.server.common.data.id.EntityId; | ||
30 | import org.thingsboard.server.common.data.kv.*; | 30 | import org.thingsboard.server.common.data.kv.*; |
31 | import org.thingsboard.server.common.data.kv.DataType; | 31 | import org.thingsboard.server.common.data.kv.DataType; |
32 | import org.thingsboard.server.dao.AbstractAsyncDao; | 32 | import org.thingsboard.server.dao.AbstractAsyncDao; |
33 | -import org.thingsboard.server.dao.AbstractDao; | ||
34 | import org.thingsboard.server.dao.model.ModelConstants; | 33 | import org.thingsboard.server.dao.model.ModelConstants; |
35 | 34 | ||
36 | import javax.annotation.Nullable; | 35 | import javax.annotation.Nullable; |
@@ -40,8 +39,6 @@ import java.time.Instant; | @@ -40,8 +39,6 @@ import java.time.Instant; | ||
40 | import java.time.LocalDateTime; | 39 | import java.time.LocalDateTime; |
41 | import java.time.ZoneOffset; | 40 | import java.time.ZoneOffset; |
42 | import java.util.*; | 41 | import java.util.*; |
43 | -import java.util.concurrent.ExecutorService; | ||
44 | -import java.util.concurrent.Executors; | ||
45 | import java.util.stream.Collectors; | 42 | import java.util.stream.Collectors; |
46 | 43 | ||
47 | import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; | 44 | import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; |
@@ -64,8 +61,10 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao | @@ -64,8 +61,10 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao | ||
64 | private TsPartitionDate tsFormat; | 61 | private TsPartitionDate tsFormat; |
65 | 62 | ||
66 | private PreparedStatement partitionInsertStmt; | 63 | private PreparedStatement partitionInsertStmt; |
64 | + private PreparedStatement partitionInsertTtlStmt; | ||
67 | private PreparedStatement[] latestInsertStmts; | 65 | private PreparedStatement[] latestInsertStmts; |
68 | private PreparedStatement[] saveStmts; | 66 | private PreparedStatement[] saveStmts; |
67 | + private PreparedStatement[] saveTtlStmts; | ||
69 | private PreparedStatement[] fetchStmts; | 68 | private PreparedStatement[] fetchStmts; |
70 | private PreparedStatement findLatestStmt; | 69 | private PreparedStatement findLatestStmt; |
71 | private PreparedStatement findAllLatestStmt; | 70 | private PreparedStatement findAllLatestStmt; |
@@ -255,15 +254,32 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao | @@ -255,15 +254,32 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao | ||
255 | } | 254 | } |
256 | 255 | ||
257 | @Override | 256 | @Override |
258 | - public ResultSetFuture save(EntityId entityId, long partition, TsKvEntry tsKvEntry) { | 257 | + public ResultSetFuture save(EntityId entityId, long partition, TsKvEntry tsKvEntry, long ttl) { |
259 | DataType type = tsKvEntry.getDataType(); | 258 | DataType type = tsKvEntry.getDataType(); |
260 | - BoundStatement stmt = getSaveStmt(type).bind() | ||
261 | - .setString(0, entityId.getEntityType().name()) | 259 | + BoundStatement stmt = (ttl == 0 ? getSaveStmt(type) : getSaveTtlStmt(type)).bind(); |
260 | + stmt.setString(0, entityId.getEntityType().name()) | ||
262 | .setUUID(1, entityId.getId()) | 261 | .setUUID(1, entityId.getId()) |
263 | .setString(2, tsKvEntry.getKey()) | 262 | .setString(2, tsKvEntry.getKey()) |
264 | .setLong(3, partition) | 263 | .setLong(3, partition) |
265 | .setLong(4, tsKvEntry.getTs()); | 264 | .setLong(4, tsKvEntry.getTs()); |
266 | addValue(tsKvEntry, stmt, 5); | 265 | addValue(tsKvEntry, stmt, 5); |
266 | + if (ttl > 0) { | ||
267 | + stmt.setInt(6, (int) ttl); | ||
268 | + } | ||
269 | + return executeAsyncWrite(stmt); | ||
270 | + } | ||
271 | + | ||
272 | + @Override | ||
273 | + public ResultSetFuture savePartition(EntityId entityId, long partition, String key, long ttl) { | ||
274 | + log.debug("Saving partition {} for the entity [{}-{}] and key {}", partition, entityId.getEntityType(), entityId.getId(), key); | ||
275 | + BoundStatement stmt = (ttl == 0 ? getPartitionInsertStmt() : getPartitionInsertTtlStmt()).bind(); | ||
276 | + stmt = stmt.setString(0, entityId.getEntityType().name()) | ||
277 | + .setUUID(1, entityId.getId()) | ||
278 | + .setLong(2, partition) | ||
279 | + .setString(3, key); | ||
280 | + if (ttl > 0) { | ||
281 | + stmt.setInt(4, (int) ttl); | ||
282 | + } | ||
267 | return executeAsyncWrite(stmt); | 283 | return executeAsyncWrite(stmt); |
268 | } | 284 | } |
269 | 285 | ||
@@ -280,16 +296,6 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao | @@ -280,16 +296,6 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao | ||
280 | } | 296 | } |
281 | 297 | ||
282 | @Override | 298 | @Override |
283 | - public ResultSetFuture savePartition(EntityId entityId, long partition, String key) { | ||
284 | - log.debug("Saving partition {} for the entity [{}-{}] and key {}", partition, entityId.getEntityType(), entityId.getId(), key); | ||
285 | - return executeAsyncWrite(getPartitionInsertStmt().bind() | ||
286 | - .setString(0, entityId.getEntityType().name()) | ||
287 | - .setUUID(1, entityId.getId()) | ||
288 | - .setLong(2, partition) | ||
289 | - .setString(3, key)); | ||
290 | - } | ||
291 | - | ||
292 | - @Override | ||
293 | public List<TsKvEntry> convertResultToTsKvEntryList(List<Row> rows) { | 299 | public List<TsKvEntry> convertResultToTsKvEntryList(List<Row> rows) { |
294 | List<TsKvEntry> entries = new ArrayList<>(rows.size()); | 300 | List<TsKvEntry> entries = new ArrayList<>(rows.size()); |
295 | if (!rows.isEmpty()) { | 301 | if (!rows.isEmpty()) { |
@@ -365,6 +371,23 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao | @@ -365,6 +371,23 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao | ||
365 | return saveStmts[dataType.ordinal()]; | 371 | return saveStmts[dataType.ordinal()]; |
366 | } | 372 | } |
367 | 373 | ||
374 | + private PreparedStatement getSaveTtlStmt(DataType dataType) { | ||
375 | + if (saveTtlStmts == null) { | ||
376 | + saveTtlStmts = new PreparedStatement[DataType.values().length]; | ||
377 | + for (DataType type : DataType.values()) { | ||
378 | + saveTtlStmts[type.ordinal()] = getSession().prepare("INSERT INTO " + ModelConstants.TS_KV_CF + | ||
379 | + "(" + ModelConstants.ENTITY_TYPE_COLUMN + | ||
380 | + "," + ModelConstants.ENTITY_ID_COLUMN + | ||
381 | + "," + ModelConstants.KEY_COLUMN + | ||
382 | + "," + ModelConstants.PARTITION_COLUMN + | ||
383 | + "," + ModelConstants.TS_COLUMN + | ||
384 | + "," + getColumnName(type) + ")" + | ||
385 | + " VALUES(?, ?, ?, ?, ?, ?) USING TTL ?"); | ||
386 | + } | ||
387 | + } | ||
388 | + return saveTtlStmts[dataType.ordinal()]; | ||
389 | + } | ||
390 | + | ||
368 | private PreparedStatement getFetchStmt(Aggregation aggType) { | 391 | private PreparedStatement getFetchStmt(Aggregation aggType) { |
369 | if (fetchStmts == null) { | 392 | if (fetchStmts == null) { |
370 | fetchStmts = new PreparedStatement[Aggregation.values().length]; | 393 | fetchStmts = new PreparedStatement[Aggregation.values().length]; |
@@ -418,6 +441,19 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao | @@ -418,6 +441,19 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao | ||
418 | return partitionInsertStmt; | 441 | return partitionInsertStmt; |
419 | } | 442 | } |
420 | 443 | ||
444 | + private PreparedStatement getPartitionInsertTtlStmt() { | ||
445 | + if (partitionInsertTtlStmt == null) { | ||
446 | + partitionInsertTtlStmt = getSession().prepare("INSERT INTO " + ModelConstants.TS_KV_PARTITIONS_CF + | ||
447 | + "(" + ModelConstants.ENTITY_TYPE_COLUMN + | ||
448 | + "," + ModelConstants.ENTITY_ID_COLUMN + | ||
449 | + "," + ModelConstants.PARTITION_COLUMN + | ||
450 | + "," + ModelConstants.KEY_COLUMN + ")" + | ||
451 | + " VALUES(?, ?, ?, ?) USING TTL ?"); | ||
452 | + } | ||
453 | + return partitionInsertTtlStmt; | ||
454 | + } | ||
455 | + | ||
456 | + | ||
421 | private PreparedStatement getFindLatestStmt() { | 457 | private PreparedStatement getFindLatestStmt() { |
422 | if (findLatestStmt == null) { | 458 | if (findLatestStmt == null) { |
423 | findLatestStmt = getSession().prepare("SELECT " + | 459 | findLatestStmt = getSession().prepare("SELECT " + |
@@ -87,29 +87,33 @@ public class BaseTimeseriesService implements TimeseriesService { | @@ -87,29 +87,33 @@ public class BaseTimeseriesService implements TimeseriesService { | ||
87 | if (tsKvEntry == null) { | 87 | if (tsKvEntry == null) { |
88 | throw new IncorrectParameterException("Key value entry can't be null"); | 88 | throw new IncorrectParameterException("Key value entry can't be null"); |
89 | } | 89 | } |
90 | - UUID uid = entityId.getId(); | ||
91 | long partitionTs = timeseriesDao.toPartitionTs(tsKvEntry.getTs()); | 90 | long partitionTs = timeseriesDao.toPartitionTs(tsKvEntry.getTs()); |
92 | 91 | ||
93 | List<ResultSetFuture> futures = Lists.newArrayListWithExpectedSize(INSERTS_PER_ENTRY); | 92 | List<ResultSetFuture> futures = Lists.newArrayListWithExpectedSize(INSERTS_PER_ENTRY); |
94 | - saveAndRegisterFutures(futures, entityId, tsKvEntry, partitionTs); | 93 | + saveAndRegisterFutures(futures, entityId, tsKvEntry, partitionTs, 0L); |
95 | return Futures.allAsList(futures); | 94 | return Futures.allAsList(futures); |
96 | } | 95 | } |
97 | 96 | ||
98 | @Override | 97 | @Override |
99 | public ListenableFuture<List<ResultSet>> save(EntityId entityId, List<TsKvEntry> tsKvEntries) { | 98 | public ListenableFuture<List<ResultSet>> save(EntityId entityId, List<TsKvEntry> tsKvEntries) { |
99 | + return save(entityId, tsKvEntries, 0L); | ||
100 | + } | ||
101 | + | ||
102 | + @Override | ||
103 | + public ListenableFuture<List<ResultSet>> save(EntityId entityId, List<TsKvEntry> tsKvEntries, long ttl) { | ||
100 | validate(entityId); | 104 | validate(entityId); |
101 | List<ResultSetFuture> futures = Lists.newArrayListWithExpectedSize(tsKvEntries.size() * INSERTS_PER_ENTRY); | 105 | List<ResultSetFuture> futures = Lists.newArrayListWithExpectedSize(tsKvEntries.size() * INSERTS_PER_ENTRY); |
102 | for (TsKvEntry tsKvEntry : tsKvEntries) { | 106 | for (TsKvEntry tsKvEntry : tsKvEntries) { |
103 | if (tsKvEntry == null) { | 107 | if (tsKvEntry == null) { |
104 | throw new IncorrectParameterException("Key value entry can't be null"); | 108 | throw new IncorrectParameterException("Key value entry can't be null"); |
105 | } | 109 | } |
106 | - UUID uid = entityId.getId(); | ||
107 | long partitionTs = timeseriesDao.toPartitionTs(tsKvEntry.getTs()); | 110 | long partitionTs = timeseriesDao.toPartitionTs(tsKvEntry.getTs()); |
108 | - saveAndRegisterFutures(futures, entityId, tsKvEntry, partitionTs); | 111 | + saveAndRegisterFutures(futures, entityId, tsKvEntry, partitionTs, ttl); |
109 | } | 112 | } |
110 | return Futures.allAsList(futures); | 113 | return Futures.allAsList(futures); |
111 | } | 114 | } |
112 | 115 | ||
116 | + | ||
113 | @Override | 117 | @Override |
114 | public TsKvEntry convertResultToTsKvEntry(Row row) { | 118 | public TsKvEntry convertResultToTsKvEntry(Row row) { |
115 | return timeseriesDao.convertResultToTsKvEntry(row); | 119 | return timeseriesDao.convertResultToTsKvEntry(row); |
@@ -120,10 +124,10 @@ public class BaseTimeseriesService implements TimeseriesService { | @@ -120,10 +124,10 @@ public class BaseTimeseriesService implements TimeseriesService { | ||
120 | return timeseriesDao.convertResultToTsKvEntryList(rs.all()); | 124 | return timeseriesDao.convertResultToTsKvEntryList(rs.all()); |
121 | } | 125 | } |
122 | 126 | ||
123 | - private void saveAndRegisterFutures(List<ResultSetFuture> futures, EntityId entityId, TsKvEntry tsKvEntry, long partitionTs) { | ||
124 | - futures.add(timeseriesDao.savePartition(entityId, partitionTs, tsKvEntry.getKey())); | 127 | + private void saveAndRegisterFutures(List<ResultSetFuture> futures, EntityId entityId, TsKvEntry tsKvEntry, long partitionTs, long ttl) { |
128 | + futures.add(timeseriesDao.savePartition(entityId, partitionTs, tsKvEntry.getKey(), ttl)); | ||
125 | futures.add(timeseriesDao.saveLatest(entityId, tsKvEntry)); | 129 | futures.add(timeseriesDao.saveLatest(entityId, tsKvEntry)); |
126 | - futures.add(timeseriesDao.save(entityId, partitionTs, tsKvEntry)); | 130 | + futures.add(timeseriesDao.save(entityId, partitionTs, tsKvEntry, ttl)); |
127 | } | 131 | } |
128 | 132 | ||
129 | private static void validate(EntityId entityId) { | 133 | private static void validate(EntityId entityId) { |
@@ -23,9 +23,6 @@ import org.thingsboard.server.common.data.kv.TsKvEntry; | @@ -23,9 +23,6 @@ import org.thingsboard.server.common.data.kv.TsKvEntry; | ||
23 | import org.thingsboard.server.common.data.kv.TsKvQuery; | 23 | import org.thingsboard.server.common.data.kv.TsKvQuery; |
24 | 24 | ||
25 | import java.util.List; | 25 | import java.util.List; |
26 | -import java.util.Optional; | ||
27 | -import java.util.Set; | ||
28 | -import java.util.UUID; | ||
29 | 26 | ||
30 | /** | 27 | /** |
31 | * @author Andrew Shvayka | 28 | * @author Andrew Shvayka |
@@ -40,9 +37,9 @@ public interface TimeseriesDao { | @@ -40,9 +37,9 @@ public interface TimeseriesDao { | ||
40 | 37 | ||
41 | ResultSetFuture findAllLatest(EntityId entityId); | 38 | ResultSetFuture findAllLatest(EntityId entityId); |
42 | 39 | ||
43 | - ResultSetFuture save(EntityId entityId, long partition, TsKvEntry tsKvEntry); | 40 | + ResultSetFuture save(EntityId entityId, long partition, TsKvEntry tsKvEntry, long ttl); |
44 | 41 | ||
45 | - ResultSetFuture savePartition(EntityId entityId, long partition, String key); | 42 | + ResultSetFuture savePartition(EntityId entityId, long partition, String key, long ttl); |
46 | 43 | ||
47 | ResultSetFuture saveLatest(EntityId entityId, TsKvEntry tsKvEntry); | 44 | ResultSetFuture saveLatest(EntityId entityId, TsKvEntry tsKvEntry); |
48 | 45 |
@@ -44,6 +44,8 @@ public interface TimeseriesService { | @@ -44,6 +44,8 @@ public interface TimeseriesService { | ||
44 | 44 | ||
45 | ListenableFuture<List<ResultSet>> save(EntityId entityId, List<TsKvEntry> tsKvEntry); | 45 | ListenableFuture<List<ResultSet>> save(EntityId entityId, List<TsKvEntry> tsKvEntry); |
46 | 46 | ||
47 | + ListenableFuture<List<ResultSet>> save(EntityId entityId, List<TsKvEntry> tsKvEntry, long ttl); | ||
48 | + | ||
47 | TsKvEntry convertResultToTsKvEntry(Row row); | 49 | TsKvEntry convertResultToTsKvEntry(Row row); |
48 | 50 | ||
49 | List<TsKvEntry> convertResultSetToTsKvEntryList(ResultSet rs); | 51 | List<TsKvEntry> convertResultSetToTsKvEntryList(ResultSet rs); |
@@ -79,7 +79,9 @@ public interface PluginContext { | @@ -79,7 +79,9 @@ public interface PluginContext { | ||
79 | 79 | ||
80 | void saveTsData(EntityId entityId, TsKvEntry entry, PluginCallback<Void> callback); | 80 | void saveTsData(EntityId entityId, TsKvEntry entry, PluginCallback<Void> callback); |
81 | 81 | ||
82 | - void saveTsData(EntityId entityId, List<TsKvEntry> entry, PluginCallback<Void> callback); | 82 | + void saveTsData(EntityId entityId, List<TsKvEntry> entries, PluginCallback<Void> callback); |
83 | + | ||
84 | + void saveTsData(EntityId deviceId, List<TsKvEntry> entries, long ttl, PluginCallback<Void> pluginCallback); | ||
83 | 85 | ||
84 | void loadTimeseries(EntityId entityId, List<TsKvQuery> queries, PluginCallback<List<TsKvEntry>> callback); | 86 | void loadTimeseries(EntityId entityId, List<TsKvQuery> queries, PluginCallback<List<TsKvEntry>> callback); |
85 | 87 | ||
@@ -106,4 +108,5 @@ public interface PluginContext { | @@ -106,4 +108,5 @@ public interface PluginContext { | ||
106 | void loadAttributes(EntityId entityId, Collection<String> attributeTypes, Collection<String> attributeKeys, PluginCallback<List<AttributeKvEntry>> callback); | 108 | void loadAttributes(EntityId entityId, Collection<String> attributeTypes, Collection<String> attributeKeys, PluginCallback<List<AttributeKvEntry>> callback); |
107 | 109 | ||
108 | void getCustomerDevices(TenantId tenantId, CustomerId customerId, int limit, PluginCallback<List<Device>> callback); | 110 | void getCustomerDevices(TenantId tenantId, CustomerId customerId, int limit, PluginCallback<List<Device>> callback); |
111 | + | ||
109 | } | 112 | } |
@@ -23,9 +23,14 @@ import org.thingsboard.server.common.msg.core.TelemetryUploadRequest; | @@ -23,9 +23,14 @@ import org.thingsboard.server.common.msg.core.TelemetryUploadRequest; | ||
23 | public class TelemetryUploadRequestRuleToPluginMsg extends AbstractRuleToPluginMsg<TelemetryUploadRequest> { | 23 | public class TelemetryUploadRequestRuleToPluginMsg extends AbstractRuleToPluginMsg<TelemetryUploadRequest> { |
24 | 24 | ||
25 | private static final long serialVersionUID = 1L; | 25 | private static final long serialVersionUID = 1L; |
26 | + private final long ttl; | ||
26 | 27 | ||
27 | - public TelemetryUploadRequestRuleToPluginMsg(TenantId tenantId, CustomerId customerId, DeviceId deviceId, TelemetryUploadRequest payload) { | 28 | + public TelemetryUploadRequestRuleToPluginMsg(TenantId tenantId, CustomerId customerId, DeviceId deviceId, TelemetryUploadRequest payload, long ttl) { |
28 | super(tenantId, customerId, deviceId, payload); | 29 | super(tenantId, customerId, deviceId, payload); |
30 | + this.ttl = ttl; | ||
29 | } | 31 | } |
30 | 32 | ||
33 | + public long getTtl() { | ||
34 | + return ttl; | ||
35 | + } | ||
31 | } | 36 | } |
@@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.extensions.core.action.telemetry; | 16 | package org.thingsboard.server.extensions.core.action.telemetry; |
17 | 17 | ||
18 | +import org.springframework.util.StringUtils; | ||
18 | import org.thingsboard.server.common.msg.core.GetAttributesRequest; | 19 | import org.thingsboard.server.common.msg.core.GetAttributesRequest; |
19 | import org.thingsboard.server.common.msg.core.TelemetryUploadRequest; | 20 | import org.thingsboard.server.common.msg.core.TelemetryUploadRequest; |
20 | import org.thingsboard.server.common.msg.core.UpdateAttributesRequest; | 21 | import org.thingsboard.server.common.msg.core.UpdateAttributesRequest; |
@@ -23,7 +24,6 @@ import org.thingsboard.server.common.msg.session.FromDeviceMsg; | @@ -23,7 +24,6 @@ import org.thingsboard.server.common.msg.session.FromDeviceMsg; | ||
23 | import org.thingsboard.server.common.msg.session.MsgType; | 24 | import org.thingsboard.server.common.msg.session.MsgType; |
24 | import org.thingsboard.server.common.msg.session.ToDeviceMsg; | 25 | import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
25 | import org.thingsboard.server.extensions.api.component.Action; | 26 | import org.thingsboard.server.extensions.api.component.Action; |
26 | -import org.thingsboard.server.extensions.api.component.EmptyComponentConfiguration; | ||
27 | import org.thingsboard.server.extensions.api.plugins.PluginAction; | 27 | import org.thingsboard.server.extensions.api.plugins.PluginAction; |
28 | import org.thingsboard.server.extensions.api.plugins.msg.*; | 28 | import org.thingsboard.server.extensions.api.plugins.msg.*; |
29 | import org.thingsboard.server.extensions.api.rules.RuleContext; | 29 | import org.thingsboard.server.extensions.api.rules.RuleContext; |
@@ -31,11 +31,22 @@ import org.thingsboard.server.extensions.api.rules.RuleProcessingMetaData; | @@ -31,11 +31,22 @@ import org.thingsboard.server.extensions.api.rules.RuleProcessingMetaData; | ||
31 | import org.thingsboard.server.extensions.api.rules.SimpleRuleLifecycleComponent; | 31 | import org.thingsboard.server.extensions.api.rules.SimpleRuleLifecycleComponent; |
32 | 32 | ||
33 | import java.util.Optional; | 33 | import java.util.Optional; |
34 | +import java.util.concurrent.TimeUnit; | ||
34 | 35 | ||
35 | -@Action(name = "Telemetry Plugin Action") | ||
36 | -public class TelemetryPluginAction extends SimpleRuleLifecycleComponent implements PluginAction<EmptyComponentConfiguration> { | 36 | +@Action(name = "Telemetry Plugin Action", descriptor = "TelemetryPluginActionDescriptor.json", configuration = TelemetryPluginActionConfiguration.class) |
37 | +public class TelemetryPluginAction extends SimpleRuleLifecycleComponent implements PluginAction<TelemetryPluginActionConfiguration> { | ||
37 | 38 | ||
38 | - public void init(EmptyComponentConfiguration configuration) { | 39 | + protected TelemetryPluginActionConfiguration configuration; |
40 | + protected long ttl; | ||
41 | + | ||
42 | + @Override | ||
43 | + public void init(TelemetryPluginActionConfiguration configuration) { | ||
44 | + this.configuration = configuration; | ||
45 | + if (StringUtils.isEmpty(configuration.getTimeUnit()) || configuration.getTtlValue() == 0L) { | ||
46 | + this.ttl = 0L; | ||
47 | + } else { | ||
48 | + this.ttl = TimeUnit.valueOf(configuration.getTimeUnit()).toSeconds(configuration.getTtlValue()); | ||
49 | + } | ||
39 | } | 50 | } |
40 | 51 | ||
41 | @Override | 52 | @Override |
@@ -44,7 +55,7 @@ public class TelemetryPluginAction extends SimpleRuleLifecycleComponent implemen | @@ -44,7 +55,7 @@ public class TelemetryPluginAction extends SimpleRuleLifecycleComponent implemen | ||
44 | if (msg.getMsgType() == MsgType.POST_TELEMETRY_REQUEST) { | 55 | if (msg.getMsgType() == MsgType.POST_TELEMETRY_REQUEST) { |
45 | TelemetryUploadRequest payload = (TelemetryUploadRequest) msg; | 56 | TelemetryUploadRequest payload = (TelemetryUploadRequest) msg; |
46 | return Optional.of(new TelemetryUploadRequestRuleToPluginMsg(toDeviceActorMsg.getTenantId(), toDeviceActorMsg.getCustomerId(), | 57 | return Optional.of(new TelemetryUploadRequestRuleToPluginMsg(toDeviceActorMsg.getTenantId(), toDeviceActorMsg.getCustomerId(), |
47 | - toDeviceActorMsg.getDeviceId(), payload)); | 58 | + toDeviceActorMsg.getDeviceId(), payload, ttl)); |
48 | } else if (msg.getMsgType() == MsgType.POST_ATTRIBUTES_REQUEST) { | 59 | } else if (msg.getMsgType() == MsgType.POST_ATTRIBUTES_REQUEST) { |
49 | UpdateAttributesRequest payload = (UpdateAttributesRequest) msg; | 60 | UpdateAttributesRequest payload = (UpdateAttributesRequest) msg; |
50 | return Optional.of(new UpdateAttributesRequestRuleToPluginMsg(toDeviceActorMsg.getTenantId(), toDeviceActorMsg.getCustomerId(), | 61 | return Optional.of(new UpdateAttributesRequestRuleToPluginMsg(toDeviceActorMsg.getTenantId(), toDeviceActorMsg.getCustomerId(), |
1 | +/** | ||
2 | + * Copyright © 2016-2017 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.extensions.core.action.telemetry; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonInclude; | ||
19 | +import lombok.Data; | ||
20 | + | ||
21 | +/** | ||
22 | + * @author Andrew Shvayka | ||
23 | + */ | ||
24 | +@Data | ||
25 | +@JsonInclude(JsonInclude.Include.NON_NULL) | ||
26 | +public class TelemetryPluginActionConfiguration { | ||
27 | + | ||
28 | + private String timeUnit; | ||
29 | + private int ttlValue; | ||
30 | + | ||
31 | +} |
@@ -148,6 +148,7 @@ public class TelemetryRestMsgHandler extends DefaultRestMsgHandler { | @@ -148,6 +148,7 @@ public class TelemetryRestMsgHandler extends DefaultRestMsgHandler { | ||
148 | String[] pathParams = request.getPathParams(); | 148 | String[] pathParams = request.getPathParams(); |
149 | EntityId entityId; | 149 | EntityId entityId; |
150 | String scope; | 150 | String scope; |
151 | + long ttl = 0L; | ||
151 | TelemetryFeature feature; | 152 | TelemetryFeature feature; |
152 | if (pathParams.length == 2) { | 153 | if (pathParams.length == 2) { |
153 | entityId = DeviceId.fromString(pathParams[0]); | 154 | entityId = DeviceId.fromString(pathParams[0]); |
@@ -161,6 +162,11 @@ public class TelemetryRestMsgHandler extends DefaultRestMsgHandler { | @@ -161,6 +162,11 @@ public class TelemetryRestMsgHandler extends DefaultRestMsgHandler { | ||
161 | entityId = EntityIdFactory.getByTypeAndId(pathParams[0], pathParams[1]); | 162 | entityId = EntityIdFactory.getByTypeAndId(pathParams[0], pathParams[1]); |
162 | feature = TelemetryFeature.forName(pathParams[2].toUpperCase()); | 163 | feature = TelemetryFeature.forName(pathParams[2].toUpperCase()); |
163 | scope = pathParams[3]; | 164 | scope = pathParams[3]; |
165 | + } else if (pathParams.length == 5) { | ||
166 | + entityId = EntityIdFactory.getByTypeAndId(pathParams[0], pathParams[1]); | ||
167 | + feature = TelemetryFeature.forName(pathParams[2].toUpperCase()); | ||
168 | + scope = pathParams[3]; | ||
169 | + ttl = Long.parseLong(pathParams[4]); | ||
164 | } else { | 170 | } else { |
165 | msg.getResponseHolder().setResult(new ResponseEntity<>(HttpStatus.BAD_REQUEST)); | 171 | msg.getResponseHolder().setResult(new ResponseEntity<>(HttpStatus.BAD_REQUEST)); |
166 | return; | 172 | return; |
@@ -211,7 +217,7 @@ public class TelemetryRestMsgHandler extends DefaultRestMsgHandler { | @@ -211,7 +217,7 @@ public class TelemetryRestMsgHandler extends DefaultRestMsgHandler { | ||
211 | entries.add(new BasicTsKvEntry(entry.getKey(), kv)); | 217 | entries.add(new BasicTsKvEntry(entry.getKey(), kv)); |
212 | } | 218 | } |
213 | } | 219 | } |
214 | - ctx.saveTsData(entityId, entries, new PluginCallback<Void>() { | 220 | + ctx.saveTsData(entityId, entries, ttl, new PluginCallback<Void>() { |
215 | @Override | 221 | @Override |
216 | public void onSuccess(PluginContext ctx, Void value) { | 222 | public void onSuccess(PluginContext ctx, Void value) { |
217 | msg.getResponseHolder().setResult(new ResponseEntity<>(HttpStatus.OK)); | 223 | msg.getResponseHolder().setResult(new ResponseEntity<>(HttpStatus.OK)); |
@@ -92,7 +92,7 @@ public class TelemetryRuleMsgHandler extends DefaultRuleMsgHandler { | @@ -92,7 +92,7 @@ public class TelemetryRuleMsgHandler extends DefaultRuleMsgHandler { | ||
92 | tsKvEntries.add(new BasicTsKvEntry(entry.getKey(), kv)); | 92 | tsKvEntries.add(new BasicTsKvEntry(entry.getKey(), kv)); |
93 | } | 93 | } |
94 | } | 94 | } |
95 | - ctx.saveTsData(msg.getDeviceId(), tsKvEntries, new PluginCallback<Void>() { | 95 | + ctx.saveTsData(msg.getDeviceId(), tsKvEntries, msg.getTtl(), new PluginCallback<Void>() { |
96 | @Override | 96 | @Override |
97 | public void onSuccess(PluginContext ctx, Void data) { | 97 | public void onSuccess(PluginContext ctx, Void data) { |
98 | ctx.reply(new ResponsePluginToRuleMsg(msg.getUid(), tenantId, ruleId, BasicStatusCodeResponse.onSuccess(request.getMsgType(), request.getRequestId()))); | 98 | ctx.reply(new ResponsePluginToRuleMsg(msg.getUid(), tenantId, ruleId, BasicStatusCodeResponse.onSuccess(request.getMsgType(), request.getRequestId()))); |
1 | +{ | ||
2 | + "schema": { | ||
3 | + "title": "Telemetry Plugin Action Configuration", | ||
4 | + "type": "object", | ||
5 | + "properties": { | ||
6 | + "timeUnit": { | ||
7 | + "title": "Time Unit", | ||
8 | + "type": "string", | ||
9 | + "default": "DAYS" | ||
10 | + }, | ||
11 | + "ttlValue": { | ||
12 | + "title": "TTL", | ||
13 | + "type": "integer", | ||
14 | + "default": 365, | ||
15 | + "minimum": 0, | ||
16 | + "maximum": 100000 | ||
17 | + } | ||
18 | + }, | ||
19 | + "required": [ | ||
20 | + "timeUnit", | ||
21 | + "ttlValue" | ||
22 | + ] | ||
23 | + }, | ||
24 | + "form": [ | ||
25 | + { | ||
26 | + "key": "timeUnit", | ||
27 | + "type": "rc-select", | ||
28 | + "multiple": false, | ||
29 | + "items": [ | ||
30 | + { | ||
31 | + "value": "SECONDS", | ||
32 | + "label": "Seconds" | ||
33 | + }, | ||
34 | + { | ||
35 | + "value": "MINUTES", | ||
36 | + "label": "Minutes" | ||
37 | + }, | ||
38 | + { | ||
39 | + "value": "HOURS", | ||
40 | + "label": "Hours" | ||
41 | + }, | ||
42 | + { | ||
43 | + "value": "DAYS", | ||
44 | + "label": "Days" | ||
45 | + } | ||
46 | + ] | ||
47 | + }, | ||
48 | + "ttlValue" | ||
49 | + ] | ||
50 | +} |