aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar/handler/FilterHandler.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/traccar/handler/FilterHandler.java')
-rw-r--r--src/main/java/org/traccar/handler/FilterHandler.java158
1 files changed, 110 insertions, 48 deletions
diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java
index e576a26b8..a15d3ffad 100644
--- a/src/main/java/org/traccar/handler/FilterHandler.java
+++ b/src/main/java/org/traccar/handler/FilterHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2014 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,51 +16,90 @@
package org.traccar.handler;
import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.BaseDataHandler;
-import org.traccar.Context;
import org.traccar.config.Config;
import org.traccar.config.Keys;
+import org.traccar.database.StatisticsManager;
import org.traccar.helper.UnitsConverter;
+import org.traccar.helper.model.AttributeUtil;
+import org.traccar.model.Calendar;
+import org.traccar.model.Device;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.storage.Storage;
import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Order;
+import org.traccar.storage.query.Request;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
import java.util.Date;
+@Singleton
@ChannelHandler.Sharable
-public class FilterHandler extends BaseDataHandler {
+public class FilterHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(FilterHandler.class);
- private boolean filterInvalid;
- private boolean filterZero;
- private boolean filterDuplicate;
- private long filterFuture;
- private boolean filterApproximate;
- private int filterAccuracy;
- private boolean filterStatic;
- private int filterDistance;
- private int filterMaxSpeed;
- private long filterMinPeriod;
- private boolean filterRelative;
- private long skipLimit;
- private boolean skipAttributes;
-
- public FilterHandler(Config config) {
+ private final boolean enabled;
+ private final boolean filterInvalid;
+ private final boolean filterZero;
+ private final boolean filterDuplicate;
+ private final boolean filterOutdated;
+ private final long filterFuture;
+ private final long filterPast;
+ private final boolean filterApproximate;
+ private final int filterAccuracy;
+ private final boolean filterStatic;
+ private final int filterDistance;
+ private final int filterMaxSpeed;
+ private final long filterMinPeriod;
+ private final int filterDailyLimit;
+ private final boolean filterRelative;
+ private final long skipLimit;
+ private final boolean skipAttributes;
+
+ private final CacheManager cacheManager;
+ private final Storage storage;
+ private final StatisticsManager statisticsManager;
+
+ @Inject
+ public FilterHandler(
+ Config config, CacheManager cacheManager, Storage storage, StatisticsManager statisticsManager) {
+ enabled = config.getBoolean(Keys.FILTER_ENABLE);
filterInvalid = config.getBoolean(Keys.FILTER_INVALID);
filterZero = config.getBoolean(Keys.FILTER_ZERO);
filterDuplicate = config.getBoolean(Keys.FILTER_DUPLICATE);
+ filterOutdated = config.getBoolean(Keys.FILTER_OUTDATED);
filterFuture = config.getLong(Keys.FILTER_FUTURE) * 1000;
+ filterPast = config.getLong(Keys.FILTER_PAST) * 1000;
filterAccuracy = config.getInteger(Keys.FILTER_ACCURACY);
filterApproximate = config.getBoolean(Keys.FILTER_APPROXIMATE);
filterStatic = config.getBoolean(Keys.FILTER_STATIC);
filterDistance = config.getInteger(Keys.FILTER_DISTANCE);
filterMaxSpeed = config.getInteger(Keys.FILTER_MAX_SPEED);
- filterMinPeriod = config.getInteger(Keys.FILTER_MIN_PERIOD) * 1000;
+ filterMinPeriod = config.getInteger(Keys.FILTER_MIN_PERIOD) * 1000L;
+ filterDailyLimit = config.getInteger(Keys.FILTER_DAILY_LIMIT);
filterRelative = config.getBoolean(Keys.FILTER_RELATIVE);
skipLimit = config.getLong(Keys.FILTER_SKIP_LIMIT) * 1000;
skipAttributes = config.getBoolean(Keys.FILTER_SKIP_ATTRIBUTES_ENABLE);
+ this.cacheManager = cacheManager;
+ this.storage = storage;
+ this.statisticsManager = statisticsManager;
+ }
+
+ private Position getPrecedingPosition(long deviceId, Date date) throws StorageException {
+ return storage.getObject(Position.class, new Request(
+ new Columns.All(),
+ new Condition.And(
+ new Condition.Equals("deviceId", deviceId),
+ new Condition.Compare("fixTime", "<=", "time", date)),
+ new Order("fixTime", true, 1)));
}
private boolean filterInvalid(Position position) {
@@ -76,7 +115,7 @@ public class FilterHandler extends BaseDataHandler {
private boolean filterDuplicate(Position position, Position last) {
if (filterDuplicate && last != null && position.getFixTime().equals(last.getFixTime())) {
for (String key : position.getAttributes().keySet()) {
- if (!last.getAttributes().containsKey(key)) {
+ if (!last.hasAttribute(key)) {
return false;
}
}
@@ -85,10 +124,18 @@ public class FilterHandler extends BaseDataHandler {
return false;
}
+ private boolean filterOutdated(Position position) {
+ return filterOutdated && position.getOutdated();
+ }
+
private boolean filterFuture(Position position) {
return filterFuture != 0 && position.getFixTime().getTime() > System.currentTimeMillis() + filterFuture;
}
+ private boolean filterPast(Position position) {
+ return filterPast != 0 && position.getFixTime().getTime() < System.currentTimeMillis() - filterPast;
+ }
+
private boolean filterAccuracy(Position position) {
return filterAccuracy != 0 && position.getAccuracy() > filterAccuracy;
}
@@ -125,6 +172,13 @@ public class FilterHandler extends BaseDataHandler {
return false;
}
+ private boolean filterDailyLimit(Position position) {
+ if (filterDailyLimit != 0) {
+ return statisticsManager.messageStoredCount(position.getDeviceId()) >= filterDailyLimit;
+ }
+ return false;
+ }
+
private boolean skipLimit(Position position, Position last) {
if (skipLimit != 0 && last != null) {
return (position.getServerTime().getTime() - last.getServerTime().getTime()) > skipLimit;
@@ -134,10 +188,9 @@ public class FilterHandler extends BaseDataHandler {
private boolean skipAttributes(Position position) {
if (skipAttributes) {
- String attributesString = Context.getIdentityManager().lookupAttributeString(
- position.getDeviceId(), "filter.skipAttributes", "", false, true);
- for (String attribute : attributesString.split("[ ,]")) {
- if (position.getAttributes().containsKey(attribute)) {
+ String string = AttributeUtil.lookup(cacheManager, Keys.FILTER_SKIP_ATTRIBUTES, position.getDeviceId());
+ for (String attribute : string.split("[ ,]")) {
+ if (position.hasAttribute(attribute)) {
return true;
}
}
@@ -145,7 +198,7 @@ public class FilterHandler extends BaseDataHandler {
return false;
}
- private boolean filter(Position position) {
+ protected boolean filter(Position position) {
StringBuilder filterType = new StringBuilder();
@@ -156,15 +209,24 @@ public class FilterHandler extends BaseDataHandler {
if (filterZero(position)) {
filterType.append("Zero ");
}
+ if (filterOutdated(position)) {
+ filterType.append("Outdated ");
+ }
if (filterFuture(position)) {
filterType.append("Future ");
}
+ if (filterPast(position)) {
+ filterType.append("Past ");
+ }
if (filterAccuracy(position)) {
filterType.append("Accuracy ");
}
if (filterApproximate(position)) {
filterType.append("Approximate ");
}
+ if (filterDailyLimit(position)) {
+ filterType.append("DailyLimit ");
+ }
// filter out excessive data
long deviceId = position.getDeviceId();
@@ -173,13 +235,13 @@ public class FilterHandler extends BaseDataHandler {
if (filterRelative) {
try {
Date newFixTime = position.getFixTime();
- preceding = Context.getDataManager().getPrecedingPosition(deviceId, newFixTime);
+ preceding = getPrecedingPosition(deviceId, newFixTime);
} catch (StorageException e) {
LOGGER.warn("Error retrieving preceding position; fallbacking to last received position.", e);
- preceding = getLastReceivedPosition(deviceId);
+ preceding = cacheManager.getPosition(deviceId);
}
} else {
- preceding = getLastReceivedPosition(deviceId);
+ preceding = cacheManager.getPosition(deviceId);
}
if (filterDuplicate(position, preceding) && !skipLimit(position, preceding) && !skipAttributes(position)) {
filterType.append("Duplicate ");
@@ -198,34 +260,34 @@ public class FilterHandler extends BaseDataHandler {
}
}
- if (filterType.length() > 0) {
-
- StringBuilder message = new StringBuilder();
- message.append("Position filtered by ");
- message.append(filterType.toString());
- message.append("filters from device: ");
- message.append(Context.getIdentityManager().getById(deviceId).getUniqueId());
+ Device device = cacheManager.getObject(Device.class, deviceId);
+ if (device.getCalendarId() > 0) {
+ Calendar calendar = cacheManager.getObject(Calendar.class, device.getCalendarId());
+ if (!calendar.checkMoment(position.getFixTime())) {
+ filterType.append("Calendar ");
+ }
+ }
- LOGGER.info(message.toString());
+ if (filterType.length() > 0) {
+ LOGGER.info("Position filtered by {}filters from device: {}", filterType, device.getUniqueId());
return true;
}
return false;
}
- private Position getLastReceivedPosition(long deviceId) {
- if (Context.getIdentityManager() != null) {
- return Context.getIdentityManager().getLastPosition(deviceId);
- }
- return null;
- }
-
@Override
- protected Position handlePosition(Position position) {
- if (filter(position)) {
- return null;
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ if (msg instanceof Position) {
+ Position position = (Position) msg;
+ if (enabled && filter(position)) {
+ ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(position));
+ } else {
+ ctx.fireChannelRead(position);
+ }
+ } else {
+ super.channelRead(ctx, msg);
}
- return position;
}
}