aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar/handler
diff options
context:
space:
mode:
authorAnton Tananaev <anton@traccar.org>2024-03-30 18:46:37 -0700
committerAnton Tananaev <anton@traccar.org>2024-03-30 18:46:37 -0700
commitf84e2710e05660822633ec9e61cde44c03a42d7e (patch)
tree0d68bee50cc42ed206d270275dfb32b4b69c5186 /src/main/java/org/traccar/handler
parentee996425221ca64fdf00777d9035cedc6dccfa43 (diff)
downloadtrackermap-server-f84e2710e05660822633ec9e61cde44c03a42d7e.tar.gz
trackermap-server-f84e2710e05660822633ec9e61cde44c03a42d7e.tar.bz2
trackermap-server-f84e2710e05660822633ec9e61cde44c03a42d7e.zip
Refactor position and event handlers
Diffstat (limited to 'src/main/java/org/traccar/handler')
-rw-r--r--src/main/java/org/traccar/handler/BasePositionHandler.java27
-rw-r--r--src/main/java/org/traccar/handler/ComputedAttributesHandler.java40
-rw-r--r--src/main/java/org/traccar/handler/CopyAttributesHandler.java16
-rw-r--r--src/main/java/org/traccar/handler/DatabaseHandler.java (renamed from src/main/java/org/traccar/handler/DefaultDataHandler.java)20
-rw-r--r--src/main/java/org/traccar/handler/DistanceHandler.java13
-rw-r--r--src/main/java/org/traccar/handler/EngineHoursHandler.java16
-rw-r--r--src/main/java/org/traccar/handler/FilterHandler.java25
-rw-r--r--src/main/java/org/traccar/handler/GeocoderHandler.java65
-rw-r--r--src/main/java/org/traccar/handler/GeofenceHandler.java15
-rw-r--r--src/main/java/org/traccar/handler/GeolocationHandler.java73
-rw-r--r--src/main/java/org/traccar/handler/HemisphereHandler.java16
-rw-r--r--src/main/java/org/traccar/handler/MotionHandler.java16
-rw-r--r--src/main/java/org/traccar/handler/PositionForwardingHandler.java137
-rw-r--r--src/main/java/org/traccar/handler/SpeedLimitHandler.java49
-rw-r--r--src/main/java/org/traccar/handler/TimeHandler.java15
-rw-r--r--src/main/java/org/traccar/handler/events/AlertEventHandler.java17
-rw-r--r--src/main/java/org/traccar/handler/events/BaseEventHandler.java32
-rw-r--r--src/main/java/org/traccar/handler/events/BehaviorEventHandler.java18
-rw-r--r--src/main/java/org/traccar/handler/events/CommandResultEventHandler.java17
-rw-r--r--src/main/java/org/traccar/handler/events/DriverEventHandler.java18
-rw-r--r--src/main/java/org/traccar/handler/events/FuelEventHandler.java22
-rw-r--r--src/main/java/org/traccar/handler/events/GeofenceEventHandler.java21
-rw-r--r--src/main/java/org/traccar/handler/events/IgnitionEventHandler.java25
-rw-r--r--src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java19
-rw-r--r--src/main/java/org/traccar/handler/events/MediaEventHandler.java16
-rw-r--r--src/main/java/org/traccar/handler/events/MotionEventHandler.java22
-rw-r--r--src/main/java/org/traccar/handler/events/OverspeedEventHandler.java27
-rw-r--r--src/main/java/org/traccar/handler/network/AcknowledgementHandler.java (renamed from src/main/java/org/traccar/handler/AcknowledgementHandler.java)2
-rw-r--r--src/main/java/org/traccar/handler/network/MainEventHandler.java195
-rw-r--r--src/main/java/org/traccar/handler/network/NetworkForwarderHandler.java (renamed from src/main/java/org/traccar/handler/NetworkForwarderHandler.java)2
-rw-r--r--src/main/java/org/traccar/handler/network/NetworkMessageHandler.java (renamed from src/main/java/org/traccar/handler/NetworkMessageHandler.java)2
-rw-r--r--src/main/java/org/traccar/handler/network/OpenChannelHandler.java (renamed from src/main/java/org/traccar/handler/OpenChannelHandler.java)2
-rw-r--r--src/main/java/org/traccar/handler/network/RemoteAddressHandler.java (renamed from src/main/java/org/traccar/handler/RemoteAddressHandler.java)8
-rw-r--r--src/main/java/org/traccar/handler/network/StandardLoggingHandler.java (renamed from src/main/java/org/traccar/handler/StandardLoggingHandler.java)2
34 files changed, 584 insertions, 426 deletions
diff --git a/src/main/java/org/traccar/handler/BasePositionHandler.java b/src/main/java/org/traccar/handler/BasePositionHandler.java
new file mode 100644
index 000000000..2fee5c652
--- /dev/null
+++ b/src/main/java/org/traccar/handler/BasePositionHandler.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2015 - 2024 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.handler;
+
+import org.traccar.model.Position;
+
+public abstract class BasePositionHandler {
+
+ public interface Callback {
+ void processed(Position position);
+ }
+
+ public abstract void handlePosition(Position position, Callback callback);
+}
diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java
index 8b010ceae..8d6fb39c3 100644
--- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java
+++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2024 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,26 +16,15 @@
*/
package org.traccar.handler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.List;
-
-import io.netty.channel.ChannelHandler;
-import org.apache.commons.jexl3.JexlFeatures;
-import org.apache.commons.jexl3.JexlEngine;
+import jakarta.inject.Inject;
import org.apache.commons.jexl3.JexlBuilder;
-import org.apache.commons.jexl3.introspection.JexlSandbox;
+import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.JexlException;
+import org.apache.commons.jexl3.JexlFeatures;
import org.apache.commons.jexl3.MapContext;
+import org.apache.commons.jexl3.introspection.JexlSandbox;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.BaseDataHandler;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Attribute;
@@ -43,12 +32,17 @@ import org.traccar.model.Device;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
-@Singleton
-@ChannelHandler.Sharable
-public class ComputedAttributesHandler extends BaseDataHandler {
+public class ComputedAttributesHandler extends BasePositionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(ComputedAttributesHandler.class);
@@ -144,7 +138,7 @@ public class ComputedAttributesHandler extends BaseDataHandler {
}
@Override
- protected Position handlePosition(Position position) {
+ public void handlePosition(Position position, Callback callback) {
Collection<Attribute> attributes = cacheManager.getDeviceObjects(position.getDeviceId(), Attribute.class);
for (Attribute attribute : attributes) {
if (attribute.getAttribute() != null) {
@@ -202,7 +196,7 @@ public class ComputedAttributesHandler extends BaseDataHandler {
}
}
}
- return position;
+ callback.processed(position);
}
}
diff --git a/src/main/java/org/traccar/handler/CopyAttributesHandler.java b/src/main/java/org/traccar/handler/CopyAttributesHandler.java
index 42b438e41..9c31bf56e 100644
--- a/src/main/java/org/traccar/handler/CopyAttributesHandler.java
+++ b/src/main/java/org/traccar/handler/CopyAttributesHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org)
* Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,20 +16,14 @@
*/
package org.traccar.handler;
-import io.netty.channel.ChannelHandler;
-import org.traccar.BaseDataHandler;
+import jakarta.inject.Inject;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.helper.model.AttributeUtil;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-
-@Singleton
-@ChannelHandler.Sharable
-public class CopyAttributesHandler extends BaseDataHandler {
+public class CopyAttributesHandler extends BasePositionHandler {
private final boolean enabled;
private final CacheManager cacheManager;
@@ -41,7 +35,7 @@ public class CopyAttributesHandler extends BaseDataHandler {
}
@Override
- protected Position handlePosition(Position position) {
+ public void handlePosition(Position position, Callback callback) {
if (enabled) {
String attributesString = AttributeUtil.lookup(
cacheManager, Keys.PROCESSING_COPY_ATTRIBUTES, position.getDeviceId());
@@ -54,7 +48,7 @@ public class CopyAttributesHandler extends BaseDataHandler {
}
}
}
- return position;
+ callback.processed(position);
}
}
diff --git a/src/main/java/org/traccar/handler/DefaultDataHandler.java b/src/main/java/org/traccar/handler/DatabaseHandler.java
index cca6dcd0a..b1f218a1e 100644
--- a/src/main/java/org/traccar/handler/DefaultDataHandler.java
+++ b/src/main/java/org/traccar/handler/DatabaseHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2024 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.
@@ -15,33 +15,27 @@
*/
package org.traccar.handler;
-import io.netty.channel.ChannelHandler;
+import jakarta.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.BaseDataHandler;
import org.traccar.model.Position;
import org.traccar.storage.Storage;
import org.traccar.storage.query.Columns;
import org.traccar.storage.query.Request;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-
-@Singleton
-@ChannelHandler.Sharable
-public class DefaultDataHandler extends BaseDataHandler {
+public class DatabaseHandler extends BasePositionHandler {
- private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDataHandler.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseHandler.class);
private final Storage storage;
@Inject
- public DefaultDataHandler(Storage storage) {
+ public DatabaseHandler(Storage storage) {
this.storage = storage;
}
@Override
- protected Position handlePosition(Position position) {
+ public void handlePosition(Position position, Callback callback) {
try {
position.setId(storage.addObject(position, new Request(new Columns.Exclude("id"))));
@@ -49,7 +43,7 @@ public class DefaultDataHandler extends BaseDataHandler {
LOGGER.warn("Failed to store position", error);
}
- return position;
+ callback.processed(position);
}
}
diff --git a/src/main/java/org/traccar/handler/DistanceHandler.java b/src/main/java/org/traccar/handler/DistanceHandler.java
index db8c73779..ee5d64894 100644
--- a/src/main/java/org/traccar/handler/DistanceHandler.java
+++ b/src/main/java/org/traccar/handler/DistanceHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org)
* Copyright 2015 Amila Silva
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,14 @@
*/
package org.traccar.handler;
-import io.netty.channel.ChannelHandler;
import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-import org.traccar.BaseDataHandler;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.helper.DistanceCalculator;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-@Singleton
-@ChannelHandler.Sharable
-public class DistanceHandler extends BaseDataHandler {
+public class DistanceHandler extends BasePositionHandler {
private final CacheManager cacheManager;
@@ -45,7 +40,7 @@ public class DistanceHandler extends BaseDataHandler {
}
@Override
- protected Position handlePosition(Position position) {
+ public void handlePosition(Position position, Callback callback) {
double distance = 0.0;
if (position.hasAttribute(Position.KEY_DISTANCE)) {
@@ -76,7 +71,7 @@ public class DistanceHandler extends BaseDataHandler {
position.set(Position.KEY_DISTANCE, distance);
position.set(Position.KEY_TOTAL_DISTANCE, totalDistance + distance);
- return position;
+ callback.processed(position);
}
}
diff --git a/src/main/java/org/traccar/handler/EngineHoursHandler.java b/src/main/java/org/traccar/handler/EngineHoursHandler.java
index 621205b34..ed5f9b509 100644
--- a/src/main/java/org/traccar/handler/EngineHoursHandler.java
+++ b/src/main/java/org/traccar/handler/EngineHoursHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 2024 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,11 @@
*/
package org.traccar.handler;
-import io.netty.channel.ChannelHandler;
-import org.traccar.BaseDataHandler;
+import jakarta.inject.Inject;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-
-@Singleton
-@ChannelHandler.Sharable
-public class EngineHoursHandler extends BaseDataHandler {
+public class EngineHoursHandler extends BasePositionHandler {
private final CacheManager cacheManager;
@@ -36,7 +30,7 @@ public class EngineHoursHandler extends BaseDataHandler {
}
@Override
- protected Position handlePosition(Position position) {
+ public void handlePosition(Position position, Callback callback) {
if (!position.hasAttribute(Position.KEY_HOURS)) {
Position last = cacheManager.getPosition(position.getDeviceId());
if (last != null) {
@@ -49,7 +43,7 @@ public class EngineHoursHandler extends BaseDataHandler {
}
}
}
- return position;
+ callback.processed(position);
}
}
diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java
index a15d3ffad..4cc6233d0 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 - 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2014 - 2024 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.
@@ -15,9 +15,7 @@
*/
package org.traccar.handler;
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
+import jakarta.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.config.Config;
@@ -36,13 +34,9 @@ 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 ChannelInboundHandlerAdapter {
+public class FilterHandler extends BasePositionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(FilterHandler.class);
@@ -277,16 +271,11 @@ public class FilterHandler extends ChannelInboundHandlerAdapter {
}
@Override
- 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);
- }
+ public void handlePosition(Position position, Callback callback) {
+ if (enabled && filter(position)) {
+ callback.processed(null);
} else {
- super.channelRead(ctx, msg);
+ callback.processed(position);
}
}
diff --git a/src/main/java/org/traccar/handler/GeocoderHandler.java b/src/main/java/org/traccar/handler/GeocoderHandler.java
index e4f240a90..c62bcb6f8 100644
--- a/src/main/java/org/traccar/handler/GeocoderHandler.java
+++ b/src/main/java/org/traccar/handler/GeocoderHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2024 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.
@@ -15,9 +15,6 @@
*/
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.config.Config;
@@ -26,8 +23,7 @@ import org.traccar.geocoder.Geocoder;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-@ChannelHandler.Sharable
-public class GeocoderHandler extends ChannelInboundHandlerAdapter {
+public class GeocoderHandler extends BasePositionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(GeocoderHandler.class);
@@ -46,39 +42,38 @@ public class GeocoderHandler extends ChannelInboundHandlerAdapter {
}
@Override
- public void channelRead(final ChannelHandlerContext ctx, Object message) {
- if (message instanceof Position && !ignorePositions) {
- final Position position = (Position) message;
- if (processInvalidPositions || position.getValid()) {
- if (reuseDistance != 0) {
- Position lastPosition = cacheManager.getPosition(position.getDeviceId());
- if (lastPosition != null && lastPosition.getAddress() != null
- && position.getDouble(Position.KEY_DISTANCE) <= reuseDistance) {
- position.setAddress(lastPosition.getAddress());
- ctx.fireChannelRead(position);
- return;
- }
+ public void handlePosition(Position position, Callback callback) {
+ if (!ignorePositions) {
+ callback.processed(position);
+ }
+
+ if (processInvalidPositions || position.getValid()) {
+ if (reuseDistance != 0) {
+ Position lastPosition = cacheManager.getPosition(position.getDeviceId());
+ if (lastPosition != null && lastPosition.getAddress() != null
+ && position.getDouble(Position.KEY_DISTANCE) <= reuseDistance) {
+ position.setAddress(lastPosition.getAddress());
+ callback.processed(position);
+ return;
}
+ }
- geocoder.getAddress(position.getLatitude(), position.getLongitude(),
- new Geocoder.ReverseGeocoderCallback() {
- @Override
- public void onSuccess(String address) {
- position.setAddress(address);
- ctx.fireChannelRead(position);
- }
+ geocoder.getAddress(position.getLatitude(), position.getLongitude(),
+ new Geocoder.ReverseGeocoderCallback() {
+ @Override
+ public void onSuccess(String address) {
+ position.setAddress(address);
+ callback.processed(position);
+ }
- @Override
- public void onFailure(Throwable e) {
- LOGGER.warn("Geocoding failed", e);
- ctx.fireChannelRead(position);
- }
- });
- } else {
- ctx.fireChannelRead(position);
- }
+ @Override
+ public void onFailure(Throwable e) {
+ LOGGER.warn("Geocoding failed", e);
+ callback.processed(position);
+ }
+ });
} else {
- ctx.fireChannelRead(message);
+ callback.processed(position);
}
}
diff --git a/src/main/java/org/traccar/handler/GeofenceHandler.java b/src/main/java/org/traccar/handler/GeofenceHandler.java
index 68bc6dbf0..33b46f058 100644
--- a/src/main/java/org/traccar/handler/GeofenceHandler.java
+++ b/src/main/java/org/traccar/handler/GeofenceHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2023 - 2024 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.
@@ -15,20 +15,15 @@
*/
package org.traccar.handler;
-import io.netty.channel.ChannelHandler;
-import org.traccar.BaseDataHandler;
+import jakarta.inject.Inject;
import org.traccar.config.Config;
import org.traccar.helper.model.GeofenceUtil;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
import java.util.List;
-@Singleton
-@ChannelHandler.Sharable
-public class GeofenceHandler extends BaseDataHandler {
+public class GeofenceHandler extends BasePositionHandler {
private final Config config;
private final CacheManager cacheManager;
@@ -40,13 +35,13 @@ public class GeofenceHandler extends BaseDataHandler {
}
@Override
- protected Position handlePosition(Position position) {
+ public void handlePosition(Position position, Callback callback) {
List<Long> geofenceIds = GeofenceUtil.getCurrentGeofences(config, cacheManager, position);
if (!geofenceIds.isEmpty()) {
position.setGeofenceIds(geofenceIds);
}
- return position;
+ callback.processed(position);
}
}
diff --git a/src/main/java/org/traccar/handler/GeolocationHandler.java b/src/main/java/org/traccar/handler/GeolocationHandler.java
index a54ea03e3..cb9c04808 100644
--- a/src/main/java/org/traccar/handler/GeolocationHandler.java
+++ b/src/main/java/org/traccar/handler/GeolocationHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2024 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.
@@ -15,9 +15,6 @@
*/
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.config.Config;
@@ -27,8 +24,7 @@ import org.traccar.geolocation.GeolocationProvider;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-@ChannelHandler.Sharable
-public class GeolocationHandler extends ChannelInboundHandlerAdapter {
+public class GeolocationHandler extends BasePositionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(GeolocationHandler.class);
@@ -51,46 +47,41 @@ public class GeolocationHandler extends ChannelInboundHandlerAdapter {
}
@Override
- public void channelRead(final ChannelHandlerContext ctx, Object message) {
- if (message instanceof Position) {
- final Position position = (Position) message;
- if ((position.getOutdated() || processInvalidPositions && !position.getValid())
- && position.getNetwork() != null
- && (!requireWifi || position.getNetwork().getWifiAccessPoints() != null)) {
- if (reuse) {
- Position lastPosition = cacheManager.getPosition(position.getDeviceId());
- if (lastPosition != null && position.getNetwork().equals(lastPosition.getNetwork())) {
- updatePosition(
- position, lastPosition.getLatitude(), lastPosition.getLongitude(),
- lastPosition.getAccuracy());
- ctx.fireChannelRead(position);
- return;
- }
+ public void handlePosition(Position position, Callback callback) {
+ if ((position.getOutdated() || processInvalidPositions && !position.getValid())
+ && position.getNetwork() != null
+ && (!requireWifi || position.getNetwork().getWifiAccessPoints() != null)) {
+ if (reuse) {
+ Position lastPosition = cacheManager.getPosition(position.getDeviceId());
+ if (lastPosition != null && position.getNetwork().equals(lastPosition.getNetwork())) {
+ updatePosition(
+ position, lastPosition.getLatitude(), lastPosition.getLongitude(),
+ lastPosition.getAccuracy());
+ callback.processed(position);
+ return;
}
+ }
- if (statisticsManager != null) {
- statisticsManager.registerGeolocationRequest();
- }
+ if (statisticsManager != null) {
+ statisticsManager.registerGeolocationRequest();
+ }
- geolocationProvider.getLocation(position.getNetwork(),
- new GeolocationProvider.LocationProviderCallback() {
- @Override
- public void onSuccess(double latitude, double longitude, double accuracy) {
- updatePosition(position, latitude, longitude, accuracy);
- ctx.fireChannelRead(position);
- }
+ geolocationProvider.getLocation(position.getNetwork(),
+ new GeolocationProvider.LocationProviderCallback() {
+ @Override
+ public void onSuccess(double latitude, double longitude, double accuracy) {
+ updatePosition(position, latitude, longitude, accuracy);
+ callback.processed(position);
+ }
- @Override
- public void onFailure(Throwable e) {
- LOGGER.warn("Geolocation network error", e);
- ctx.fireChannelRead(position);
- }
- });
- } else {
- ctx.fireChannelRead(position);
- }
+ @Override
+ public void onFailure(Throwable e) {
+ LOGGER.warn("Geolocation network error", e);
+ callback.processed(position);
+ }
+ });
} else {
- ctx.fireChannelRead(message);
+ callback.processed(position);
}
}
diff --git a/src/main/java/org/traccar/handler/HemisphereHandler.java b/src/main/java/org/traccar/handler/HemisphereHandler.java
index 294e449db..6b64177e4 100644
--- a/src/main/java/org/traccar/handler/HemisphereHandler.java
+++ b/src/main/java/org/traccar/handler/HemisphereHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2024 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.
@@ -15,18 +15,12 @@
*/
package org.traccar.handler;
-import io.netty.channel.ChannelHandler;
-import org.traccar.BaseDataHandler;
+import jakarta.inject.Inject;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Position;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-
-@Singleton
-@ChannelHandler.Sharable
-public class HemisphereHandler extends BaseDataHandler {
+public class HemisphereHandler extends BasePositionHandler {
private int latitudeFactor;
private int longitudeFactor;
@@ -52,14 +46,14 @@ public class HemisphereHandler extends BaseDataHandler {
}
@Override
- protected Position handlePosition(Position position) {
+ public void handlePosition(Position position, Callback callback) {
if (latitudeFactor != 0) {
position.setLatitude(Math.abs(position.getLatitude()) * latitudeFactor);
}
if (longitudeFactor != 0) {
position.setLongitude(Math.abs(position.getLongitude()) * longitudeFactor);
}
- return position;
+ callback.processed(position);
}
}
diff --git a/src/main/java/org/traccar/handler/MotionHandler.java b/src/main/java/org/traccar/handler/MotionHandler.java
index 68a31a16a..bb7ff2a65 100644
--- a/src/main/java/org/traccar/handler/MotionHandler.java
+++ b/src/main/java/org/traccar/handler/MotionHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2024 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,13 @@
*/
package org.traccar.handler;
-import io.netty.channel.ChannelHandler;
-import org.traccar.BaseDataHandler;
+import jakarta.inject.Inject;
import org.traccar.config.Keys;
import org.traccar.helper.model.AttributeUtil;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-
-@Singleton
-@ChannelHandler.Sharable
-public class MotionHandler extends BaseDataHandler {
+public class MotionHandler extends BasePositionHandler {
private final CacheManager cacheManager;
@@ -38,13 +32,13 @@ public class MotionHandler extends BaseDataHandler {
}
@Override
- protected Position handlePosition(Position position) {
+ public void handlePosition(Position position, Callback callback) {
if (!position.hasAttribute(Position.KEY_MOTION)) {
double threshold = AttributeUtil.lookup(
cacheManager, Keys.EVENT_MOTION_SPEED_THRESHOLD, position.getDeviceId());
position.set(Position.KEY_MOTION, position.getSpeed() > threshold);
}
- return position;
+ callback.processed(position);
}
}
diff --git a/src/main/java/org/traccar/handler/PositionForwardingHandler.java b/src/main/java/org/traccar/handler/PositionForwardingHandler.java
new file mode 100644
index 000000000..be62fff37
--- /dev/null
+++ b/src/main/java/org/traccar/handler/PositionForwardingHandler.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2015 - 2024 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.handler;
+
+import io.netty.util.Timeout;
+import io.netty.util.Timer;
+import io.netty.util.TimerTask;
+import jakarta.annotation.Nullable;
+import jakarta.inject.Inject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.forward.PositionData;
+import org.traccar.forward.PositionForwarder;
+import org.traccar.forward.ResultHandler;
+import org.traccar.model.Device;
+import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class PositionForwardingHandler extends BasePositionHandler {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PositionForwardingHandler.class);
+
+ private final CacheManager cacheManager;
+ private final Timer timer;
+
+ private final PositionForwarder positionForwarder;
+
+ private final boolean retryEnabled;
+ private final int retryDelay;
+ private final int retryCount;
+ private final int retryLimit;
+
+ private final AtomicInteger deliveryPending;
+
+ @Inject
+ public PositionForwardingHandler(
+ Config config, CacheManager cacheManager, Timer timer, @Nullable PositionForwarder positionForwarder) {
+
+ this.cacheManager = cacheManager;
+ this.timer = timer;
+ this.positionForwarder = positionForwarder;
+
+ this.retryEnabled = config.getBoolean(Keys.FORWARD_RETRY_ENABLE);
+ this.retryDelay = config.getInteger(Keys.FORWARD_RETRY_DELAY);
+ this.retryCount = config.getInteger(Keys.FORWARD_RETRY_COUNT);
+ this.retryLimit = config.getInteger(Keys.FORWARD_RETRY_LIMIT);
+
+ this.deliveryPending = new AtomicInteger();
+ }
+
+ class AsyncRequestAndCallback implements ResultHandler, TimerTask {
+
+ private final PositionData positionData;
+
+ private int retries = 0;
+
+ AsyncRequestAndCallback(PositionData positionData) {
+ this.positionData = positionData;
+ deliveryPending.incrementAndGet();
+ }
+
+ private void send() {
+ positionForwarder.forward(positionData, this);
+ }
+
+ private void retry(Throwable throwable) {
+ boolean scheduled = false;
+ try {
+ if (retryEnabled && deliveryPending.get() <= retryLimit && retries < retryCount) {
+ schedule();
+ scheduled = true;
+ }
+ } finally {
+ int pending = scheduled ? deliveryPending.get() : deliveryPending.decrementAndGet();
+ LOGGER.warn("Position forwarding failed: " + pending + " pending", throwable);
+ }
+ }
+
+ private void schedule() {
+ timer.newTimeout(this, retryDelay * (long) Math.pow(2, retries++), TimeUnit.MILLISECONDS);
+ }
+
+ @Override
+ public void onResult(boolean success, Throwable throwable) {
+ if (success) {
+ deliveryPending.decrementAndGet();
+ } else {
+ retry(throwable);
+ }
+ }
+
+ @Override
+ public void run(Timeout timeout) {
+ boolean sent = false;
+ try {
+ if (!timeout.isCancelled()) {
+ send();
+ sent = true;
+ }
+ } finally {
+ if (!sent) {
+ deliveryPending.decrementAndGet();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void handlePosition(Position position, Callback callback) {
+ if (positionForwarder != null) {
+ PositionData positionData = new PositionData();
+ positionData.setPosition(position);
+ positionData.setDevice(cacheManager.getObject(Device.class, position.getDeviceId()));
+ new AsyncRequestAndCallback(positionData).send();
+ }
+ callback.processed(position);
+ }
+
+}
diff --git a/src/main/java/org/traccar/handler/SpeedLimitHandler.java b/src/main/java/org/traccar/handler/SpeedLimitHandler.java
index 6edb6e912..604c10ca7 100644
--- a/src/main/java/org/traccar/handler/SpeedLimitHandler.java
+++ b/src/main/java/org/traccar/handler/SpeedLimitHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2020 - 2024 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.
@@ -15,20 +15,13 @@
*/
package org.traccar.handler;
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
+import jakarta.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.model.Position;
import org.traccar.speedlimit.SpeedLimitProvider;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-
-@Singleton
-@ChannelHandler.Sharable
-public class SpeedLimitHandler extends ChannelInboundHandlerAdapter {
+public class SpeedLimitHandler extends BasePositionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(SpeedLimitHandler.class);
@@ -40,26 +33,22 @@ public class SpeedLimitHandler extends ChannelInboundHandlerAdapter {
}
@Override
- public void channelRead(final ChannelHandlerContext ctx, Object message) {
- if (message instanceof Position) {
- final Position position = (Position) message;
- speedLimitProvider.getSpeedLimit(position.getLatitude(), position.getLongitude(),
- new SpeedLimitProvider.SpeedLimitProviderCallback() {
- @Override
- public void onSuccess(double speedLimit) {
- position.set(Position.KEY_SPEED_LIMIT, speedLimit);
- ctx.fireChannelRead(position);
- }
-
- @Override
- public void onFailure(Throwable e) {
- LOGGER.warn("Speed limit provider failed", e);
- ctx.fireChannelRead(position);
- }
- });
- } else {
- ctx.fireChannelRead(message);
- }
+ public void handlePosition(Position position, Callback callback) {
+
+ speedLimitProvider.getSpeedLimit(position.getLatitude(), position.getLongitude(),
+ new SpeedLimitProvider.SpeedLimitProviderCallback() {
+ @Override
+ public void onSuccess(double speedLimit) {
+ position.set(Position.KEY_SPEED_LIMIT, speedLimit);
+ callback.processed(position);
+ }
+
+ @Override
+ public void onFailure(Throwable e) {
+ LOGGER.warn("Speed limit provider failed", e);
+ callback.processed(position);
+ }
+ });
}
}
diff --git a/src/main/java/org/traccar/handler/TimeHandler.java b/src/main/java/org/traccar/handler/TimeHandler.java
index ef0c3445d..2e703c681 100644
--- a/src/main/java/org/traccar/handler/TimeHandler.java
+++ b/src/main/java/org/traccar/handler/TimeHandler.java
@@ -15,11 +15,7 @@
*/
package org.traccar.handler;
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Position;
@@ -28,9 +24,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
-@Singleton
-@ChannelHandler.Sharable
-public class TimeHandler extends ChannelInboundHandlerAdapter {
+public class TimeHandler extends BasePositionHandler {
private final boolean enabled;
private final boolean useServerTime;
@@ -53,10 +47,9 @@ public class TimeHandler extends ChannelInboundHandlerAdapter {
}
@Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) {
+ public void handlePosition(Position position, Callback callback) {
- if (enabled && msg instanceof Position) {
- Position position = (Position) msg;
+ if (enabled) {
if (protocols == null || protocols.contains(position.getProtocol())) {
if (useServerTime) {
position.setDeviceTime(position.getServerTime());
@@ -66,7 +59,7 @@ public class TimeHandler extends ChannelInboundHandlerAdapter {
}
}
}
- ctx.fireChannelRead(msg);
+ callback.processed(position);
}
}
diff --git a/src/main/java/org/traccar/handler/events/AlertEventHandler.java b/src/main/java/org/traccar/handler/events/AlertEventHandler.java
index 531a0f957..ca580b60d 100644
--- a/src/main/java/org/traccar/handler/events/AlertEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/AlertEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2024 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.
@@ -15,21 +15,13 @@
*/
package org.traccar.handler.events;
-import java.util.Collections;
-import java.util.Map;
-
-import io.netty.channel.ChannelHandler;
+import jakarta.inject.Inject;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Event;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-
-@Singleton
-@ChannelHandler.Sharable
public class AlertEventHandler extends BaseEventHandler {
private final CacheManager cacheManager;
@@ -42,7 +34,7 @@ public class AlertEventHandler extends BaseEventHandler {
}
@Override
- protected Map<Event, Position> analyzePosition(Position position) {
+ public void analyzePosition(Position position, Callback callback) {
Object alarm = position.getAttributes().get(Position.KEY_ALARM);
if (alarm != null) {
boolean ignoreAlert = false;
@@ -55,10 +47,9 @@ public class AlertEventHandler extends BaseEventHandler {
if (!ignoreAlert) {
Event event = new Event(Event.TYPE_ALARM, position);
event.set(Position.KEY_ALARM, (String) alarm);
- return Collections.singletonMap(event, position);
+ callback.eventDetected(event);
}
}
- return null;
}
}
diff --git a/src/main/java/org/traccar/handler/events/BaseEventHandler.java b/src/main/java/org/traccar/handler/events/BaseEventHandler.java
index 4a4fb40ff..009c83145 100644
--- a/src/main/java/org/traccar/handler/events/BaseEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/BaseEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2024 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.
@@ -15,33 +15,17 @@
*/
package org.traccar.handler.events;
-import java.util.Map;
-
-import org.traccar.BaseDataHandler;
-import org.traccar.database.NotificationManager;
import org.traccar.model.Event;
import org.traccar.model.Position;
-import jakarta.inject.Inject;
-
-public abstract class BaseEventHandler extends BaseDataHandler {
-
- private NotificationManager notificationManager;
+public abstract class BaseEventHandler {
- @Inject
- public void setNotificationManager(NotificationManager notificationManager) {
- this.notificationManager = notificationManager;
+ public interface Callback {
+ void eventDetected(Event event);
}
- @Override
- protected Position handlePosition(Position position) {
- Map<Event, Position> events = analyzePosition(position);
- if (events != null && !events.isEmpty()) {
- notificationManager.updateEvents(events);
- }
- return position;
- }
-
- protected abstract Map<Event, Position> analyzePosition(Position position);
-
+ /**
+ * Event handlers should be processed synchronously.
+ */
+ public abstract void analyzePosition(Position position, Callback callback);
}
diff --git a/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java b/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java
index 08ae35fcd..d654e18ce 100644
--- a/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2021 - 2024 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.
@@ -15,7 +15,7 @@
*/
package org.traccar.handler.events;
-import io.netty.channel.ChannelHandler;
+import jakarta.inject.Inject;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.helper.UnitsConverter;
@@ -23,13 +23,6 @@ import org.traccar.model.Event;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-import java.util.Collections;
-import java.util.Map;
-
-@Singleton
-@ChannelHandler.Sharable
public class BehaviorEventHandler extends BaseEventHandler {
private final double accelerationThreshold;
@@ -45,7 +38,7 @@ public class BehaviorEventHandler extends BaseEventHandler {
}
@Override
- protected Map<Event, Position> analyzePosition(Position position) {
+ public void analyzePosition(Position position, Callback callback) {
Position lastPosition = cacheManager.getPosition(position.getDeviceId());
if (lastPosition != null && position.getFixTime().equals(lastPosition.getFixTime())) {
@@ -54,14 +47,13 @@ public class BehaviorEventHandler extends BaseEventHandler {
if (accelerationThreshold != 0 && acceleration >= accelerationThreshold) {
Event event = new Event(Event.TYPE_ALARM, position);
event.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
- return Collections.singletonMap(event, position);
+ callback.eventDetected(event);
} else if (brakingThreshold != 0 && acceleration <= -brakingThreshold) {
Event event = new Event(Event.TYPE_ALARM, position);
event.set(Position.KEY_ALARM, Position.ALARM_BRAKING);
- return Collections.singletonMap(event, position);
+ callback.eventDetected(event);
}
}
- return null;
}
}
diff --git a/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java b/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java
index b70f8f33b..b98807b23 100644
--- a/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2024 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.
@@ -15,18 +15,10 @@
*/
package org.traccar.handler.events;
-import java.util.Collections;
-import java.util.Map;
-
-import io.netty.channel.ChannelHandler;
+import jakarta.inject.Inject;
import org.traccar.model.Event;
import org.traccar.model.Position;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-
-@Singleton
-@ChannelHandler.Sharable
public class CommandResultEventHandler extends BaseEventHandler {
@Inject
@@ -34,14 +26,13 @@ public class CommandResultEventHandler extends BaseEventHandler {
}
@Override
- protected Map<Event, Position> analyzePosition(Position position) {
+ public void analyzePosition(Position position, Callback callback) {
Object commandResult = position.getAttributes().get(Position.KEY_RESULT);
if (commandResult != null) {
Event event = new Event(Event.TYPE_COMMAND_RESULT, position);
event.set(Position.KEY_RESULT, (String) commandResult);
- return Collections.singletonMap(event, position);
+ callback.eventDetected(event);
}
- return null;
}
}
diff --git a/src/main/java/org/traccar/handler/events/DriverEventHandler.java b/src/main/java/org/traccar/handler/events/DriverEventHandler.java
index b68327983..31f8d2b4b 100644
--- a/src/main/java/org/traccar/handler/events/DriverEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/DriverEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2024 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,12 @@
*/
package org.traccar.handler.events;
-import io.netty.channel.ChannelHandler;
+import jakarta.inject.Inject;
import org.traccar.helper.model.PositionUtil;
import org.traccar.model.Event;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-import java.util.Collections;
-import java.util.Map;
-
-@Singleton
-@ChannelHandler.Sharable
public class DriverEventHandler extends BaseEventHandler {
private final CacheManager cacheManager;
@@ -39,9 +32,9 @@ public class DriverEventHandler extends BaseEventHandler {
}
@Override
- protected Map<Event, Position> analyzePosition(Position position) {
+ public void analyzePosition(Position position, Callback callback) {
if (!PositionUtil.isLatest(cacheManager, position)) {
- return null;
+ return;
}
String driverUniqueId = position.getString(Position.KEY_DRIVER_UNIQUE_ID);
if (driverUniqueId != null) {
@@ -53,10 +46,9 @@ public class DriverEventHandler extends BaseEventHandler {
if (!driverUniqueId.equals(oldDriverUniqueId)) {
Event event = new Event(Event.TYPE_DRIVER_CHANGED, position);
event.set(Position.KEY_DRIVER_UNIQUE_ID, driverUniqueId);
- return Collections.singletonMap(event, position);
+ callback.eventDetected(event);
}
}
- return null;
}
}
diff --git a/src/main/java/org/traccar/handler/events/FuelEventHandler.java b/src/main/java/org/traccar/handler/events/FuelEventHandler.java
index e5085ecc2..c5675f51d 100644
--- a/src/main/java/org/traccar/handler/events/FuelEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/FuelEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2024 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.
@@ -15,7 +15,7 @@
*/
package org.traccar.handler.events;
-import io.netty.channel.ChannelHandler;
+import jakarta.inject.Inject;
import org.traccar.config.Keys;
import org.traccar.helper.model.AttributeUtil;
import org.traccar.helper.model.PositionUtil;
@@ -24,12 +24,6 @@ import org.traccar.model.Event;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-import java.util.Map;
-
-@Singleton
-@ChannelHandler.Sharable
public class FuelEventHandler extends BaseEventHandler {
private final CacheManager cacheManager;
@@ -40,14 +34,14 @@ public class FuelEventHandler extends BaseEventHandler {
}
@Override
- protected Map<Event, Position> analyzePosition(Position position) {
+ public void analyzePosition(Position position, Callback callback) {
Device device = cacheManager.getObject(Device.class, position.getDeviceId());
if (device == null) {
- return null;
+ return;
}
if (!PositionUtil.isLatest(cacheManager, position)) {
- return null;
+ return;
}
if (position.hasAttribute(Position.KEY_FUEL_LEVEL)) {
@@ -61,19 +55,17 @@ public class FuelEventHandler extends BaseEventHandler {
double threshold = AttributeUtil.lookup(
cacheManager, Keys.EVENT_FUEL_INCREASE_THRESHOLD, position.getDeviceId());
if (threshold > 0 && change >= threshold) {
- return Map.of(new Event(Event.TYPE_DEVICE_FUEL_INCREASE, position), position);
+ callback.eventDetected(new Event(Event.TYPE_DEVICE_FUEL_INCREASE, position));
}
} else if (change < 0) {
double threshold = AttributeUtil.lookup(
cacheManager, Keys.EVENT_FUEL_DROP_THRESHOLD, position.getDeviceId());
if (threshold > 0 && Math.abs(change) >= threshold) {
- return Map.of(new Event(Event.TYPE_DEVICE_FUEL_DROP, position), position);
+ callback.eventDetected(new Event(Event.TYPE_DEVICE_FUEL_DROP, position));
}
}
}
}
-
- return null;
}
}
diff --git a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java
index dbe2b8118..c8ecfb1ed 100644
--- a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2024 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.
@@ -15,7 +15,7 @@
*/
package org.traccar.handler.events;
-import io.netty.channel.ChannelHandler;
+import jakarta.inject.Inject;
import org.traccar.helper.model.PositionUtil;
import org.traccar.model.Calendar;
import org.traccar.model.Event;
@@ -23,15 +23,9 @@ import org.traccar.model.Geofence;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-@Singleton
-@ChannelHandler.Sharable
public class GeofenceEventHandler extends BaseEventHandler {
private final CacheManager cacheManager;
@@ -42,9 +36,9 @@ public class GeofenceEventHandler extends BaseEventHandler {
}
@Override
- protected Map<Event, Position> analyzePosition(Position position) {
+ public void analyzePosition(Position position, Callback callback) {
if (!PositionUtil.isLatest(cacheManager, position)) {
- return null;
+ return;
}
List<Long> oldGeofences = new ArrayList<>();
@@ -60,7 +54,6 @@ public class GeofenceEventHandler extends BaseEventHandler {
oldGeofences.removeAll(position.getGeofenceIds());
}
- Map<Event, Position> events = new HashMap<>();
for (long geofenceId : oldGeofences) {
Geofence geofence = cacheManager.getObject(Geofence.class, geofenceId);
if (geofence != null) {
@@ -69,7 +62,7 @@ public class GeofenceEventHandler extends BaseEventHandler {
if (calendar == null || calendar.checkMoment(position.getFixTime())) {
Event event = new Event(Event.TYPE_GEOFENCE_EXIT, position);
event.setGeofenceId(geofenceId);
- events.put(event, position);
+ callback.eventDetected(event);
}
}
}
@@ -79,10 +72,8 @@ public class GeofenceEventHandler extends BaseEventHandler {
if (calendar == null || calendar.checkMoment(position.getFixTime())) {
Event event = new Event(Event.TYPE_GEOFENCE_ENTER, position);
event.setGeofenceId(geofenceId);
- events.put(event, position);
+ callback.eventDetected(event);
}
}
- return events;
}
-
}
diff --git a/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java b/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java
index ba4159a42..bbf9fadd1 100644
--- a/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org)
* Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,13 @@
*/
package org.traccar.handler.events;
-import java.util.Collections;
-import java.util.Map;
-
-import io.netty.channel.ChannelHandler;
+import jakarta.inject.Inject;
import org.traccar.helper.model.PositionUtil;
import org.traccar.model.Device;
import org.traccar.model.Event;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-
-@Singleton
-@ChannelHandler.Sharable
public class IgnitionEventHandler extends BaseEventHandler {
private final CacheManager cacheManager;
@@ -41,14 +33,12 @@ public class IgnitionEventHandler extends BaseEventHandler {
}
@Override
- protected Map<Event, Position> analyzePosition(Position position) {
+ public void analyzePosition(Position position, Callback callback) {
Device device = cacheManager.getObject(Device.class, position.getDeviceId());
if (device == null || !PositionUtil.isLatest(cacheManager, position)) {
- return null;
+ return;
}
- Map<Event, Position> result = null;
-
if (position.hasAttribute(Position.KEY_IGNITION)) {
boolean ignition = position.getBoolean(Position.KEY_IGNITION);
@@ -57,15 +47,12 @@ public class IgnitionEventHandler extends BaseEventHandler {
boolean oldIgnition = lastPosition.getBoolean(Position.KEY_IGNITION);
if (ignition && !oldIgnition) {
- result = Collections.singletonMap(
- new Event(Event.TYPE_IGNITION_ON, position), position);
+ callback.eventDetected(new Event(Event.TYPE_IGNITION_ON, position));
} else if (!ignition && oldIgnition) {
- result = Collections.singletonMap(
- new Event(Event.TYPE_IGNITION_OFF, position), position);
+ callback.eventDetected(new Event(Event.TYPE_IGNITION_OFF, position));
}
}
}
- return result;
}
}
diff --git a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java
index 2fa2e8869..573ad4ad6 100644
--- a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java
@@ -16,20 +16,12 @@
*/
package org.traccar.handler.events;
-import java.util.HashMap;
-import java.util.Map;
-
-import io.netty.channel.ChannelHandler;
+import jakarta.inject.Inject;
import org.traccar.model.Event;
import org.traccar.model.Maintenance;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-
-@Singleton
-@ChannelHandler.Sharable
public class MaintenanceEventHandler extends BaseEventHandler {
private final CacheManager cacheManager;
@@ -40,13 +32,12 @@ public class MaintenanceEventHandler extends BaseEventHandler {
}
@Override
- protected Map<Event, Position> analyzePosition(Position position) {
+ public void analyzePosition(Position position, Callback callback) {
Position lastPosition = cacheManager.getPosition(position.getDeviceId());
if (lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) < 0) {
- return null;
+ return;
}
- Map<Event, Position> events = new HashMap<>();
for (Maintenance maintenance : cacheManager.getDeviceObjects(position.getDeviceId(), Maintenance.class)) {
if (maintenance.getPeriod() != 0) {
double oldValue = getValue(lastPosition, maintenance.getType());
@@ -58,13 +49,11 @@ public class MaintenanceEventHandler extends BaseEventHandler {
Event event = new Event(Event.TYPE_MAINTENANCE, position);
event.setMaintenanceId(maintenance.getId());
event.set(maintenance.getType(), newValue);
- events.put(event, position);
+ callback.eventDetected(event);
}
}
}
}
-
- return events;
}
private double getValue(Position position, String type) {
diff --git a/src/main/java/org/traccar/handler/events/MediaEventHandler.java b/src/main/java/org/traccar/handler/events/MediaEventHandler.java
index 52d8e6961..2745296c4 100644
--- a/src/main/java/org/traccar/handler/events/MediaEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/MediaEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2022 - 2024 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.
@@ -15,18 +15,12 @@
*/
package org.traccar.handler.events;
-import io.netty.channel.ChannelHandler;
+import jakarta.inject.Inject;
import org.traccar.model.Event;
import org.traccar.model.Position;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-import java.util.Map;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
-@Singleton
-@ChannelHandler.Sharable
public class MediaEventHandler extends BaseEventHandler {
@Inject
@@ -34,8 +28,8 @@ public class MediaEventHandler extends BaseEventHandler {
}
@Override
- protected Map<Event, Position> analyzePosition(Position position) {
- return Stream.of(Position.KEY_IMAGE, Position.KEY_VIDEO, Position.KEY_AUDIO)
+ public void analyzePosition(Position position, Callback callback) {
+ Stream.of(Position.KEY_IMAGE, Position.KEY_VIDEO, Position.KEY_AUDIO)
.filter(position::hasAttribute)
.map(type -> {
Event event = new Event(Event.TYPE_MEDIA, position);
@@ -43,7 +37,7 @@ public class MediaEventHandler extends BaseEventHandler {
event.set("file", position.getString(type));
return event;
})
- .collect(Collectors.toMap(event -> event, event -> position));
+ .forEach(callback::eventDetected);
}
}
diff --git a/src/main/java/org/traccar/handler/events/MotionEventHandler.java b/src/main/java/org/traccar/handler/events/MotionEventHandler.java
index 15902d6d4..41d68985b 100644
--- a/src/main/java/org/traccar/handler/events/MotionEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/MotionEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,13 @@
*/
package org.traccar.handler.events;
-import io.netty.channel.ChannelHandler;
+import jakarta.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.config.Keys;
import org.traccar.helper.model.AttributeUtil;
import org.traccar.helper.model.PositionUtil;
import org.traccar.model.Device;
-import org.traccar.model.Event;
import org.traccar.model.Position;
import org.traccar.reports.common.TripsConfig;
import org.traccar.session.cache.CacheManager;
@@ -35,13 +34,6 @@ import org.traccar.storage.query.Columns;
import org.traccar.storage.query.Condition;
import org.traccar.storage.query.Request;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-import java.util.Collections;
-import java.util.Map;
-
-@Singleton
-@ChannelHandler.Sharable
public class MotionEventHandler extends BaseEventHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(MotionEventHandler.class);
@@ -56,17 +48,17 @@ public class MotionEventHandler extends BaseEventHandler {
}
@Override
- protected Map<Event, Position> analyzePosition(Position position) {
+ public void analyzePosition(Position position, Callback callback) {
long deviceId = position.getDeviceId();
Device device = cacheManager.getObject(Device.class, deviceId);
if (device == null || !PositionUtil.isLatest(cacheManager, position)) {
- return null;
+ return;
}
boolean processInvalid = AttributeUtil.lookup(
cacheManager, Keys.EVENT_MOTION_PROCESS_INVALID_POSITIONS, deviceId);
if (!processInvalid && !position.getValid()) {
- return null;
+ return;
}
TripsConfig tripsConfig = new TripsConfig(new AttributeUtil.CacheProvider(cacheManager, deviceId));
@@ -82,7 +74,9 @@ public class MotionEventHandler extends BaseEventHandler {
LOGGER.warn("Update device motion error", e);
}
}
- return state.getEvent() != null ? Collections.singletonMap(state.getEvent(), position) : null;
+ if (state.getEvent() != null) {
+ callback.eventDetected(state.getEvent());
+ }
}
}
diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java
index 3bb5f713c..9598581e6 100644
--- a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
*/
package org.traccar.handler.events;
-import io.netty.channel.ChannelHandler;
+import jakarta.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.config.Config;
@@ -24,7 +24,6 @@ import org.traccar.config.Keys;
import org.traccar.helper.model.AttributeUtil;
import org.traccar.helper.model.PositionUtil;
import org.traccar.model.Device;
-import org.traccar.model.Event;
import org.traccar.model.Geofence;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
@@ -36,13 +35,6 @@ import org.traccar.storage.query.Columns;
import org.traccar.storage.query.Condition;
import org.traccar.storage.query.Request;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-import java.util.Collections;
-import java.util.Map;
-
-@Singleton
-@ChannelHandler.Sharable
public class OverspeedEventHandler extends BaseEventHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(OverspeedEventHandler.class);
@@ -55,8 +47,7 @@ public class OverspeedEventHandler extends BaseEventHandler {
private final double multiplier;
@Inject
- public OverspeedEventHandler(
- Config config, CacheManager cacheManager, Storage storage) {
+ public OverspeedEventHandler(Config config, CacheManager cacheManager, Storage storage) {
this.cacheManager = cacheManager;
this.storage = storage;
minimalDuration = config.getLong(Keys.EVENT_OVERSPEED_MINIMAL_DURATION) * 1000;
@@ -65,15 +56,15 @@ public class OverspeedEventHandler extends BaseEventHandler {
}
@Override
- protected Map<Event, Position> analyzePosition(Position position) {
+ public void analyzePosition(Position position, Callback callback) {
long deviceId = position.getDeviceId();
Device device = cacheManager.getObject(Device.class, position.getDeviceId());
if (device == null) {
- return null;
+ return;
}
if (!PositionUtil.isLatest(cacheManager, position) || !position.getValid()) {
- return null;
+ return;
}
double speedLimit = AttributeUtil.lookup(cacheManager, Keys.EVENT_OVERSPEED_LIMIT, deviceId);
@@ -105,7 +96,7 @@ public class OverspeedEventHandler extends BaseEventHandler {
}
if (speedLimit == 0) {
- return null;
+ return;
}
OverspeedState state = OverspeedState.fromDevice(device);
@@ -120,7 +111,9 @@ public class OverspeedEventHandler extends BaseEventHandler {
LOGGER.warn("Update device overspeed error", e);
}
}
- return state.getEvent() != null ? Collections.singletonMap(state.getEvent(), position) : null;
+ if (state.getEvent() != null) {
+ callback.eventDetected(state.getEvent());
+ }
}
}
diff --git a/src/main/java/org/traccar/handler/AcknowledgementHandler.java b/src/main/java/org/traccar/handler/network/AcknowledgementHandler.java
index 4c1085998..e87f5d34c 100644
--- a/src/main/java/org/traccar/handler/AcknowledgementHandler.java
+++ b/src/main/java/org/traccar/handler/network/AcknowledgementHandler.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.handler;
+package org.traccar.handler.network;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
diff --git a/src/main/java/org/traccar/handler/network/MainEventHandler.java b/src/main/java/org/traccar/handler/network/MainEventHandler.java
new file mode 100644
index 000000000..901036d44
--- /dev/null
+++ b/src/main/java/org/traccar/handler/network/MainEventHandler.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2012 - 2022 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.handler.network;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.channel.socket.DatagramChannel;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.timeout.IdleStateEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.BasePipelineFactory;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.database.StatisticsManager;
+import org.traccar.helper.DateUtil;
+import org.traccar.helper.NetworkUtil;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Device;
+import org.traccar.model.Position;
+import org.traccar.session.ConnectionManager;
+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.Request;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+@Singleton
+@ChannelHandler.Sharable
+public class MainEventHandler extends ChannelInboundHandlerAdapter {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(MainEventHandler.class);
+
+ private final Set<String> connectionlessProtocols = new HashSet<>();
+ private final Set<String> logAttributes = new LinkedHashSet<>();
+
+ private final CacheManager cacheManager;
+ private final Storage storage;
+ private final ConnectionManager connectionManager;
+ private final StatisticsManager statisticsManager;
+
+ @Inject
+ public MainEventHandler(
+ Config config, CacheManager cacheManager, Storage storage, ConnectionManager connectionManager,
+ StatisticsManager statisticsManager) {
+ this.cacheManager = cacheManager;
+ this.storage = storage;
+ this.connectionManager = connectionManager;
+ this.statisticsManager = statisticsManager;
+ String connectionlessProtocolList = config.getString(Keys.STATUS_IGNORE_OFFLINE);
+ if (connectionlessProtocolList != null) {
+ connectionlessProtocols.addAll(Arrays.asList(connectionlessProtocolList.split("[, ]")));
+ }
+ logAttributes.addAll(Arrays.asList(config.getString(Keys.LOGGER_ATTRIBUTES).split("[, ]")));
+ }
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) {
+ if (msg instanceof Position) {
+
+ Position position = (Position) msg;
+ Device device = cacheManager.getObject(Device.class, position.getDeviceId());
+
+ try {
+ if (PositionUtil.isLatest(cacheManager, position)) {
+ Device updatedDevice = new Device();
+ updatedDevice.setId(position.getDeviceId());
+ updatedDevice.setPositionId(position.getId());
+ storage.updateObject(updatedDevice, new Request(
+ new Columns.Include("positionId"),
+ new Condition.Equals("id", updatedDevice.getId())));
+
+ cacheManager.updatePosition(position);
+ connectionManager.updatePosition(true, position);
+ }
+ } catch (StorageException error) {
+ LOGGER.warn("Failed to update device", error);
+ }
+
+ StringBuilder builder = new StringBuilder();
+ builder.append("[").append(NetworkUtil.session(ctx.channel())).append("] ");
+ builder.append("id: ").append(device.getUniqueId());
+ for (String attribute : logAttributes) {
+ switch (attribute) {
+ case "time":
+ builder.append(", time: ").append(DateUtil.formatDate(position.getFixTime(), false));
+ break;
+ case "position":
+ builder.append(", lat: ").append(String.format("%.5f", position.getLatitude()));
+ builder.append(", lon: ").append(String.format("%.5f", position.getLongitude()));
+ break;
+ case "speed":
+ if (position.getSpeed() > 0) {
+ builder.append(", speed: ").append(String.format("%.1f", position.getSpeed()));
+ }
+ break;
+ case "course":
+ builder.append(", course: ").append(String.format("%.1f", position.getCourse()));
+ break;
+ case "accuracy":
+ if (position.getAccuracy() > 0) {
+ builder.append(", accuracy: ").append(String.format("%.1f", position.getAccuracy()));
+ }
+ break;
+ case "outdated":
+ if (position.getOutdated()) {
+ builder.append(", outdated");
+ }
+ break;
+ case "invalid":
+ if (!position.getValid()) {
+ builder.append(", invalid");
+ }
+ break;
+ default:
+ Object value = position.getAttributes().get(attribute);
+ if (value != null) {
+ builder.append(", ").append(attribute).append(": ").append(value);
+ }
+ break;
+ }
+ }
+ LOGGER.info(builder.toString());
+
+ statisticsManager.registerMessageStored(position.getDeviceId(), position.getProtocol());
+
+ ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(position));
+ }
+ }
+
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) {
+ if (!(ctx.channel() instanceof DatagramChannel)) {
+ LOGGER.info("[{}] connected", NetworkUtil.session(ctx.channel()));
+ }
+ }
+
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) {
+ LOGGER.info("[{}] disconnected", NetworkUtil.session(ctx.channel()));
+ closeChannel(ctx.channel());
+
+ boolean supportsOffline = BasePipelineFactory.getHandler(ctx.pipeline(), HttpRequestDecoder.class) == null
+ && !connectionlessProtocols.contains(ctx.pipeline().get(BaseProtocolDecoder.class).getProtocolName());
+ connectionManager.deviceDisconnected(ctx.channel(), supportsOffline);
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+ while (cause.getCause() != null && cause.getCause() != cause) {
+ cause = cause.getCause();
+ }
+ LOGGER.info("[{}] error", NetworkUtil.session(ctx.channel()), cause);
+ closeChannel(ctx.channel());
+ }
+
+ @Override
+ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
+ if (evt instanceof IdleStateEvent) {
+ LOGGER.info("[{}] timed out", NetworkUtil.session(ctx.channel()));
+ closeChannel(ctx.channel());
+ }
+ }
+
+ private void closeChannel(Channel channel) {
+ if (!(channel instanceof DatagramChannel)) {
+ channel.close();
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/handler/NetworkForwarderHandler.java b/src/main/java/org/traccar/handler/network/NetworkForwarderHandler.java
index 470e175ca..5f07ce355 100644
--- a/src/main/java/org/traccar/handler/NetworkForwarderHandler.java
+++ b/src/main/java/org/traccar/handler/network/NetworkForwarderHandler.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.handler;
+package org.traccar.handler.network;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
diff --git a/src/main/java/org/traccar/handler/NetworkMessageHandler.java b/src/main/java/org/traccar/handler/network/NetworkMessageHandler.java
index b1d926bfa..c2fb9016a 100644
--- a/src/main/java/org/traccar/handler/NetworkMessageHandler.java
+++ b/src/main/java/org/traccar/handler/network/NetworkMessageHandler.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.handler;
+package org.traccar.handler.network;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelDuplexHandler;
diff --git a/src/main/java/org/traccar/handler/OpenChannelHandler.java b/src/main/java/org/traccar/handler/network/OpenChannelHandler.java
index e416f35ae..21aaae676 100644
--- a/src/main/java/org/traccar/handler/OpenChannelHandler.java
+++ b/src/main/java/org/traccar/handler/network/OpenChannelHandler.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.handler;
+package org.traccar.handler.network;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
diff --git a/src/main/java/org/traccar/handler/RemoteAddressHandler.java b/src/main/java/org/traccar/handler/network/RemoteAddressHandler.java
index 61ada5b91..d545ed799 100644
--- a/src/main/java/org/traccar/handler/RemoteAddressHandler.java
+++ b/src/main/java/org/traccar/handler/network/RemoteAddressHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2024 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.
@@ -13,20 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.handler;
+package org.traccar.handler.network;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
+import jakarta.inject.Inject;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Position;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
import java.net.InetSocketAddress;
-@Singleton
@ChannelHandler.Sharable
public class RemoteAddressHandler extends ChannelInboundHandlerAdapter {
diff --git a/src/main/java/org/traccar/handler/StandardLoggingHandler.java b/src/main/java/org/traccar/handler/network/StandardLoggingHandler.java
index 513602dd8..dae93655d 100644
--- a/src/main/java/org/traccar/handler/StandardLoggingHandler.java
+++ b/src/main/java/org/traccar/handler/network/StandardLoggingHandler.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.handler;
+package org.traccar.handler.network;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;