diff options
Diffstat (limited to 'src/main/java/org/traccar/handler')
28 files changed, 508 insertions, 187 deletions
diff --git a/src/main/java/org/traccar/handler/AcknowledgementHandler.java b/src/main/java/org/traccar/handler/AcknowledgementHandler.java new file mode 100644 index 000000000..4c1085998 --- /dev/null +++ b/src/main/java/org/traccar/handler/AcknowledgementHandler.java @@ -0,0 +1,121 @@ +/* + * Copyright 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. + * 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.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOutboundHandlerAdapter; +import io.netty.channel.ChannelPromise; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +public class AcknowledgementHandler extends ChannelOutboundHandlerAdapter { + + private static final Logger LOGGER = LoggerFactory.getLogger(AcknowledgementHandler.class); + + public interface Event { + } + + public static class EventReceived implements Event { + } + + public static class EventDecoded implements Event { + private final Collection<Object> objects; + + public EventDecoded(Collection<Object> objects) { + this.objects = objects; + } + + public Collection<Object> getObjects() { + return objects; + } + } + + public static class EventHandled implements Event { + private final Object object; + + public EventHandled(Object object) { + this.object = object; + } + + public Object getObject() { + return object; + } + } + + private static final class Entry { + private final Object message; + private final ChannelPromise promise; + + private Entry(Object message, ChannelPromise promise) { + this.message = message; + this.promise = promise; + } + + public Object getMessage() { + return message; + } + + public ChannelPromise getPromise() { + return promise; + } + } + + private List<Entry> queue; + private final Set<Object> waiting = new HashSet<>(); + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + List<Entry> output = new LinkedList<>(); + synchronized (this) { + if (msg instanceof Event) { + if (msg instanceof EventReceived) { + LOGGER.debug("Event received"); + if (queue == null) { + queue = new LinkedList<>(); + } + } else if (msg instanceof EventDecoded) { + EventDecoded event = (EventDecoded) msg; + LOGGER.debug("Event decoded {}", event.getObjects().size()); + waiting.addAll(event.getObjects()); + } else if (msg instanceof EventHandled) { + EventHandled event = (EventHandled) msg; + LOGGER.debug("Event handled"); + waiting.remove(event.getObject()); + } + if (!(msg instanceof EventReceived) && waiting.isEmpty()) { + output.addAll(queue); + queue = null; + } + } else if (queue != null) { + LOGGER.debug("Message queued"); + queue.add(new Entry(msg, promise)); + } else { + LOGGER.debug("Message sent"); + output.add(new Entry(msg, promise)); + } + } + for (Entry entry : output) { + ctx.write(entry.getMessage(), entry.getPromise()); + } + } + +} diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 620852502..8b010ceae 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -24,11 +24,15 @@ 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.jexl2.JexlEngine; -import org.apache.commons.jexl2.JexlException; -import org.apache.commons.jexl2.MapContext; +import org.apache.commons.jexl3.JexlFeatures; +import org.apache.commons.jexl3.JexlEngine; +import org.apache.commons.jexl3.JexlBuilder; +import org.apache.commons.jexl3.introspection.JexlSandbox; +import org.apache.commons.jexl3.JexlException; +import org.apache.commons.jexl3.MapContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.BaseDataHandler; @@ -39,8 +43,8 @@ import org.traccar.model.Device; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable @@ -52,15 +56,33 @@ public class ComputedAttributesHandler extends BaseDataHandler { private final JexlEngine engine; + private final JexlFeatures features; + private final boolean includeDeviceAttributes; + private final boolean includeLastAttributes; @Inject public ComputedAttributesHandler(Config config, CacheManager cacheManager) { this.cacheManager = cacheManager; - engine = new JexlEngine(); - engine.setStrict(true); - engine.setFunctions(Collections.singletonMap("math", Math.class)); + JexlSandbox sandbox = new JexlSandbox(false); + sandbox.allow("com.safe.Functions"); + sandbox.allow(Math.class.getName()); + List.of( + Double.class, Float.class, Integer.class, Long.class, Short.class, + Character.class, Boolean.class, String.class, Byte.class) + .forEach((type) -> sandbox.allow(type.getName())); + features = new JexlFeatures() + .localVar(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES)) + .loops(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOOPS)) + .newInstance(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_NEW_INSTANCE_CREATION)) + .structuredLiteral(true); + engine = new JexlBuilder() + .strict(true) + .namespaces(Collections.singletonMap("math", Math.class)) + .sandbox(sandbox) + .create(); includeDeviceAttributes = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES); + includeLastAttributes = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LAST_ATTRIBUTES); } private MapContext prepareContext(Position position) { @@ -68,13 +90,17 @@ public class ComputedAttributesHandler extends BaseDataHandler { if (includeDeviceAttributes) { Device device = cacheManager.getObject(Device.class, position.getDeviceId()); if (device != null) { - for (Object key : device.getAttributes().keySet()) { - result.set((String) key, device.getAttributes().get(key)); + for (String key : device.getAttributes().keySet()) { + result.set(key, device.getAttributes().get(key)); } } } + Position last = null; + if (includeLastAttributes) { + last = cacheManager.getPosition(position.getDeviceId()); + } Set<Method> methods = new HashSet<>(Arrays.asList(position.getClass().getMethods())); - methods.removeAll(Arrays.asList(Object.class.getMethods())); + Arrays.asList(Object.class.getMethods()).forEach(methods::remove); for (Method method : methods) { if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { String name = Character.toLowerCase(method.getName().charAt(3)) + method.getName().substring(4); @@ -82,9 +108,17 @@ public class ComputedAttributesHandler extends BaseDataHandler { try { if (!method.getReturnType().equals(Map.class)) { result.set(name, method.invoke(position)); + if (last != null) { + result.set(prefixAttribute("last", name), method.invoke(last)); + } } else { - for (Object key : ((Map) method.invoke(position)).keySet()) { - result.set((String) key, ((Map) method.invoke(position)).get(key)); + for (Map.Entry<?, ?> entry : ((Map<?, ?>) method.invoke(position)).entrySet()) { + result.set((String) entry.getKey(), entry.getValue()); + } + if (last != null) { + for (Map.Entry<?, ?> entry : ((Map<?, ?>) method.invoke(last)).entrySet()) { + result.set(prefixAttribute("last", (String) entry.getKey()), entry.getValue()); + } } } } catch (IllegalAccessException | InvocationTargetException error) { @@ -95,12 +129,18 @@ public class ComputedAttributesHandler extends BaseDataHandler { return result; } + private String prefixAttribute(String prefix, String key) { + return prefix + Character.toUpperCase(key.charAt(0)) + key.substring(1); + } + /** * @deprecated logic needs to be extracted to be used in API resource */ @Deprecated public Object computeAttribute(Attribute attribute, Position position) throws JexlException { - return engine.createExpression(attribute.getExpression()).evaluate(prepareContext(position)); + return engine + .createScript(features, engine.createInfo(), attribute.getExpression()) + .execute(prepareContext(position)); } @Override diff --git a/src/main/java/org/traccar/handler/CopyAttributesHandler.java b/src/main/java/org/traccar/handler/CopyAttributesHandler.java index e5c9bc29a..42b438e41 100644 --- a/src/main/java/org/traccar/handler/CopyAttributesHandler.java +++ b/src/main/java/org/traccar/handler/CopyAttributesHandler.java @@ -24,8 +24,8 @@ import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/DefaultDataHandler.java b/src/main/java/org/traccar/handler/DefaultDataHandler.java index 89255a5fe..cca6dcd0a 100644 --- a/src/main/java/org/traccar/handler/DefaultDataHandler.java +++ b/src/main/java/org/traccar/handler/DefaultDataHandler.java @@ -24,8 +24,8 @@ import org.traccar.storage.Storage; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/DistanceHandler.java b/src/main/java/org/traccar/handler/DistanceHandler.java index 30dc9ff2b..db8c73779 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 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2015 Amila Silva * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,6 +17,8 @@ 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; @@ -24,11 +26,6 @@ import org.traccar.helper.DistanceCalculator; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.math.BigDecimal; -import java.math.RoundingMode; - @Singleton @ChannelHandler.Sharable public class DistanceHandler extends BaseDataHandler { @@ -36,15 +33,15 @@ public class DistanceHandler extends BaseDataHandler { private final CacheManager cacheManager; private final boolean filter; - private final int coordinatesMinError; - private final int coordinatesMaxError; + private final int minError; + private final int maxError; @Inject public DistanceHandler(Config config, CacheManager cacheManager) { this.cacheManager = cacheManager; this.filter = config.getBoolean(Keys.COORDINATES_FILTER); - this.coordinatesMinError = config.getInteger(Keys.COORDINATES_MIN_ERROR); - this.coordinatesMaxError = config.getInteger(Keys.COORDINATES_MAX_ERROR); + this.minError = config.getInteger(Keys.COORDINATES_MIN_ERROR); + this.maxError = config.getInteger(Keys.COORDINATES_MAX_ERROR); } @Override @@ -54,8 +51,7 @@ public class DistanceHandler extends BaseDataHandler { if (position.hasAttribute(Position.KEY_DISTANCE)) { distance = position.getDouble(Position.KEY_DISTANCE); } - double totalDistance = 0.0; - + double totalDistance; Position last = cacheManager.getPosition(position.getDeviceId()); if (last != null) { totalDistance = last.getDouble(Position.KEY_TOTAL_DISTANCE); @@ -63,11 +59,10 @@ public class DistanceHandler extends BaseDataHandler { distance = DistanceCalculator.distance( position.getLatitude(), position.getLongitude(), last.getLatitude(), last.getLongitude()); - distance = BigDecimal.valueOf(distance).setScale(2, RoundingMode.HALF_EVEN).doubleValue(); } if (filter && last.getLatitude() != 0 && last.getLongitude() != 0) { - boolean satisfiesMin = coordinatesMinError == 0 || distance > coordinatesMinError; - boolean satisfiesMax = coordinatesMaxError == 0 || distance < coordinatesMaxError; + boolean satisfiesMin = minError == 0 || distance > minError; + boolean satisfiesMax = maxError == 0 || distance < maxError || position.getValid(); if (!satisfiesMin || !satisfiesMax) { position.setValid(last.getValid()); position.setLatitude(last.getLatitude()); @@ -75,10 +70,11 @@ public class DistanceHandler extends BaseDataHandler { distance = 0; } } + } else { + totalDistance = 0.0; } position.set(Position.KEY_DISTANCE, distance); - totalDistance = BigDecimal.valueOf(totalDistance + distance).setScale(2, RoundingMode.HALF_EVEN).doubleValue(); - position.set(Position.KEY_TOTAL_DISTANCE, totalDistance); + position.set(Position.KEY_TOTAL_DISTANCE, totalDistance + distance); return position; } diff --git a/src/main/java/org/traccar/handler/EngineHoursHandler.java b/src/main/java/org/traccar/handler/EngineHoursHandler.java index c10fe9064..621205b34 100644 --- a/src/main/java/org/traccar/handler/EngineHoursHandler.java +++ b/src/main/java/org/traccar/handler/EngineHoursHandler.java @@ -21,8 +21,8 @@ import org.traccar.BaseDataHandler; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index 994276bb6..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 - 2022 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,13 +16,16 @@ 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.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; @@ -33,13 +36,13 @@ import org.traccar.storage.query.Condition; import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +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); @@ -47,6 +50,7 @@ public class FilterHandler extends BaseDataHandler { 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; @@ -55,19 +59,23 @@ public class FilterHandler extends BaseDataHandler { 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) { + 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); @@ -76,11 +84,13 @@ public class FilterHandler extends BaseDataHandler { filterDistance = config.getInteger(Keys.FILTER_DISTANCE); filterMaxSpeed = config.getInteger(Keys.FILTER_MAX_SPEED); 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 { @@ -114,6 +124,10 @@ 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; } @@ -158,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; @@ -177,7 +198,7 @@ public class FilterHandler extends BaseDataHandler { return false; } - private boolean filter(Position position) { + protected boolean filter(Position position) { StringBuilder filterType = new StringBuilder(); @@ -188,6 +209,9 @@ public class FilterHandler extends BaseDataHandler { if (filterZero(position)) { filterType.append("Zero "); } + if (filterOutdated(position)) { + filterType.append("Outdated "); + } if (filterFuture(position)) { filterType.append("Future "); } @@ -200,6 +224,9 @@ public class FilterHandler extends BaseDataHandler { if (filterApproximate(position)) { filterType.append("Approximate "); } + if (filterDailyLimit(position)) { + filterType.append("DailyLimit "); + } // filter out excessive data long deviceId = position.getDeviceId(); @@ -233,9 +260,16 @@ public class FilterHandler extends BaseDataHandler { } } + 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 "); + } + } + if (filterType.length() > 0) { - String uniqueId = cacheManager.getObject(Device.class, deviceId).getUniqueId(); - LOGGER.info("Position filtered by {}filters from device: {}", filterType, uniqueId); + LOGGER.info("Position filtered by {}filters from device: {}", filterType, device.getUniqueId()); return true; } @@ -243,11 +277,17 @@ public class FilterHandler extends BaseDataHandler { } @Override - protected Position handlePosition(Position position) { - if (enabled && 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; } } diff --git a/src/main/java/org/traccar/handler/GeofenceHandler.java b/src/main/java/org/traccar/handler/GeofenceHandler.java new file mode 100644 index 000000000..68bc6dbf0 --- /dev/null +++ b/src/main/java/org/traccar/handler/GeofenceHandler.java @@ -0,0 +1,52 @@ +/* + * Copyright 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. + * 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.channel.ChannelHandler; +import org.traccar.BaseDataHandler; +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 { + + private final Config config; + private final CacheManager cacheManager; + + @Inject + public GeofenceHandler(Config config, CacheManager cacheManager) { + this.config = config; + this.cacheManager = cacheManager; + } + + @Override + protected Position handlePosition(Position position) { + + List<Long> geofenceIds = GeofenceUtil.getCurrentGeofences(config, cacheManager, position); + if (!geofenceIds.isEmpty()) { + position.setGeofenceIds(geofenceIds); + } + return position; + } + +} diff --git a/src/main/java/org/traccar/handler/GeolocationHandler.java b/src/main/java/org/traccar/handler/GeolocationHandler.java index e7389f22d..a54ea03e3 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 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -37,6 +37,7 @@ public class GeolocationHandler extends ChannelInboundHandlerAdapter { private final StatisticsManager statisticsManager; private final boolean processInvalidPositions; private final boolean reuse; + private final boolean requireWifi; public GeolocationHandler( Config config, GeolocationProvider geolocationProvider, CacheManager cacheManager, @@ -46,6 +47,7 @@ public class GeolocationHandler extends ChannelInboundHandlerAdapter { this.statisticsManager = statisticsManager; processInvalidPositions = config.getBoolean(Keys.GEOLOCATION_PROCESS_INVALID_POSITIONS); reuse = config.getBoolean(Keys.GEOLOCATION_REUSE); + requireWifi = config.getBoolean(Keys.GEOLOCATION_REQUIRE_WIFI); } @Override @@ -53,7 +55,8 @@ public class GeolocationHandler extends ChannelInboundHandlerAdapter { if (message instanceof Position) { final Position position = (Position) message; if ((position.getOutdated() || processInvalidPositions && !position.getValid()) - && position.getNetwork() != null) { + && position.getNetwork() != null + && (!requireWifi || position.getNetwork().getWifiAccessPoints() != null)) { if (reuse) { Position lastPosition = cacheManager.getPosition(position.getDeviceId()); if (lastPosition != null && position.getNetwork().equals(lastPosition.getNetwork())) { diff --git a/src/main/java/org/traccar/handler/HemisphereHandler.java b/src/main/java/org/traccar/handler/HemisphereHandler.java index ccbde9fe5..294e449db 100644 --- a/src/main/java/org/traccar/handler/HemisphereHandler.java +++ b/src/main/java/org/traccar/handler/HemisphereHandler.java @@ -21,8 +21,8 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Position; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/MotionHandler.java b/src/main/java/org/traccar/handler/MotionHandler.java index 10312f9b3..68a31a16a 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 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,27 +18,31 @@ package org.traccar.handler; import io.netty.channel.ChannelHandler; import org.traccar.BaseDataHandler; +import org.traccar.config.Keys; +import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Position; -import org.traccar.reports.common.TripsConfig; +import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable public class MotionHandler extends BaseDataHandler { - private final double speedThreshold; + private final CacheManager cacheManager; @Inject - public MotionHandler(TripsConfig tripsConfig) { - speedThreshold = tripsConfig.getSpeedThreshold(); + public MotionHandler(CacheManager cacheManager) { + this.cacheManager = cacheManager; } @Override protected Position handlePosition(Position position) { if (!position.hasAttribute(Position.KEY_MOTION)) { - position.set(Position.KEY_MOTION, position.getSpeed() > speedThreshold); + double threshold = AttributeUtil.lookup( + cacheManager, Keys.EVENT_MOTION_SPEED_THRESHOLD, position.getDeviceId()); + position.set(Position.KEY_MOTION, position.getSpeed() > threshold); } return position; } diff --git a/src/main/java/org/traccar/handler/NetworkForwarderHandler.java b/src/main/java/org/traccar/handler/NetworkForwarderHandler.java new file mode 100644 index 000000000..470e175ca --- /dev/null +++ b/src/main/java/org/traccar/handler/NetworkForwarderHandler.java @@ -0,0 +1,72 @@ +/* + * Copyright 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. + * 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.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.socket.DatagramChannel; +import io.netty.channel.socket.DatagramPacket; +import org.traccar.forward.NetworkForwarder; + +import jakarta.inject.Inject; +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +public class NetworkForwarderHandler extends ChannelInboundHandlerAdapter { + + private final int port; + + private NetworkForwarder networkForwarder; + + public NetworkForwarderHandler(int port) { + this.port = port; + } + + @Inject + public void setNetworkForwarder(NetworkForwarder networkForwarder) { + this.networkForwarder = networkForwarder; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + boolean datagram = ctx.channel() instanceof DatagramChannel; + SocketAddress remoteAddress; + ByteBuf buffer; + if (datagram) { + DatagramPacket message = (DatagramPacket) msg; + remoteAddress = message.recipient(); + buffer = message.content(); + } else { + remoteAddress = ctx.channel().remoteAddress(); + buffer = (ByteBuf) msg; + } + + byte[] data = new byte[buffer.readableBytes()]; + buffer.getBytes(buffer.readerIndex(), data); + networkForwarder.forward((InetSocketAddress) remoteAddress, port, datagram, data); + super.channelRead(ctx, msg); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (!(ctx.channel() instanceof DatagramChannel)) { + networkForwarder.disconnect((InetSocketAddress) ctx.channel().remoteAddress()); + } + super.channelInactive(ctx); + } + +} diff --git a/src/main/java/org/traccar/handler/RemoteAddressHandler.java b/src/main/java/org/traccar/handler/RemoteAddressHandler.java index e18d34ef2..61ada5b91 100644 --- a/src/main/java/org/traccar/handler/RemoteAddressHandler.java +++ b/src/main/java/org/traccar/handler/RemoteAddressHandler.java @@ -22,8 +22,8 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Position; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.net.InetSocketAddress; @Singleton diff --git a/src/main/java/org/traccar/handler/SpeedLimitHandler.java b/src/main/java/org/traccar/handler/SpeedLimitHandler.java index 0c6025999..6edb6e912 100644 --- a/src/main/java/org/traccar/handler/SpeedLimitHandler.java +++ b/src/main/java/org/traccar/handler/SpeedLimitHandler.java @@ -23,8 +23,8 @@ import org.slf4j.LoggerFactory; import org.traccar.model.Position; import org.traccar.speedlimit.SpeedLimitProvider; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/StandardLoggingHandler.java b/src/main/java/org/traccar/handler/StandardLoggingHandler.java index 84492e2a5..5978d632e 100644 --- a/src/main/java/org/traccar/handler/StandardLoggingHandler.java +++ b/src/main/java/org/traccar/handler/StandardLoggingHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 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. @@ -20,68 +20,73 @@ import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; +import jakarta.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.NetworkMessage; import org.traccar.helper.NetworkUtil; +import org.traccar.model.LogRecord; +import org.traccar.session.ConnectionManager; import java.net.InetSocketAddress; -import java.net.SocketAddress; public class StandardLoggingHandler extends ChannelDuplexHandler { private static final Logger LOGGER = LoggerFactory.getLogger(StandardLoggingHandler.class); private final String protocol; + private ConnectionManager connectionManager; public StandardLoggingHandler(String protocol) { this.protocol = protocol; } + @Inject + public void setConnectionManager(ConnectionManager connectionManager) { + this.connectionManager = connectionManager; + } + @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - log(ctx, false, msg); + LogRecord record = createLogRecord(msg); + log(ctx, false, record); super.channelRead(ctx, msg); + if (record != null) { + connectionManager.updateLog(record); + } } @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - log(ctx, true, msg); + log(ctx, true, createLogRecord(msg)); super.write(ctx, msg, promise); } - public void log(ChannelHandlerContext ctx, boolean downstream, Object o) { - if (o instanceof NetworkMessage) { - NetworkMessage networkMessage = (NetworkMessage) o; + private LogRecord createLogRecord(Object msg) { + if (msg instanceof NetworkMessage) { + NetworkMessage networkMessage = (NetworkMessage) msg; if (networkMessage.getMessage() instanceof ByteBuf) { - log(ctx, downstream, networkMessage.getRemoteAddress(), (ByteBuf) networkMessage.getMessage()); + LogRecord record = new LogRecord(); + record.setAddress((InetSocketAddress) networkMessage.getRemoteAddress()); + record.setProtocol(protocol); + record.setData(ByteBufUtil.hexDump((ByteBuf) networkMessage.getMessage())); + return record; } - } else if (o instanceof ByteBuf) { - log(ctx, downstream, ctx.channel().remoteAddress(), (ByteBuf) o); } + return null; } - public void log(ChannelHandlerContext ctx, boolean downstream, SocketAddress remoteAddress, ByteBuf buf) { - StringBuilder message = new StringBuilder(); - - message.append("[").append(NetworkUtil.session(ctx.channel())).append(": "); - message.append(protocol); - if (downstream) { - message.append(" > "); - } else { - message.append(" < "); + private void log(ChannelHandlerContext ctx, boolean downstream, LogRecord record) { + if (record != null) { + StringBuilder message = new StringBuilder(); + message.append("[").append(NetworkUtil.session(ctx.channel())).append(": "); + message.append(protocol); + message.append(downstream ? " > " : " < "); + message.append(record.getAddress().getHostString()); + message.append("] "); + message.append(record.getData()); + LOGGER.info(message.toString()); } - - if (remoteAddress instanceof InetSocketAddress) { - message.append(((InetSocketAddress) remoteAddress).getHostString()); - } else { - message.append("unknown"); - } - message.append("] "); - - message.append(ByteBufUtil.hexDump(buf)); - - LOGGER.info(message.toString()); } } diff --git a/src/main/java/org/traccar/handler/TimeHandler.java b/src/main/java/org/traccar/handler/TimeHandler.java index c98b0bd4c..3c3e17450 100644 --- a/src/main/java/org/traccar/handler/TimeHandler.java +++ b/src/main/java/org/traccar/handler/TimeHandler.java @@ -23,8 +23,8 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Position; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Arrays; import java.util.HashSet; import java.util.Set; diff --git a/src/main/java/org/traccar/handler/events/AlertEventHandler.java b/src/main/java/org/traccar/handler/events/AlertEventHandler.java index 9f77df989..531a0f957 100644 --- a/src/main/java/org/traccar/handler/events/AlertEventHandler.java +++ b/src/main/java/org/traccar/handler/events/AlertEventHandler.java @@ -25,8 +25,8 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/events/BaseEventHandler.java b/src/main/java/org/traccar/handler/events/BaseEventHandler.java index 271aaa35d..4a4fb40ff 100644 --- a/src/main/java/org/traccar/handler/events/BaseEventHandler.java +++ b/src/main/java/org/traccar/handler/events/BaseEventHandler.java @@ -22,7 +22,7 @@ import org.traccar.database.NotificationManager; import org.traccar.model.Event; import org.traccar.model.Position; -import javax.inject.Inject; +import jakarta.inject.Inject; public abstract class BaseEventHandler extends BaseDataHandler { diff --git a/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java b/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java index 51bbd82d6..08ae35fcd 100644 --- a/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java +++ b/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java @@ -23,8 +23,8 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Collections; import java.util.Map; diff --git a/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java b/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java index 772176e9c..b70f8f33b 100644 --- a/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java +++ b/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java @@ -22,8 +22,8 @@ import io.netty.channel.ChannelHandler; import org.traccar.model.Event; import org.traccar.model.Position; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/events/DriverEventHandler.java b/src/main/java/org/traccar/handler/events/DriverEventHandler.java index 51fdc0307..b68327983 100644 --- a/src/main/java/org/traccar/handler/events/DriverEventHandler.java +++ b/src/main/java/org/traccar/handler/events/DriverEventHandler.java @@ -22,8 +22,8 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Collections; import java.util.Map; diff --git a/src/main/java/org/traccar/handler/events/FuelEventHandler.java b/src/main/java/org/traccar/handler/events/FuelEventHandler.java index 462cc4223..e5085ecc2 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 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 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. @@ -24,8 +24,8 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Map; @Singleton @@ -60,13 +60,13 @@ public class FuelEventHandler extends BaseEventHandler { if (change > 0) { double threshold = AttributeUtil.lookup( cacheManager, Keys.EVENT_FUEL_INCREASE_THRESHOLD, position.getDeviceId()); - if (change >= threshold) { + if (threshold > 0 && change >= threshold) { return Map.of(new Event(Event.TYPE_DEVICE_FUEL_INCREASE, position), position); } } else if (change < 0) { double threshold = AttributeUtil.lookup( cacheManager, Keys.EVENT_FUEL_DROP_THRESHOLD, position.getDeviceId()); - if (Math.abs(change) >= threshold) { + if (threshold > 0 && Math.abs(change) >= threshold) { return Map.of(new Event(Event.TYPE_DEVICE_FUEL_DROP, position), position); } } diff --git a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java index 9414f4b31..dbe2b8118 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 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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,24 +16,15 @@ package org.traccar.handler.events; import io.netty.channel.ChannelHandler; -import org.traccar.config.Config; -import org.traccar.helper.model.GeofenceUtil; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Calendar; -import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Geofence; 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 javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -43,62 +34,43 @@ import java.util.Map; @ChannelHandler.Sharable public class GeofenceEventHandler extends BaseEventHandler { - private final Config config; private final CacheManager cacheManager; - private final ConnectionManager connectionManager; - private final Storage storage; @Inject - public GeofenceEventHandler( - Config config, CacheManager cacheManager, ConnectionManager connectionManager, Storage storage) { - this.config = config; + public GeofenceEventHandler(CacheManager cacheManager) { this.cacheManager = cacheManager; - this.connectionManager = connectionManager; - this.storage = storage; } @Override protected Map<Event, Position> analyzePosition(Position position) { - Device device = cacheManager.getObject(Device.class, position.getDeviceId()); - if (device == null) { - return null; - } - if (!PositionUtil.isLatest(cacheManager, position) || !position.getValid()) { + if (!PositionUtil.isLatest(cacheManager, position)) { return null; } - List<Long> currentGeofences = GeofenceUtil.getCurrentGeofences(config, cacheManager, position); List<Long> oldGeofences = new ArrayList<>(); - if (device.getGeofenceIds() != null) { - oldGeofences.addAll(device.getGeofenceIds()); + Position lastPosition = cacheManager.getPosition(position.getDeviceId()); + if (lastPosition != null && lastPosition.getGeofenceIds() != null) { + oldGeofences.addAll(lastPosition.getGeofenceIds()); } - List<Long> newGeofences = new ArrayList<>(currentGeofences); - newGeofences.removeAll(oldGeofences); - oldGeofences.removeAll(currentGeofences); - - - if (!oldGeofences.isEmpty() || !newGeofences.isEmpty()) { - device.setGeofenceIds(currentGeofences.isEmpty() ? null : currentGeofences); - - try { - storage.updateObject(device, new Request( - new Columns.Include("geofenceIds"), - new Condition.Equals("id", device.getId()))); - } catch (StorageException e) { - throw new RuntimeException("Update device geofences error", e); - } - connectionManager.updateDevice(true, device); + List<Long> newGeofences = new ArrayList<>(); + if (position.getGeofenceIds() != null) { + newGeofences.addAll(position.getGeofenceIds()); + newGeofences.removeAll(oldGeofences); + oldGeofences.removeAll(position.getGeofenceIds()); } Map<Event, Position> events = new HashMap<>(); for (long geofenceId : oldGeofences) { - long calendarId = cacheManager.getObject(Geofence.class, geofenceId).getCalendarId(); - Calendar calendar = calendarId != 0 ? cacheManager.getObject(Calendar.class, calendarId) : null; - if (calendar == null || calendar.checkMoment(position.getFixTime())) { - Event event = new Event(Event.TYPE_GEOFENCE_EXIT, position); - event.setGeofenceId(geofenceId); - events.put(event, position); + Geofence geofence = cacheManager.getObject(Geofence.class, geofenceId); + if (geofence != null) { + long calendarId = geofence.getCalendarId(); + Calendar calendar = calendarId != 0 ? cacheManager.getObject(Calendar.class, calendarId) : null; + if (calendar == null || calendar.checkMoment(position.getFixTime())) { + Event event = new Event(Event.TYPE_GEOFENCE_EXIT, position); + event.setGeofenceId(geofenceId); + events.put(event, position); + } } } for (long geofenceId : newGeofences) { diff --git a/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java b/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java index b2e9a3325..ba4159a42 100644 --- a/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java +++ b/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java @@ -26,8 +26,8 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable diff --git a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java index 909950acf..2fa2e8869 100644 --- a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,8 +25,8 @@ import org.traccar.model.Maintenance; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; @Singleton @ChannelHandler.Sharable @@ -49,8 +49,8 @@ public class MaintenanceEventHandler extends BaseEventHandler { Map<Event, Position> events = new HashMap<>(); for (Maintenance maintenance : cacheManager.getDeviceObjects(position.getDeviceId(), Maintenance.class)) { if (maintenance.getPeriod() != 0) { - double oldValue = lastPosition.getDouble(maintenance.getType()); - double newValue = position.getDouble(maintenance.getType()); + double oldValue = getValue(lastPosition, maintenance.getType()); + double newValue = getValue(position, maintenance.getType()); if (oldValue != 0.0 && newValue != 0.0 && newValue >= maintenance.getStart()) { if (oldValue < maintenance.getStart() || (long) ((oldValue - maintenance.getStart()) / maintenance.getPeriod()) @@ -67,4 +67,17 @@ public class MaintenanceEventHandler extends BaseEventHandler { return events; } + private double getValue(Position position, String type) { + switch (type) { + case "serverTime": + return position.getServerTime().getTime(); + case "deviceTime": + return position.getDeviceTime().getTime(); + case "fixTime": + return position.getFixTime().getTime(); + default: + return position.getDouble(type); + } + } + } diff --git a/src/main/java/org/traccar/handler/events/MediaEventHandler.java b/src/main/java/org/traccar/handler/events/MediaEventHandler.java index a49e08e8d..52d8e6961 100644 --- a/src/main/java/org/traccar/handler/events/MediaEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MediaEventHandler.java @@ -19,8 +19,8 @@ import io.netty.channel.ChannelHandler; import org.traccar.model.Event; import org.traccar.model.Position; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; diff --git a/src/main/java/org/traccar/handler/events/MotionEventHandler.java b/src/main/java/org/traccar/handler/events/MotionEventHandler.java index c406bd935..15902d6d4 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 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,6 +19,8 @@ package org.traccar.handler.events; import io.netty.channel.ChannelHandler; 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; @@ -33,8 +35,8 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Collections; import java.util.Map; @@ -46,14 +48,11 @@ public class MotionEventHandler extends BaseEventHandler { private final CacheManager cacheManager; private final Storage storage; - private final TripsConfig tripsConfig; @Inject - public MotionEventHandler( - CacheManager cacheManager, Storage storage, TripsConfig tripsConfig) { + public MotionEventHandler(CacheManager cacheManager, Storage storage) { this.cacheManager = cacheManager; this.storage = storage; - this.tripsConfig = tripsConfig; } @Override @@ -61,14 +60,16 @@ public class MotionEventHandler extends BaseEventHandler { long deviceId = position.getDeviceId(); Device device = cacheManager.getObject(Device.class, deviceId); - if (device == null) { + if (device == null || !PositionUtil.isLatest(cacheManager, position)) { return null; } - if (!PositionUtil.isLatest(cacheManager, position) - || !tripsConfig.getProcessInvalidPositions() && !position.getValid()) { + boolean processInvalid = AttributeUtil.lookup( + cacheManager, Keys.EVENT_MOTION_PROCESS_INVALID_POSITIONS, deviceId); + if (!processInvalid && !position.getValid()) { return null; } + TripsConfig tripsConfig = new TripsConfig(new AttributeUtil.CacheProvider(cacheManager, deviceId)); MotionState state = MotionState.fromDevice(device); MotionProcessor.updateState(state, position, position.getBoolean(Position.KEY_MOTION), tripsConfig); if (state.isChanged()) { diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java index 4d6aa8857..3bb5f713c 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 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,8 +36,8 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import javax.inject.Inject; -import javax.inject.Singleton; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import java.util.Collections; import java.util.Map; @@ -52,6 +52,7 @@ public class OverspeedEventHandler extends BaseEventHandler { private final long minimalDuration; private final boolean preferLowest; + private final double multiplier; @Inject public OverspeedEventHandler( @@ -60,6 +61,7 @@ public class OverspeedEventHandler extends BaseEventHandler { this.storage = storage; minimalDuration = config.getLong(Keys.EVENT_OVERSPEED_MINIMAL_DURATION) * 1000; preferLowest = config.getBoolean(Keys.EVENT_OVERSPEED_PREFER_LOWEST); + multiplier = config.getDouble(Keys.EVENT_OVERSPEED_THRESHOLD_MULTIPLIER); } @Override @@ -84,8 +86,8 @@ public class OverspeedEventHandler extends BaseEventHandler { double geofenceSpeedLimit = 0; long overspeedGeofenceId = 0; - if (device.getGeofenceIds() != null) { - for (long geofenceId : device.getGeofenceIds()) { + if (position.getGeofenceIds() != null) { + for (long geofenceId : position.getGeofenceIds()) { Geofence geofence = cacheManager.getObject(Geofence.class, geofenceId); if (geofence != null) { double currentSpeedLimit = geofence.getDouble(Keys.EVENT_OVERSPEED_LIMIT.getKey()); @@ -107,7 +109,7 @@ public class OverspeedEventHandler extends BaseEventHandler { } OverspeedState state = OverspeedState.fromDevice(device); - OverspeedProcessor.updateState(state, position, speedLimit, minimalDuration, overspeedGeofenceId); + OverspeedProcessor.updateState(state, position, speedLimit, multiplier, minimalDuration, overspeedGeofenceId); if (state.isChanged()) { state.toDevice(device); try { |