...
|
...
|
@@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.query.BooleanFilterPredicate; |
31
|
31
|
import org.thingsboard.server.common.data.query.ComplexFilterPredicate;
|
32
|
32
|
import org.thingsboard.server.common.data.query.EntityKey;
|
33
|
33
|
import org.thingsboard.server.common.data.query.EntityKeyType;
|
|
34
|
+import org.thingsboard.server.common.data.query.FilterPredicateValue;
|
34
|
35
|
import org.thingsboard.server.common.data.query.KeyFilter;
|
35
|
36
|
import org.thingsboard.server.common.data.query.KeyFilterPredicate;
|
36
|
37
|
import org.thingsboard.server.common.data.query.NumericFilterPredicate;
|
...
|
...
|
@@ -41,6 +42,7 @@ import java.time.Instant; |
41
|
42
|
import java.time.ZoneId;
|
42
|
43
|
import java.time.ZonedDateTime;
|
43
|
44
|
import java.util.Set;
|
|
45
|
+import java.util.function.Function;
|
44
|
46
|
|
45
|
47
|
@Data
|
46
|
48
|
class AlarmRuleState {
|
...
|
...
|
@@ -246,38 +248,38 @@ class AlarmRuleState { |
246
|
248
|
if (value == null) {
|
247
|
249
|
return false;
|
248
|
250
|
}
|
249
|
|
- eval = eval && eval(value, keyFilter.getPredicate());
|
|
251
|
+ eval = eval && eval(data, value, keyFilter.getPredicate());
|
250
|
252
|
}
|
251
|
253
|
return eval;
|
252
|
254
|
}
|
253
|
255
|
|
254
|
|
- private boolean eval(EntityKeyValue value, KeyFilterPredicate predicate) {
|
|
256
|
+ private boolean eval(DataSnapshot data, EntityKeyValue value, KeyFilterPredicate predicate) {
|
255
|
257
|
switch (predicate.getType()) {
|
256
|
258
|
case STRING:
|
257
|
|
- return evalStrPredicate(value, (StringFilterPredicate) predicate);
|
|
259
|
+ return evalStrPredicate(data, value, (StringFilterPredicate) predicate);
|
258
|
260
|
case NUMERIC:
|
259
|
|
- return evalNumPredicate(value, (NumericFilterPredicate) predicate);
|
260
|
|
- case COMPLEX:
|
261
|
|
- return evalComplexPredicate(value, (ComplexFilterPredicate) predicate);
|
|
261
|
+ return evalNumPredicate(data, value, (NumericFilterPredicate) predicate);
|
262
|
262
|
case BOOLEAN:
|
263
|
|
- return evalBoolPredicate(value, (BooleanFilterPredicate) predicate);
|
|
263
|
+ return evalBoolPredicate(data, value, (BooleanFilterPredicate) predicate);
|
|
264
|
+ case COMPLEX:
|
|
265
|
+ return evalComplexPredicate(data, value, (ComplexFilterPredicate) predicate);
|
264
|
266
|
default:
|
265
|
267
|
return false;
|
266
|
268
|
}
|
267
|
269
|
}
|
268
|
270
|
|
269
|
|
- private boolean evalComplexPredicate(EntityKeyValue ekv, ComplexFilterPredicate predicate) {
|
|
271
|
+ private boolean evalComplexPredicate(DataSnapshot data, EntityKeyValue ekv, ComplexFilterPredicate predicate) {
|
270
|
272
|
switch (predicate.getOperation()) {
|
271
|
273
|
case OR:
|
272
|
274
|
for (KeyFilterPredicate kfp : predicate.getPredicates()) {
|
273
|
|
- if (eval(ekv, kfp)) {
|
|
275
|
+ if (eval(data, ekv, kfp)) {
|
274
|
276
|
return true;
|
275
|
277
|
}
|
276
|
278
|
}
|
277
|
279
|
return false;
|
278
|
280
|
case AND:
|
279
|
281
|
for (KeyFilterPredicate kfp : predicate.getPredicates()) {
|
280
|
|
- if (!eval(ekv, kfp)) {
|
|
282
|
+ if (!eval(data, ekv, kfp)) {
|
281
|
283
|
return false;
|
282
|
284
|
}
|
283
|
285
|
}
|
...
|
...
|
@@ -287,109 +289,55 @@ class AlarmRuleState { |
287
|
289
|
}
|
288
|
290
|
}
|
289
|
291
|
|
290
|
|
- private boolean evalBoolPredicate(EntityKeyValue ekv, BooleanFilterPredicate predicate) {
|
291
|
|
- Boolean value;
|
292
|
|
- switch (ekv.getDataType()) {
|
293
|
|
- case LONG:
|
294
|
|
- value = ekv.getLngValue() > 0;
|
295
|
|
- break;
|
296
|
|
- case DOUBLE:
|
297
|
|
- value = ekv.getDblValue() > 0;
|
298
|
|
- break;
|
299
|
|
- case BOOLEAN:
|
300
|
|
- value = ekv.getBoolValue();
|
301
|
|
- break;
|
302
|
|
- case STRING:
|
303
|
|
- try {
|
304
|
|
- value = Boolean.parseBoolean(ekv.getStrValue());
|
305
|
|
- break;
|
306
|
|
- } catch (RuntimeException e) {
|
307
|
|
- return false;
|
308
|
|
- }
|
309
|
|
- case JSON:
|
310
|
|
- try {
|
311
|
|
- value = Boolean.parseBoolean(ekv.getJsonValue());
|
312
|
|
- break;
|
313
|
|
- } catch (RuntimeException e) {
|
314
|
|
- return false;
|
315
|
|
- }
|
316
|
|
- default:
|
317
|
|
- return false;
|
318
|
|
- }
|
319
|
|
- if (value == null) {
|
|
292
|
+ private boolean evalBoolPredicate(DataSnapshot data, EntityKeyValue ekv, BooleanFilterPredicate predicate) {
|
|
293
|
+ Boolean val = getBoolValue(ekv);
|
|
294
|
+ if (val == null) {
|
320
|
295
|
return false;
|
321
|
296
|
}
|
|
297
|
+ Boolean predicateValue = getPredicateValue(data, predicate.getValue(), AlarmRuleState::getBoolValue);
|
322
|
298
|
switch (predicate.getOperation()) {
|
323
|
299
|
case EQUAL:
|
324
|
|
- return value.equals(predicate.getValue().getDefaultValue());
|
|
300
|
+ return val.equals(predicateValue);
|
325
|
301
|
case NOT_EQUAL:
|
326
|
|
- return !value.equals(predicate.getValue().getDefaultValue());
|
|
302
|
+ return !val.equals(predicateValue);
|
327
|
303
|
default:
|
328
|
304
|
throw new RuntimeException("Operation not supported: " + predicate.getOperation());
|
329
|
305
|
}
|
330
|
306
|
}
|
331
|
307
|
|
332
|
|
- private boolean evalNumPredicate(EntityKeyValue ekv, NumericFilterPredicate predicate) {
|
333
|
|
- Double value;
|
334
|
|
- switch (ekv.getDataType()) {
|
335
|
|
- case LONG:
|
336
|
|
- value = ekv.getLngValue().doubleValue();
|
337
|
|
- break;
|
338
|
|
- case DOUBLE:
|
339
|
|
- value = ekv.getDblValue();
|
340
|
|
- break;
|
341
|
|
- case BOOLEAN:
|
342
|
|
- value = ekv.getBoolValue() ? 1.0 : 0.0;
|
343
|
|
- break;
|
344
|
|
- case STRING:
|
345
|
|
- try {
|
346
|
|
- value = Double.parseDouble(ekv.getStrValue());
|
347
|
|
- break;
|
348
|
|
- } catch (RuntimeException e) {
|
349
|
|
- return false;
|
350
|
|
- }
|
351
|
|
- case JSON:
|
352
|
|
- try {
|
353
|
|
- value = Double.parseDouble(ekv.getJsonValue());
|
354
|
|
- break;
|
355
|
|
- } catch (RuntimeException e) {
|
356
|
|
- return false;
|
357
|
|
- }
|
358
|
|
- default:
|
359
|
|
- return false;
|
360
|
|
- }
|
361
|
|
- if (value == null) {
|
|
308
|
+ private boolean evalNumPredicate(DataSnapshot data, EntityKeyValue ekv, NumericFilterPredicate predicate) {
|
|
309
|
+ Double val = getDblValue(ekv);
|
|
310
|
+ if (val == null) {
|
362
|
311
|
return false;
|
363
|
312
|
}
|
364
|
|
-
|
365
|
|
- Double predicateValue = predicate.getValue().getDefaultValue();
|
|
313
|
+ Double predicateValue = getPredicateValue(data, predicate.getValue(), AlarmRuleState::getDblValue);
|
366
|
314
|
switch (predicate.getOperation()) {
|
367
|
315
|
case NOT_EQUAL:
|
368
|
|
- return !value.equals(predicateValue);
|
|
316
|
+ return !val.equals(predicateValue);
|
369
|
317
|
case EQUAL:
|
370
|
|
- return value.equals(predicateValue);
|
|
318
|
+ return val.equals(predicateValue);
|
371
|
319
|
case GREATER:
|
372
|
|
- return value > predicateValue;
|
|
320
|
+ return val > predicateValue;
|
373
|
321
|
case GREATER_OR_EQUAL:
|
374
|
|
- return value >= predicateValue;
|
|
322
|
+ return val >= predicateValue;
|
375
|
323
|
case LESS:
|
376
|
|
- return value < predicateValue;
|
|
324
|
+ return val < predicateValue;
|
377
|
325
|
case LESS_OR_EQUAL:
|
378
|
|
- return value <= predicateValue;
|
|
326
|
+ return val <= predicateValue;
|
379
|
327
|
default:
|
380
|
328
|
throw new RuntimeException("Operation not supported: " + predicate.getOperation());
|
381
|
329
|
}
|
382
|
330
|
}
|
383
|
331
|
|
384
|
|
- private boolean evalStrPredicate(EntityKeyValue ekv, StringFilterPredicate predicate) {
|
385
|
|
- String val;
|
386
|
|
- String predicateValue;
|
|
332
|
+ private boolean evalStrPredicate(DataSnapshot data, EntityKeyValue ekv, StringFilterPredicate predicate) {
|
|
333
|
+ String val = getStrValue(ekv);
|
|
334
|
+ if (val == null) {
|
|
335
|
+ return false;
|
|
336
|
+ }
|
|
337
|
+ String predicateValue = getPredicateValue(data, predicate.getValue(), AlarmRuleState::getStrValue);
|
387
|
338
|
if (predicate.isIgnoreCase()) {
|
388
|
|
- val = ekv.getStrValue().toLowerCase();
|
389
|
|
- predicateValue = predicate.getValue().getDefaultValue().toLowerCase();
|
390
|
|
- } else {
|
391
|
|
- val = ekv.getStrValue();
|
392
|
|
- predicateValue = predicate.getValue().getDefaultValue();
|
|
339
|
+ val = val.toLowerCase();
|
|
340
|
+ predicateValue = predicateValue.toLowerCase();
|
393
|
341
|
}
|
394
|
342
|
switch (predicate.getOperation()) {
|
395
|
343
|
case CONTAINS:
|
...
|
...
|
@@ -409,4 +357,99 @@ class AlarmRuleState { |
409
|
357
|
}
|
410
|
358
|
}
|
411
|
359
|
|
|
360
|
+ private <T> T getPredicateValue(DataSnapshot data, FilterPredicateValue<T> value, Function<EntityKeyValue, T> transformFunction) {
|
|
361
|
+ EntityKeyValue ekv = getDynamicPredicateValue(data, value);
|
|
362
|
+ if (ekv != null) {
|
|
363
|
+ T result = transformFunction.apply(ekv);
|
|
364
|
+ if (result != null) {
|
|
365
|
+ return result;
|
|
366
|
+ }
|
|
367
|
+ }
|
|
368
|
+ return value.getDefaultValue();
|
|
369
|
+ }
|
|
370
|
+
|
|
371
|
+ private <T> EntityKeyValue getDynamicPredicateValue(DataSnapshot data, FilterPredicateValue<T> value) {
|
|
372
|
+ EntityKeyValue ekv = null;
|
|
373
|
+ if (value.getDynamicValue() != null) {
|
|
374
|
+ ekv = data.getValue(new EntityKey(EntityKeyType.ATTRIBUTE, value.getDynamicValue().getSourceAttribute()));
|
|
375
|
+ if (ekv == null) {
|
|
376
|
+ ekv = data.getValue(new EntityKey(EntityKeyType.SERVER_ATTRIBUTE, value.getDynamicValue().getSourceAttribute()));
|
|
377
|
+ if (ekv == null) {
|
|
378
|
+ ekv = data.getValue(new EntityKey(EntityKeyType.SHARED_ATTRIBUTE, value.getDynamicValue().getSourceAttribute()));
|
|
379
|
+ if (ekv == null) {
|
|
380
|
+ ekv = data.getValue(new EntityKey(EntityKeyType.CLIENT_ATTRIBUTE, value.getDynamicValue().getSourceAttribute()));
|
|
381
|
+ }
|
|
382
|
+ }
|
|
383
|
+ }
|
|
384
|
+ }
|
|
385
|
+ return ekv;
|
|
386
|
+ }
|
|
387
|
+
|
|
388
|
+ private static String getStrValue(EntityKeyValue ekv) {
|
|
389
|
+ switch (ekv.getDataType()) {
|
|
390
|
+ case LONG:
|
|
391
|
+ return ekv.getLngValue() != null ? ekv.getLngValue().toString() : null;
|
|
392
|
+ case DOUBLE:
|
|
393
|
+ return ekv.getDblValue() != null ? ekv.getDblValue().toString() : null;
|
|
394
|
+ case BOOLEAN:
|
|
395
|
+ return ekv.getBoolValue() != null ? ekv.getBoolValue().toString() : null;
|
|
396
|
+ case STRING:
|
|
397
|
+ return ekv.getStrValue();
|
|
398
|
+ case JSON:
|
|
399
|
+ return ekv.getJsonValue();
|
|
400
|
+ default:
|
|
401
|
+ return null;
|
|
402
|
+ }
|
|
403
|
+ }
|
|
404
|
+
|
|
405
|
+ private static Double getDblValue(EntityKeyValue ekv) {
|
|
406
|
+ switch (ekv.getDataType()) {
|
|
407
|
+ case LONG:
|
|
408
|
+ return ekv.getLngValue() != null ? ekv.getLngValue().doubleValue() : null;
|
|
409
|
+ case DOUBLE:
|
|
410
|
+ return ekv.getDblValue() != null ? ekv.getDblValue() : null;
|
|
411
|
+ case BOOLEAN:
|
|
412
|
+ return ekv.getBoolValue() != null ? (ekv.getBoolValue() ? 1.0 : 0.0) : null;
|
|
413
|
+ case STRING:
|
|
414
|
+ try {
|
|
415
|
+ return Double.parseDouble(ekv.getStrValue());
|
|
416
|
+ } catch (RuntimeException e) {
|
|
417
|
+ return null;
|
|
418
|
+ }
|
|
419
|
+ case JSON:
|
|
420
|
+ try {
|
|
421
|
+ return Double.parseDouble(ekv.getJsonValue());
|
|
422
|
+ } catch (RuntimeException e) {
|
|
423
|
+ return null;
|
|
424
|
+ }
|
|
425
|
+ default:
|
|
426
|
+ return null;
|
|
427
|
+ }
|
|
428
|
+ }
|
|
429
|
+
|
|
430
|
+ private static Boolean getBoolValue(EntityKeyValue ekv) {
|
|
431
|
+ switch (ekv.getDataType()) {
|
|
432
|
+ case LONG:
|
|
433
|
+ return ekv.getLngValue() != null ? ekv.getLngValue() > 0 : null;
|
|
434
|
+ case DOUBLE:
|
|
435
|
+ return ekv.getDblValue() != null ? ekv.getDblValue() > 0 : null;
|
|
436
|
+ case BOOLEAN:
|
|
437
|
+ return ekv.getBoolValue();
|
|
438
|
+ case STRING:
|
|
439
|
+ try {
|
|
440
|
+ return Boolean.parseBoolean(ekv.getStrValue());
|
|
441
|
+ } catch (RuntimeException e) {
|
|
442
|
+ return null;
|
|
443
|
+ }
|
|
444
|
+ case JSON:
|
|
445
|
+ try {
|
|
446
|
+ return Boolean.parseBoolean(ekv.getJsonValue());
|
|
447
|
+ } catch (RuntimeException e) {
|
|
448
|
+ return null;
|
|
449
|
+ }
|
|
450
|
+ default:
|
|
451
|
+ return null;
|
|
452
|
+ }
|
|
453
|
+ }
|
|
454
|
+
|
412
|
455
|
} |
...
|
...
|
|