aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/traccar')
-rw-r--r--src/main/java/org/traccar/BaseProtocolDecoder.java14
-rw-r--r--src/main/java/org/traccar/config/ConfigKey.java73
-rw-r--r--src/main/java/org/traccar/config/ConfigSuffix.java81
-rw-r--r--src/main/java/org/traccar/config/Keys.java779
-rw-r--r--src/main/java/org/traccar/database/DeviceManager.java57
-rw-r--r--src/main/java/org/traccar/database/IdentityManager.java11
-rw-r--r--src/main/java/org/traccar/handler/FilterHandler.java48
-rw-r--r--src/main/java/org/traccar/handler/HemisphereHandler.java2
-rw-r--r--src/main/java/org/traccar/handler/events/FuelDropEventHandler.java25
-rw-r--r--src/main/java/org/traccar/handler/events/OverspeedEventHandler.java13
-rw-r--r--src/main/java/org/traccar/helper/model/AttributeUtil.java72
-rw-r--r--src/main/java/org/traccar/model/CellTower.java2
-rw-r--r--src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java14
-rw-r--r--src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java25
-rw-r--r--src/main/java/org/traccar/session/ConnectionManager.java5
-rw-r--r--src/main/java/org/traccar/session/cache/CacheManager.java4
16 files changed, 728 insertions, 497 deletions
diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java
index cbcb429b3..076b52e96 100644
--- a/src/main/java/org/traccar/BaseProtocolDecoder.java
+++ b/src/main/java/org/traccar/BaseProtocolDecoder.java
@@ -23,11 +23,13 @@ import org.traccar.database.IdentityManager;
import org.traccar.database.MediaManager;
import org.traccar.database.StatisticsManager;
import org.traccar.helper.UnitsConverter;
+import org.traccar.helper.model.AttributeUtil;
import org.traccar.model.Command;
import org.traccar.model.Device;
import org.traccar.model.Position;
import org.traccar.session.ConnectionManager;
import org.traccar.session.DeviceSession;
+import org.traccar.session.cache.CacheManager;
import org.traccar.storage.StorageException;
import javax.inject.Inject;
@@ -46,6 +48,7 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
private final Protocol protocol;
private IdentityManager identityManager;
+ private CacheManager cacheManager;
private ConnectionManager connectionManager;
private StatisticsManager statisticsManager;
private MediaManager mediaManager;
@@ -64,6 +67,15 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
this.identityManager = identityManager;
}
+ public CacheManager getCacheManager() {
+ return cacheManager;
+ }
+
+ @Inject
+ public void setCacheManager(CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
+ }
+
@Inject
public void setConnectionManager(ConnectionManager connectionManager) {
this.connectionManager = connectionManager;
@@ -125,7 +137,7 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
protected TimeZone getTimeZone(long deviceId, String defaultTimeZone) {
TimeZone result = TimeZone.getTimeZone(defaultTimeZone);
- String timeZoneName = identityManager.lookupAttributeString(deviceId, "decoder.timezone", null, false, true);
+ String timeZoneName = AttributeUtil.lookup(cacheManager, Keys.DECODER_TIMEZONE, deviceId);
if (timeZoneName != null) {
result = TimeZone.getTimeZone(timeZoneName);
}
diff --git a/src/main/java/org/traccar/config/ConfigKey.java b/src/main/java/org/traccar/config/ConfigKey.java
index c046a46a5..b8151392c 100644
--- a/src/main/java/org/traccar/config/ConfigKey.java
+++ b/src/main/java/org/traccar/config/ConfigKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2019 - 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.
@@ -15,30 +15,34 @@
*/
package org.traccar.config;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
-public class ConfigKey<T> {
+public abstract class ConfigKey<T> {
private final String key;
- private final List<KeyType> types;
+ private final Set<KeyType> types = new HashSet<>();
+ private final Class<T> valueClass;
private final T defaultValue;
- ConfigKey(String key, List<KeyType> types) {
- this(key, types, null);
- }
-
- ConfigKey(String key, List<KeyType> types, T defaultValue) {
+ ConfigKey(String key, List<KeyType> types, Class<T> valueClass, T defaultValue) {
this.key = key;
- this.types = types;
+ this.types.addAll(types);
+ this.valueClass = valueClass;
this.defaultValue = defaultValue;
}
- String getKey() {
+ public String getKey() {
return key;
}
- public List<KeyType> getTypes() {
- return types;
+ public boolean hasType(KeyType type) {
+ return types.contains(type);
+ }
+
+ public Class<T> getValueClass() {
+ return valueClass;
}
public T getDefaultValue() {
@@ -46,3 +50,48 @@ public class ConfigKey<T> {
}
}
+
+class StringConfigKey extends ConfigKey<String> {
+ StringConfigKey(String key, List<KeyType> types) {
+ super(key, types, String.class, null);
+ }
+ StringConfigKey(String key, List<KeyType> types, String defaultValue) {
+ super(key, types, String.class, defaultValue);
+ }
+}
+
+class BooleanConfigKey extends ConfigKey<Boolean> {
+ BooleanConfigKey(String key, List<KeyType> types) {
+ super(key, types, Boolean.class, null);
+ }
+ BooleanConfigKey(String key, List<KeyType> types, Boolean defaultValue) {
+ super(key, types, Boolean.class, defaultValue);
+ }
+}
+
+class IntegerConfigKey extends ConfigKey<Integer> {
+ IntegerConfigKey(String key, List<KeyType> types) {
+ super(key, types, Integer.class, null);
+ }
+ IntegerConfigKey(String key, List<KeyType> types, Integer defaultValue) {
+ super(key, types, Integer.class, defaultValue);
+ }
+}
+
+class LongConfigKey extends ConfigKey<Long> {
+ LongConfigKey(String key, List<KeyType> types) {
+ super(key, types, Long.class, null);
+ }
+ LongConfigKey(String key, List<KeyType> types, Long defaultValue) {
+ super(key, types, Long.class, defaultValue);
+ }
+}
+
+class DoubleConfigKey extends ConfigKey<Double> {
+ DoubleConfigKey(String key, List<KeyType> types) {
+ super(key, types, Double.class, null);
+ }
+ DoubleConfigKey(String key, List<KeyType> types, Double defaultValue) {
+ super(key, types, Double.class, defaultValue);
+ }
+}
diff --git a/src/main/java/org/traccar/config/ConfigSuffix.java b/src/main/java/org/traccar/config/ConfigSuffix.java
index ede4c107d..aac3219c6 100644
--- a/src/main/java/org/traccar/config/ConfigSuffix.java
+++ b/src/main/java/org/traccar/config/ConfigSuffix.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2019 - 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.
@@ -17,15 +17,11 @@ package org.traccar.config;
import java.util.List;
-public class ConfigSuffix<T> {
+public abstract class ConfigSuffix<T> {
- private final String keySuffix;
- private final List<KeyType> types;
- private final T defaultValue;
-
- ConfigSuffix(String keySuffix, List<KeyType> types) {
- this(keySuffix, types, null);
- }
+ protected final String keySuffix;
+ protected final List<KeyType> types;
+ protected final T defaultValue;
ConfigSuffix(String keySuffix, List<KeyType> types, T defaultValue) {
this.keySuffix = keySuffix;
@@ -33,8 +29,71 @@ public class ConfigSuffix<T> {
this.defaultValue = defaultValue;
}
- public ConfigKey<T> withPrefix(String prefix) {
- return new ConfigKey<>(prefix + keySuffix, types, defaultValue);
+ public abstract ConfigKey<T> withPrefix(String prefix);
+
+}
+
+class StringConfigSuffix extends ConfigSuffix<String> {
+ StringConfigSuffix(String key, List<KeyType> types) {
+ super(key, types, null);
+ }
+ StringConfigSuffix(String key, List<KeyType> types, String defaultValue) {
+ super(key, types, defaultValue);
+ }
+ @Override
+ public ConfigKey<String> withPrefix(String prefix) {
+ return new StringConfigKey(prefix + keySuffix, types, defaultValue);
+ }
+}
+
+class BooleanConfigSuffix extends ConfigSuffix<Boolean> {
+ BooleanConfigSuffix(String key, List<KeyType> types) {
+ super(key, types, null);
+ }
+ BooleanConfigSuffix(String key, List<KeyType> types, Boolean defaultValue) {
+ super(key, types, defaultValue);
+ }
+ @Override
+ public ConfigKey<Boolean> withPrefix(String prefix) {
+ return new BooleanConfigKey(prefix + keySuffix, types, defaultValue);
+ }
+}
+
+class IntegerConfigSuffix extends ConfigSuffix<Integer> {
+ IntegerConfigSuffix(String key, List<KeyType> types) {
+ super(key, types, null);
+ }
+ IntegerConfigSuffix(String key, List<KeyType> types, Integer defaultValue) {
+ super(key, types, defaultValue);
+ }
+ @Override
+ public ConfigKey<Integer> withPrefix(String prefix) {
+ return new IntegerConfigKey(prefix + keySuffix, types, defaultValue);
}
+}
+class LongConfigSuffix extends ConfigSuffix<Long> {
+ LongConfigSuffix(String key, List<KeyType> types) {
+ super(key, types, null);
+ }
+ LongConfigSuffix(String key, List<KeyType> types, Long defaultValue) {
+ super(key, types, defaultValue);
+ }
+ @Override
+ public ConfigKey<Long> withPrefix(String prefix) {
+ return new LongConfigKey(prefix + keySuffix, types, defaultValue);
+ }
+}
+
+class DoubleConfigSuffix extends ConfigSuffix<Double> {
+ DoubleConfigSuffix(String key, List<KeyType> types) {
+ super(key, types, null);
+ }
+ DoubleConfigSuffix(String key, List<KeyType> types, Double defaultValue) {
+ super(key, types, defaultValue);
+ }
+ @Override
+ public ConfigKey<Double> withPrefix(String prefix) {
+ return new DoubleConfigKey(prefix + keySuffix, types, defaultValue);
+ }
}
diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java
index 292202de0..465751d38 100644
--- a/src/main/java/org/traccar/config/Keys.java
+++ b/src/main/java/org/traccar/config/Keys.java
@@ -15,7 +15,7 @@
*/
package org.traccar.config;
-import java.util.Collections;
+import java.util.List;
public final class Keys {
@@ -25,39 +25,39 @@ public final class Keys {
/**
* Network interface for a the protocol. If not specified, server will bind all interfaces.
*/
- public static final ConfigSuffix<String> PROTOCOL_ADDRESS = new ConfigSuffix<>(
+ public static final ConfigSuffix<String> PROTOCOL_ADDRESS = new StringConfigSuffix(
".address",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Port number for the protocol. Most protocols use TCP on the transport layer. Some protocols use UDP. Some
* support both TCP and UDP.
*/
- public static final ConfigSuffix<Integer> PROTOCOL_PORT = new ConfigSuffix<>(
+ public static final ConfigSuffix<Integer> PROTOCOL_PORT = new IntegerConfigSuffix(
".port",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* List of devices for polling protocols. List should contain unique ids separated by commas. Used only for polling
* protocols.
*/
- public static final ConfigSuffix<String> PROTOCOL_DEVICES = new ConfigSuffix<>(
+ public static final ConfigSuffix<String> PROTOCOL_DEVICES = new StringConfigSuffix(
".devices",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Polling interval in seconds. Used only for polling protocols.
*/
- public static final ConfigSuffix<Long> PROTOCOL_INTERVAL = new ConfigSuffix<>(
+ public static final ConfigSuffix<Long> PROTOCOL_INTERVAL = new LongConfigSuffix(
".interval",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Enable SSL support for the protocol. Not all protocols support this.
*/
- public static final ConfigSuffix<Boolean> PROTOCOL_SSL = new ConfigSuffix<>(
+ public static final ConfigSuffix<Boolean> PROTOCOL_SSL = new BooleanConfigSuffix(
".ssl",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Connection timeout value in seconds. Because sometimes there is no way to detect lost TCP connection old
@@ -65,568 +65,640 @@ public final class Keys {
* problems with establishing new connections when number of devices is high or devices data connections are
* unstable.
*/
- public static final ConfigSuffix<Integer> PROTOCOL_TIMEOUT = new ConfigSuffix<>(
+ public static final ConfigSuffix<Integer> PROTOCOL_TIMEOUT = new IntegerConfigSuffix(
".timeout",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Device password. Commonly used in some protocol for sending commands.
*/
- public static final ConfigSuffix<String> PROTOCOL_DEVICE_PASSWORD = new ConfigSuffix<>(
+ public static final ConfigSuffix<String> PROTOCOL_DEVICE_PASSWORD = new StringConfigSuffix(
".devicePassword",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Default protocol mask to use. Currently used only by Skypatrol protocol.
*/
- public static final ConfigSuffix<Integer> PROTOCOL_MASK = new ConfigSuffix<>(
+ public static final ConfigSuffix<Integer> PROTOCOL_MASK = new IntegerConfigSuffix(
".mask",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Custom message length. Currently used only by H2 protocol for specifying binary message length.
*/
- public static final ConfigSuffix<Integer> PROTOCOL_MESSAGE_LENGTH = new ConfigSuffix<>(
+ public static final ConfigSuffix<Integer> PROTOCOL_MESSAGE_LENGTH = new IntegerConfigSuffix(
".messageLength",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Enable extended functionality for the protocol. The reason it's disabled by default is that not all devices
* support it.
*/
- public static final ConfigSuffix<Boolean> PROTOCOL_EXTENDED = new ConfigSuffix<>(
+ public static final ConfigSuffix<Boolean> PROTOCOL_EXTENDED = new BooleanConfigSuffix(
".extended",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Decode string as UTF8 instead of ASCII. Only applicable for some protocols.
*/
- public static final ConfigSuffix<Boolean> PROTOCOL_UTF8 = new ConfigSuffix<>(
+ public static final ConfigSuffix<Boolean> PROTOCOL_UTF8 = new BooleanConfigSuffix(
".utf8",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Enable CAN decoding for the protocol. Similar to 'extended' configuration, it's not supported for some devices.
*/
- public static final ConfigSuffix<Boolean> PROTOCOL_CAN = new ConfigSuffix<>(
+ public static final ConfigSuffix<Boolean> PROTOCOL_CAN = new BooleanConfigSuffix(
".can",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Indicates whether server acknowledgement is required. Only applicable for some protocols.
*/
- public static final ConfigSuffix<Boolean> PROTOCOL_ACK = new ConfigSuffix<>(
+ public static final ConfigSuffix<Boolean> PROTOCOL_ACK = new BooleanConfigSuffix(
".ack",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Ignore device reported fix time. Useful in case some devices report invalid time. Currently only available for
* GL200 protocol.
*/
- public static final ConfigSuffix<Boolean> PROTOCOL_IGNORE_FIX_TIME = new ConfigSuffix<>(
+ public static final ConfigSuffix<Boolean> PROTOCOL_IGNORE_FIX_TIME = new BooleanConfigSuffix(
".ignoreFixTime",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Decode additional TK103 attributes. Not supported for some devices.
*/
- public static final ConfigSuffix<Boolean> PROTOCOL_DECODE_LOW = new ConfigSuffix<>(
+ public static final ConfigSuffix<Boolean> PROTOCOL_DECODE_LOW = new BooleanConfigSuffix(
".decodeLow",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Use long date format for Atrack protocol.
*/
- public static final ConfigSuffix<Boolean> PROTOCOL_LONG_DATE = new ConfigSuffix<>(
+ public static final ConfigSuffix<Boolean> PROTOCOL_LONG_DATE = new BooleanConfigSuffix(
".longDate",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Use decimal fuel value format for Atrack protocol.
*/
- public static final ConfigSuffix<Boolean> PROTOCOL_DECIMAL_FUEL = new ConfigSuffix<>(
+ public static final ConfigSuffix<Boolean> PROTOCOL_DECIMAL_FUEL = new BooleanConfigSuffix(
".decimalFuel",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Indicates additional custom attributes for Atrack protocol.
*/
- public static final ConfigSuffix<Boolean> PROTOCOL_CUSTOM = new ConfigSuffix<>(
+ public static final ConfigSuffix<Boolean> PROTOCOL_CUSTOM = new BooleanConfigSuffix(
".custom",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Custom format string for Atrack protocol.
*/
- public static final ConfigSuffix<String> PROTOCOL_FORM = new ConfigSuffix<>(
+ public static final ConfigSuffix<String> PROTOCOL_FORM = new StringConfigSuffix(
".form",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Protocol configuration. Required for some devices for decoding incoming data.
*/
- public static final ConfigSuffix<String> PROTOCOL_CONFIG = new ConfigSuffix<>(
+ public static final ConfigSuffix<String> PROTOCOL_CONFIG = new StringConfigSuffix(
".config",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Alarm mapping for Atrack protocol.
*/
- public static final ConfigSuffix<String> PROTOCOL_ALARM_MAP = new ConfigSuffix<>(
+ public static final ConfigSuffix<String> PROTOCOL_ALARM_MAP = new StringConfigSuffix(
".alarmMap",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Indicates whether TAIP protocol should have prefixes for messages.
*/
- public static final ConfigSuffix<Boolean> PROTOCOL_PREFIX = new ConfigSuffix<>(
+ public static final ConfigSuffix<Boolean> PROTOCOL_PREFIX = new BooleanConfigSuffix(
".prefix",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Some devices require server address confirmation. Use this parameter to configure correct public address.
*/
- public static final ConfigSuffix<String> PROTOCOL_SERVER = new ConfigSuffix<>(
+ public static final ConfigSuffix<String> PROTOCOL_SERVER = new StringConfigSuffix(
".server",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Protocol type for Suntech.
+ */
+ public static final ConfigKey<Integer> PROTOCOL_TYPE = new IntegerConfigKey(
+ "suntech.protocolType",
+ List.of(KeyType.CONFIG, KeyType.DEVICE));
+
+ /**
+ * Suntech HBM configuration value.
+ */
+ public static final ConfigKey<Boolean> PROTOCOL_HBM = new BooleanConfigKey(
+ "suntech.hbm",
+ List.of(KeyType.CONFIG, KeyType.DEVICE));
+
+ /**
+ * Format includes ADC value.
+ */
+ public static final ConfigSuffix<Boolean> PROTOCOL_INCLUDE_ADC = new BooleanConfigSuffix(
+ ".includeAdc",
+ List.of(KeyType.CONFIG, KeyType.DEVICE));
+
+ /**
+ * Format includes RPM value.
+ */
+ public static final ConfigSuffix<Boolean> PROTOCOL_INCLUDE_RPM = new BooleanConfigSuffix(
+ ".includeRpm",
+ List.of(KeyType.CONFIG, KeyType.DEVICE));
+
+ /**
+ * Format includes temperature values.
+ */
+ public static final ConfigSuffix<Boolean> PROTOCOL_INCLUDE_TEMPERATURE = new BooleanConfigSuffix(
+ ".includeTemp",
+ List.of(KeyType.CONFIG, KeyType.DEVICE));
+
+ /**
+ * Protocol format. Used by protocols that have configurable message format.
+ */
+ public static final ConfigSuffix<String> PROTOCOL_FORMAT = new StringConfigSuffix(
+ ".format",
+ List.of(KeyType.DEVICE));
+
+ /**
+ * Protocol date format. Used by protocols that have configurable date format.
+ */
+ public static final ConfigSuffix<String> PROTOCOL_DATE_FORMAT = new StringConfigSuffix(
+ ".dateFormat",
+ List.of(KeyType.DEVICE));
+
+ /**
+ * Device time zone. Most devices report UTC time, but in some cases devices report local time, so this parameter
+ * needs to be configured for the server to be able to decode the time correctly.
+ */
+ public static final ConfigKey<String> DECODER_TIMEZONE = new StringConfigKey(
+ "decoder.timezone",
+ List.of(KeyType.CONFIG, KeyType.DEVICE));
/**
* ORBCOMM API access id.
*/
- public static final ConfigKey<String> ORBCOMM_ACCESS_ID = new ConfigKey<>(
+ public static final ConfigKey<String> ORBCOMM_ACCESS_ID = new StringConfigKey(
"orbcomm.accessId",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* ORBCOMM API password.
*/
- public static final ConfigKey<String> ORBCOMM_PASSWORD = new ConfigKey<>(
+ public static final ConfigKey<String> ORBCOMM_PASSWORD = new StringConfigKey(
"orbcomm.password",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Server wide connection timeout value in seconds. See protocol timeout for more information.
*/
- public static final ConfigKey<Integer> SERVER_TIMEOUT = new ConfigKey<>(
+ public static final ConfigKey<Integer> SERVER_TIMEOUT = new IntegerConfigKey(
"server.timeout",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Address for uploading aggregated anonymous usage statistics. Uploaded information is the same you can see on the
* statistics screen in the web app. It does not include any sensitive (e.g. locations).
*/
- public static final ConfigKey<String> SERVER_STATISTICS = new ConfigKey<>(
+ public static final ConfigKey<String> SERVER_STATISTICS = new StringConfigKey(
"server.statistics",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Fuel drop threshold value. When fuel level drops from one position to another for more the value, an event is
+ * generated.
+ */
+ public static final ConfigKey<Double> EVENT_FUEL_DROP_THRESHOLD = new DoubleConfigKey(
+ "fuelDropThreshold",
+ List.of(KeyType.SERVER, KeyType.DEVICE));
+
+ /**
+ * Speed limit value in knots.
+ */
+ public static final ConfigKey<Double> EVENT_OVERSPEED_LIMIT = new DoubleConfigKey(
+ "speedLimit",
+ List.of(KeyType.SERVER, KeyType.DEVICE));
/**
* If true, the event is generated once at the beginning of overspeeding period.
*/
- public static final ConfigKey<Boolean> EVENT_OVERSPEED_NOT_REPEAT = new ConfigKey<>(
+ public static final ConfigKey<Boolean> EVENT_OVERSPEED_NOT_REPEAT = new BooleanConfigKey(
"event.overspeed.notRepeat",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Minimal over speed duration to trigger the event. Value in seconds.
*/
- public static final ConfigKey<Long> EVENT_OVERSPEED_MINIMAL_DURATION = new ConfigKey<>(
+ public static final ConfigKey<Long> EVENT_OVERSPEED_MINIMAL_DURATION = new LongConfigKey(
"event.overspeed.minimalDuration",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Relevant only for geofence speed limits. Use the lowest speed limit from all geofences.
*/
- public static final ConfigKey<Boolean> EVENT_OVERSPEED_PREFER_LOWEST = new ConfigKey<>(
+ public static final ConfigKey<Boolean> EVENT_OVERSPEED_PREFER_LOWEST = new BooleanConfigKey(
"event.overspeed.preferLowest",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Driver behavior acceleration threshold. Value is in meter per second squared.
*/
- public static final ConfigKey<Double> EVENT_BEHAVIOR_ACCELERATION_THRESHOLD = new ConfigKey<>(
+ public static final ConfigKey<Double> EVENT_BEHAVIOR_ACCELERATION_THRESHOLD = new DoubleConfigKey(
"event.behavior.accelerationThreshold",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Driver behavior braking threshold. Value is in meter per second squared.
*/
- public static final ConfigKey<Double> EVENT_BEHAVIOR_BRAKING_THRESHOLD = new ConfigKey<>(
+ public static final ConfigKey<Double> EVENT_BEHAVIOR_BRAKING_THRESHOLD = new DoubleConfigKey(
"event.behavior.brakingThreshold",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Do not generate alert event if same alert was present in last known location.
*/
- public static final ConfigKey<Boolean> EVENT_IGNORE_DUPLICATE_ALERTS = new ConfigKey<>(
+ public static final ConfigKey<Boolean> EVENT_IGNORE_DUPLICATE_ALERTS = new BooleanConfigKey(
"event.ignoreDuplicateAlerts",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* If set to true, invalid positions will be considered for motion logic.
*/
- public static final ConfigKey<Boolean> EVENT_MOTION_PROCESS_INVALID_POSITIONS = new ConfigKey<>(
+ public static final ConfigKey<Boolean> EVENT_MOTION_PROCESS_INVALID_POSITIONS = new BooleanConfigKey(
"event.motion.processInvalidPositions",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* If the speed is above specified value, the object is considered to be in motion. Default value is 0.01 knots.
*/
- public static final ConfigKey<Double> EVENT_MOTION_SPEED_THRESHOLD = new ConfigKey<>(
+ public static final ConfigKey<Double> EVENT_MOTION_SPEED_THRESHOLD = new DoubleConfigKey(
"event.motion.speedThreshold",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
0.01);
/**
* Global polyline geofence distance. Within that distance from the polyline, point is considered within the
* geofence. Each individual geofence can also has 'polylineDistance' attribute which will take precedence.
*/
- public static final ConfigKey<Double> GEOFENCE_POLYLINE_DISTANCE = new ConfigKey<>(
+ public static final ConfigKey<Double> GEOFENCE_POLYLINE_DISTANCE = new DoubleConfigKey(
"geofence.polylineDistance",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
25.0);
/**
* Path to the database driver JAR file. Traccar includes drivers for MySQL, PostgreSQL and H2 databases. If you use
* one of those, you don't need to specify this parameter.
*/
- public static final ConfigKey<String> DATABASE_DRIVER_FILE = new ConfigKey<>(
+ public static final ConfigKey<String> DATABASE_DRIVER_FILE = new StringConfigKey(
"database.driverFile",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Database driver Java class. For H2 use 'org.h2.Driver'. MySQL driver class name is 'com.mysql.jdbc.Driver'.
*/
- public static final ConfigKey<String> DATABASE_DRIVER = new ConfigKey<>(
+ public static final ConfigKey<String> DATABASE_DRIVER = new StringConfigKey(
"database.driver",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Database connection URL. By default Traccar uses H2 database.
*/
- public static final ConfigKey<String> DATABASE_URL = new ConfigKey<>(
+ public static final ConfigKey<String> DATABASE_URL = new StringConfigKey(
"database.url",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Database user name. Default administrator user for H2 database is 'sa'.
*/
- public static final ConfigKey<String> DATABASE_USER = new ConfigKey<>(
+ public static final ConfigKey<String> DATABASE_USER = new StringConfigKey(
"database.user",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Database user password. Default password for H2 admin (sa) user is empty.
*/
- public static final ConfigKey<String> DATABASE_PASSWORD = new ConfigKey<>(
+ public static final ConfigKey<String> DATABASE_PASSWORD = new StringConfigKey(
"database.password",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Path to Liquibase master changelog file.
*/
- public static final ConfigKey<String> DATABASE_CHANGELOG = new ConfigKey<>(
+ public static final ConfigKey<String> DATABASE_CHANGELOG = new StringConfigKey(
"database.changelog",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Database connection pool size. Default value is defined by the HikariCP library.
*/
- public static final ConfigKey<Integer> DATABASE_MAX_POOL_SIZE = new ConfigKey<>(
+ public static final ConfigKey<Integer> DATABASE_MAX_POOL_SIZE = new IntegerConfigKey(
"database.maxPoolSize",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* SQL query to check connection status. Default value is 'SELECT 1'. For Oracle database you can use
* 'SELECT 1 FROM DUAL'.
*/
- public static final ConfigKey<String> DATABASE_CHECK_CONNECTION = new ConfigKey<>(
+ public static final ConfigKey<String> DATABASE_CHECK_CONNECTION = new StringConfigKey(
"database.checkConnection",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
"SELECT 1");
/**
* Store original HEX or string data as "raw" attribute in the corresponding position.
*/
- public static final ConfigKey<Boolean> DATABASE_SAVE_ORIGINAL = new ConfigKey<>(
+ public static final ConfigKey<Boolean> DATABASE_SAVE_ORIGINAL = new BooleanConfigKey(
"database.saveOriginal",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* By default server syncs with the database if it encounters and unknown device. This flag allows to disable that
* behavior to improve performance in some cases.
*/
- public static final ConfigKey<Boolean> DATABASE_IGNORE_UNKNOWN = new ConfigKey<>(
+ public static final ConfigKey<Boolean> DATABASE_IGNORE_UNKNOWN = new BooleanConfigKey(
"database.ignoreUnknown",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Automatically register unknown devices in the database.
*/
- public static final ConfigKey<Boolean> DATABASE_REGISTER_UNKNOWN = new ConfigKey<>(
+ public static final ConfigKey<Boolean> DATABASE_REGISTER_UNKNOWN = new BooleanConfigKey(
"database.registerUnknown",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Default category for auto-registered devices.
*/
- public static final ConfigKey<String> DATABASE_REGISTER_UNKNOWN_DEFAULT_CATEGORY = new ConfigKey<>(
+ public static final ConfigKey<String> DATABASE_REGISTER_UNKNOWN_DEFAULT_CATEGORY = new StringConfigKey(
"database.registerUnknown.defaultCategory",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* The group id assigned to auto-registered devices.
*/
- public static final ConfigKey<Long> DATABASE_REGISTER_UNKNOWN_DEFAULT_GROUP_ID = new ConfigKey<>(
+ public static final ConfigKey<Long> DATABASE_REGISTER_UNKNOWN_DEFAULT_GROUP_ID = new LongConfigKey(
"database.registerUnknown.defaultGroupId",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Minimum device refresh timeout in seconds. Default timeout is 5 minutes.
*/
- public static final ConfigKey<Long> DATABASE_REFRESH_DELAY = new ConfigKey<>(
+ public static final ConfigKey<Long> DATABASE_REFRESH_DELAY = new LongConfigKey(
"database.refreshDelay",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
300L);
/**
* Store empty messages as positions. For example, heartbeats.
*/
- public static final ConfigKey<Boolean> DATABASE_SAVE_EMPTY = new ConfigKey<>(
+ public static final ConfigKey<Boolean> DATABASE_SAVE_EMPTY = new BooleanConfigKey(
"database.saveEmpty",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Device limit for self registered users. Default value is -1, which indicates no limit.
*/
- public static final ConfigKey<Integer> USERS_DEFAULT_DEVICE_LIMIT = new ConfigKey<>(
+ public static final ConfigKey<Integer> USERS_DEFAULT_DEVICE_LIMIT = new IntegerConfigKey(
"users.defaultDeviceLimit",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
-1);
/**
* Default user expiration for self registered users. Value is in days. By default no expiration is set.
*/
- public static final ConfigKey<Integer> USERS_DEFAULT_EXPIRATION_DAYS = new ConfigKey<>(
+ public static final ConfigKey<Integer> USERS_DEFAULT_EXPIRATION_DAYS = new IntegerConfigKey(
"users.defaultExpirationDays",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* LDAP server URL.
*/
- public static final ConfigKey<String> LDAP_URL = new ConfigKey<>(
+ public static final ConfigKey<String> LDAP_URL = new StringConfigKey(
"ldap.url",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* LDAP server login.
*/
- public static final ConfigKey<String> LDAP_USER = new ConfigKey<>(
+ public static final ConfigKey<String> LDAP_USER = new StringConfigKey(
"ldap.user",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* LDAP server password.
*/
- public static final ConfigKey<String> LDAP_PASSWORD = new ConfigKey<>(
+ public static final ConfigKey<String> LDAP_PASSWORD = new StringConfigKey(
"ldap.password",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Force LDAP authentication.
*/
- public static final ConfigKey<Boolean> LDAP_FORCE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> LDAP_FORCE = new BooleanConfigKey(
"ldap.force",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* LDAP user search base.
*/
- public static final ConfigKey<String> LDAP_BASE = new ConfigKey<>(
+ public static final ConfigKey<String> LDAP_BASE = new StringConfigKey(
"ldap.base",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* LDAP attribute used as user id. Default value is 'uid'.
*/
- public static final ConfigKey<String> LDAP_ID_ATTRIBUTE = new ConfigKey<>(
+ public static final ConfigKey<String> LDAP_ID_ATTRIBUTE = new StringConfigKey(
"ldap.idAttribute",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
"uid");
/**
* LDAP attribute used as user name. Default value is 'cn'.
*/
- public static final ConfigKey<String> LDAP_NAME_ATTRIBUTE = new ConfigKey<>(
+ public static final ConfigKey<String> LDAP_NAME_ATTRIBUTE = new StringConfigKey(
"ldap.nameAttribute",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
"cn");
/**
* LDAP attribute used as user email. Default value is 'mail'.
*/
- public static final ConfigKey<String> LDAP_MAIN_ATTRIBUTE = new ConfigKey<>(
+ public static final ConfigKey<String> LDAP_MAIN_ATTRIBUTE = new StringConfigKey(
"ldap.mailAttribute",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
"mail");
/**
* LDAP custom search filter. If not specified, '({idAttribute}=:login)' will be used as a filter.
*/
- public static final ConfigKey<String> LDAP_SEARCH_FILTER = new ConfigKey<>(
+ public static final ConfigKey<String> LDAP_SEARCH_FILTER = new StringConfigKey(
"ldap.searchFilter",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* LDAP custom admin search filter.
*/
- public static final ConfigKey<String> LDAP_ADMIN_FILTER = new ConfigKey<>(
+ public static final ConfigKey<String> LDAP_ADMIN_FILTER = new StringConfigKey(
"ldap.adminFilter",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* LDAP admin user group. Used if custom admin filter is not specified.
*/
- public static final ConfigKey<String> LDAP_ADMIN_GROUP = new ConfigKey<>(
+ public static final ConfigKey<String> LDAP_ADMIN_GROUP = new StringConfigKey(
"ldap.adminGroup",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* If no data is reported by a device for the given amount of time, status changes from online to unknown. Value is
* in seconds. Default timeout is 10 minutes.
*/
- public static final ConfigKey<Long> STATUS_TIMEOUT = new ConfigKey<>(
+ public static final ConfigKey<Long> STATUS_TIMEOUT = new LongConfigKey(
"status.timeout",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
600L);
/**
* Force additional state check when device status changes to 'offline' or 'unknown'. Default false.
*/
- public static final ConfigKey<Boolean> STATUS_UPDATE_DEVICE_STATE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> STATUS_UPDATE_DEVICE_STATE = new BooleanConfigKey(
"status.updateDeviceState",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* List of protocol names to ignore offline status. Can be useful to not trigger status change when devices are
* configured to disconnect after reporting a batch of data.
*/
- public static final ConfigKey<String> STATUS_IGNORE_OFFLINE = new ConfigKey<>(
+ public static final ConfigKey<String> STATUS_IGNORE_OFFLINE = new StringConfigKey(
"status.ignoreOffline",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Path to the media folder. Server stores audio, video and photo files in that folder. Sub-folders will be
* automatically created for each device by unique id.
*/
- public static final ConfigKey<String> MEDIA_PATH = new ConfigKey<>(
+ public static final ConfigKey<String> MEDIA_PATH = new StringConfigKey(
"media.path",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Optional parameter to specify network interface for web interface to bind to. By default server will bind to all
* available interfaces.
*/
- public static final ConfigKey<String> WEB_ADDRESS = new ConfigKey<>(
+ public static final ConfigKey<String> WEB_ADDRESS = new StringConfigKey(
"web.address",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Web interface TCP port number. By default Traccar uses port 8082. To avoid specifying port in the browser you
* can set it to 80 (default HTTP port).
*/
- public static final ConfigKey<Integer> WEB_PORT = new ConfigKey<>(
+ public static final ConfigKey<Integer> WEB_PORT = new IntegerConfigKey(
"web.port",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Sanitize all strings returned via API. This is needed to fix XSS issues in the old web interface. New React-based
* interface doesn't require this.
*/
- public static final ConfigKey<Boolean> WEB_SANITIZE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> WEB_SANITIZE = new BooleanConfigKey(
"web.sanitize",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Path to the web app folder.
*/
- public static final ConfigKey<String> WEB_PATH = new ConfigKey<>(
+ public static final ConfigKey<String> WEB_PATH = new StringConfigKey(
"web.path",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* WebSocket connection timeout in milliseconds. Default timeout is 10 minutes.
*/
- public static final ConfigKey<Long> WEB_TIMEOUT = new ConfigKey<>(
+ public static final ConfigKey<Long> WEB_TIMEOUT = new LongConfigKey(
"web.timeout",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
60000L);
/**
* Authentication sessions timeout in seconds. By default no timeout.
*/
- public static final ConfigKey<Integer> WEB_SESSION_TIMEOUT = new ConfigKey<>(
+ public static final ConfigKey<Integer> WEB_SESSION_TIMEOUT = new IntegerConfigKey(
"web.sessionTimeout",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Enable database access console via '/console' URL. Use only for debugging. Never use in production.
*/
- public static final ConfigKey<Boolean> WEB_CONSOLE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> WEB_CONSOLE = new BooleanConfigKey(
"web.console",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Server debug version of the web app. Not recommended to use for performance reasons. It is intended to be used
* for development and debugging purposes.
*/
- public static final ConfigKey<Boolean> WEB_DEBUG = new ConfigKey<>(
+ public static final ConfigKey<Boolean> WEB_DEBUG = new BooleanConfigKey(
"web.debug",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Cross-origin resource sharing origin header value.
*/
- public static final ConfigKey<String> WEB_ORIGIN = new ConfigKey<>(
+ public static final ConfigKey<String> WEB_ORIGIN = new StringConfigKey(
"web.origin",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Cache control header value. By default resources are cached for one hour.
*/
- public static final ConfigKey<String> WEB_CACHE_CONTROL = new ConfigKey<>(
+ public static final ConfigKey<String> WEB_CACHE_CONTROL = new StringConfigKey(
"web.cacheControl",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
"max-age=3600,public");
/**
* URL to forward positions. Data is passed through URL parameters. For example, {uniqueId} for device identifier,
* {latitude} and {longitude} for coordinates.
*/
- public static final ConfigKey<String> FORWARD_URL = new ConfigKey<>(
+ public static final ConfigKey<String> FORWARD_URL = new StringConfigKey(
"forward.url",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Additional HTTP header, can be used for authorization.
*/
- public static final ConfigKey<String> FORWARD_HEADER = new ConfigKey<>(
+ public static final ConfigKey<String> FORWARD_HEADER = new StringConfigKey(
"forward.header",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Boolean value to enable forwarding in JSON format.
*/
- public static final ConfigKey<Boolean> FORWARD_JSON = new ConfigKey<>(
+ public static final ConfigKey<Boolean> FORWARD_JSON = new BooleanConfigKey(
"forward.json",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Boolean value to enable URL parameters in json mode. For example, {uniqueId} for device identifier,
* {latitude} and {longitude} for coordinates.
*/
- public static final ConfigKey<Boolean> FORWARD_URL_VARIABLES = new ConfigKey<>(
+ public static final ConfigKey<Boolean> FORWARD_URL_VARIABLES = new BooleanConfigKey(
"forward.urlVariables",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Position forwarding retrying enable. When enabled, additional attempts are made to deliver positions. If initial
@@ -635,301 +707,301 @@ public final class Keys {
* If forwarding is retried for 'forward.retry.count', retrying is canceled and the position is dropped. Positions
* pending to be delivered are limited to 'forward.retry.limit'. If this limit is reached, positions get discarded.
*/
- public static final ConfigKey<Boolean> FORWARD_RETRY_ENABLE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> FORWARD_RETRY_ENABLE = new BooleanConfigKey(
"forward.retry.enable",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Position forwarding retry first delay in milliseconds.
* Can be set to anything greater than 0. Defaults to 100 milliseconds.
*/
- public static final ConfigKey<Integer> FORWARD_RETRY_DELAY = new ConfigKey<>(
+ public static final ConfigKey<Integer> FORWARD_RETRY_DELAY = new IntegerConfigKey(
"forward.retry.delay",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Position forwarding retry maximum retries.
* Can be set to anything greater than 0. Defaults to 10 retries.
*/
- public static final ConfigKey<Integer> FORWARD_RETRY_COUNT = new ConfigKey<>(
+ public static final ConfigKey<Integer> FORWARD_RETRY_COUNT = new IntegerConfigKey(
"forward.retry.count",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Position forwarding retry pending positions limit.
* Can be set to anything greater than 0. Defaults to 100 positions.
*/
- public static final ConfigKey<Integer> FORWARD_RETRY_LIMIT = new ConfigKey<>(
+ public static final ConfigKey<Integer> FORWARD_RETRY_LIMIT = new IntegerConfigKey(
"forward.retry.limit",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Events forwarding URL.
*/
- public static final ConfigKey<String> EVENT_FORWARD_URL = new ConfigKey<>(
+ public static final ConfigKey<String> EVENT_FORWARD_URL = new StringConfigKey(
"event.forward.url",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Events forwarding headers. Example value:
* FirstHeader: hello
* SecondHeader: world
*/
- public static final ConfigKey<String> EVENT_FORWARD_HEADERS = new ConfigKey<>(
+ public static final ConfigKey<String> EVENT_FORWARD_HEADERS = new StringConfigKey(
"event.forward.header",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Enable commands queuing when devices are offline. Commands are buffered in memory only, so restarting service
* will clear the buffer.
*/
- public static final ConfigKey<Boolean> COMMANDS_QUEUEING = new ConfigKey<>(
+ public static final ConfigKey<Boolean> COMMANDS_QUEUEING = new BooleanConfigKey(
"commands.queueing",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Root folder for all template files.
*/
- public static final ConfigKey<String> TEMPLATES_ROOT = new ConfigKey<>(
+ public static final ConfigKey<String> TEMPLATES_ROOT = new StringConfigKey(
"templates.root",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
"templates");
/**
* SMS API service full URL. Enables SMS commands and notifications.
*/
- public static final ConfigKey<String> SMS_HTTP_URL = new ConfigKey<>(
+ public static final ConfigKey<String> SMS_HTTP_URL = new StringConfigKey(
"sms.http.url",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* SMS API authorization header name. Default value is 'Authorization'.
*/
- public static final ConfigKey<String> SMS_HTTP_AUTHORIZATION_HEADER = new ConfigKey<>(
+ public static final ConfigKey<String> SMS_HTTP_AUTHORIZATION_HEADER = new StringConfigKey(
"sms.http.authorizationHeader",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
"Authorization");
/**
* SMS API authorization header value. This value takes precedence over user and password.
*/
- public static final ConfigKey<String> SMS_HTTP_AUTHORIZATION = new ConfigKey<>(
+ public static final ConfigKey<String> SMS_HTTP_AUTHORIZATION = new StringConfigKey(
"sms.http.authorization",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* SMS API basic authentication user.
*/
- public static final ConfigKey<String> SMS_HTTP_USER = new ConfigKey<>(
+ public static final ConfigKey<String> SMS_HTTP_USER = new StringConfigKey(
"sms.http.user",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* SMS API basic authentication password.
*/
- public static final ConfigKey<String> SMS_HTTP_PASSWORD = new ConfigKey<>(
+ public static final ConfigKey<String> SMS_HTTP_PASSWORD = new StringConfigKey(
"sms.http.password",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* SMS API body template. Placeholders {phone} and {message} can be used in the template.
* If value starts with '{' or '[', server automatically assumes JSON format.
*/
- public static final ConfigKey<String> SMS_HTTP_TEMPLATE = new ConfigKey<>(
+ public static final ConfigKey<String> SMS_HTTP_TEMPLATE = new StringConfigKey(
"sms.http.template",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* AWS Access Key with SNS permission.
*/
- public static final ConfigKey<String> SMS_AWS_ACCESS = new ConfigKey<>(
+ public static final ConfigKey<String> SMS_AWS_ACCESS = new StringConfigKey(
"sms.aws.access",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* AWS Secret Access Key with SNS permission.
*/
- public static final ConfigKey<String> SMS_AWS_SECRET = new ConfigKey<>(
+ public static final ConfigKey<String> SMS_AWS_SECRET = new StringConfigKey(
"sms.aws.secret",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* AWS Region for SNS service.
* Make sure to use regions that are supported for messaging.
*/
- public static final ConfigKey<String> SMS_AWS_REGION = new ConfigKey<>(
+ public static final ConfigKey<String> SMS_AWS_REGION = new StringConfigKey(
"sms.aws.region",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Enabled notification options. Comma-separated string is expected.
* Example: web,mail,sms
*/
- public static final ConfigKey<String> NOTIFICATOR_TYPES = new ConfigKey<>(
+ public static final ConfigKey<String> NOTIFICATOR_TYPES = new StringConfigKey(
"notificator.types",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Traccar notification API key.
*/
- public static final ConfigKey<String> NOTIFICATOR_TRACCAR_KEY = new ConfigKey<>(
+ public static final ConfigKey<String> NOTIFICATOR_TRACCAR_KEY = new StringConfigKey(
"notificator.traccar.key",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Firebase server API key for push notifications.
*/
- public static final ConfigKey<String> NOTIFICATOR_FIREBASE_KEY = new ConfigKey<>(
+ public static final ConfigKey<String> NOTIFICATOR_FIREBASE_KEY = new StringConfigKey(
"notificator.firebase.key",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Pushover notification user name.
*/
- public static final ConfigKey<String> NOTIFICATOR_PUSHOVER_USER = new ConfigKey<>(
+ public static final ConfigKey<String> NOTIFICATOR_PUSHOVER_USER = new StringConfigKey(
"notificator.pushover.user",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Pushover notification user token.
*/
- public static final ConfigKey<String> NOTIFICATOR_PUSHOVER_TOKEN = new ConfigKey<>(
+ public static final ConfigKey<String> NOTIFICATOR_PUSHOVER_TOKEN = new StringConfigKey(
"notificator.pushover.token",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Telegram notification API key.
*/
- public static final ConfigKey<String> NOTIFICATOR_TELEGRAM_KEY = new ConfigKey<>(
+ public static final ConfigKey<String> NOTIFICATOR_TELEGRAM_KEY = new StringConfigKey(
"notificator.telegram.key",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Telegram notification chat id to post messages to.
*/
- public static final ConfigKey<String> NOTIFICATOR_TELEGRAM_CHAT_ID = new ConfigKey<>(
+ public static final ConfigKey<String> NOTIFICATOR_TELEGRAM_CHAT_ID = new StringConfigKey(
"notificator.telegram.chatId",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Telegram notification send location message.
*/
- public static final ConfigKey<Boolean> NOTIFICATOR_TELEGRAM_SEND_LOCATION = new ConfigKey<>(
+ public static final ConfigKey<Boolean> NOTIFICATOR_TELEGRAM_SEND_LOCATION = new BooleanConfigKey(
"notificator.telegram.sendLocation",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Maximum time period for reports in seconds. Can be useful to prevent users to request unreasonably long reports.
* By default there is no limit.
*/
- public static final ConfigKey<Long> REPORT_PERIOD_LIMIT = new ConfigKey<>(
+ public static final ConfigKey<Long> REPORT_PERIOD_LIMIT = new LongConfigKey(
"report.periodLimit",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Trips less than minimal duration and minimal distance are ignored. 300 seconds and 500 meters are default.
*/
- public static final ConfigKey<Long> REPORT_TRIP_MINIMAL_TRIP_DISTANCE = new ConfigKey<>(
+ public static final ConfigKey<Long> REPORT_TRIP_MINIMAL_TRIP_DISTANCE = new LongConfigKey(
"report.trip.minimalTripDistance",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
500L);
/**
* Trips less than minimal duration and minimal distance are ignored. 300 seconds and 500 meters are default.
*/
- public static final ConfigKey<Long> REPORT_TRIP_MINIMAL_TRIP_DURATION = new ConfigKey<>(
+ public static final ConfigKey<Long> REPORT_TRIP_MINIMAL_TRIP_DURATION = new LongConfigKey(
"report.trip.minimalTripDuration",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
300L);
/**
* Parking less than minimal duration does not cut trip. Default 300 seconds.
*/
- public static final ConfigKey<Long> REPORT_TRIP_MINIMAL_PARKING_DURATION = new ConfigKey<>(
+ public static final ConfigKey<Long> REPORT_TRIP_MINIMAL_PARKING_DURATION = new LongConfigKey(
"report.trip.minimalParkingDuration",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
300L);
/**
* Gaps of more than specified time are counted as stops. Default value is one hour.
*/
- public static final ConfigKey<Long> REPORT_TRIP_MINIMAL_NO_DATA_DURATION = new ConfigKey<>(
+ public static final ConfigKey<Long> REPORT_TRIP_MINIMAL_NO_DATA_DURATION = new LongConfigKey(
"report.trip.minimalNoDataDuration",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
3600L);
/**
* Flag to enable ignition use for trips calculation.
*/
- public static final ConfigKey<Boolean> REPORT_TRIP_USE_IGNITION = new ConfigKey<>(
+ public static final ConfigKey<Boolean> REPORT_TRIP_USE_IGNITION = new BooleanConfigKey(
"report.trip.useIgnition",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Boolean flag to enable or disable position filtering.
*/
- public static final ConfigKey<Boolean> FILTER_ENABLE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> FILTER_ENABLE = new BooleanConfigKey(
"filter.enable",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Filter invalid (valid field is set to false) positions.
*/
- public static final ConfigKey<Boolean> FILTER_INVALID = new ConfigKey<>(
+ public static final ConfigKey<Boolean> FILTER_INVALID = new BooleanConfigKey(
"filter.invalid",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Filter zero coordinates. Zero latitude and longitude are theoretically valid values, but it practice it usually
* indicates invalid GPS data.
*/
- public static final ConfigKey<Boolean> FILTER_ZERO = new ConfigKey<>(
+ public static final ConfigKey<Boolean> FILTER_ZERO = new BooleanConfigKey(
"filter.zero",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Filter duplicate records (duplicates are detected by time value).
*/
- public static final ConfigKey<Boolean> FILTER_DUPLICATE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> FILTER_DUPLICATE = new BooleanConfigKey(
"filter.duplicate",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Filter records with fix time in future. The values is specified in seconds. Records that have fix time more than
* specified number of seconds later than current server time would be filtered out.
*/
- public static final ConfigKey<Long> FILTER_FUTURE = new ConfigKey<>(
+ public static final ConfigKey<Long> FILTER_FUTURE = new LongConfigKey(
"filter.future",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Filter positions with accuracy less than specified value in meters.
*/
- public static final ConfigKey<Integer> FILTER_ACCURACY = new ConfigKey<>(
+ public static final ConfigKey<Integer> FILTER_ACCURACY = new IntegerConfigKey(
"filter.accuracy",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Filter cell and wifi locations that are coming from geolocation provider.
*/
- public static final ConfigKey<Boolean> FILTER_APPROXIMATE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> FILTER_APPROXIMATE = new BooleanConfigKey(
"filter.approximate",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Filter positions with exactly zero speed values.
*/
- public static final ConfigKey<Boolean> FILTER_STATIC = new ConfigKey<>(
+ public static final ConfigKey<Boolean> FILTER_STATIC = new BooleanConfigKey(
"filter.static",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Filter records by distance. The values is specified in meters. If the new position is less far than this value
* from the last one it gets filtered out.
*/
- public static final ConfigKey<Integer> FILTER_DISTANCE = new ConfigKey<>(
+ public static final ConfigKey<Integer> FILTER_DISTANCE = new IntegerConfigKey(
"filter.distance",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Filter records by Maximum Speed value in knots. Can be used to filter jumps to far locations even if Position
@@ -938,16 +1010,16 @@ public final class Keys {
*
* Tip: Shouldn't be too low. Start testing with values at about 25000.
*/
- public static final ConfigKey<Integer> FILTER_MAX_SPEED = new ConfigKey<>(
+ public static final ConfigKey<Integer> FILTER_MAX_SPEED = new IntegerConfigKey(
"filter.maxSpeed",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Filter position if time from previous position is less than specified value in seconds.
*/
- public static final ConfigKey<Integer> FILTER_MIN_PERIOD = new ConfigKey<>(
+ public static final ConfigKey<Integer> FILTER_MIN_PERIOD = new IntegerConfigKey(
"filter.minPeriod",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* If false, the server expects all locations to come sequentially (for each device). Filter checks for duplicates,
@@ -957,262 +1029,271 @@ public final class Keys {
* Filter checks for duplicates, distance, speed, or time period against the preceding Position's.
* Important: setting to true can cause potential performance issues.
*/
- public static final ConfigKey<Boolean> FILTER_RELATIVE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> FILTER_RELATIVE = new BooleanConfigKey(
"filter.relative",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Time limit for the filtering in seconds. If the time difference between the last position was received by server
* and a new position is received by server is more than this limit, the new position will not be filtered out.
*/
- public static final ConfigKey<Long> FILTER_SKIP_LIMIT = new ConfigKey<>(
+ public static final ConfigKey<Long> FILTER_SKIP_LIMIT = new LongConfigKey(
"filter.skipLimit",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Enable attributes skipping. Attribute skipping can be enabled in the config or device attributes.
* If position contains any attribute mentioned in "filter.skipAttributes" config key, position is not filtered out.
*/
- public static final ConfigKey<Boolean> FILTER_SKIP_ATTRIBUTES_ENABLE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> FILTER_SKIP_ATTRIBUTES_ENABLE = new BooleanConfigKey(
"filter.skipAttributes.enable",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Attribute skipping can be enabled in the config or device attributes.
+ * If position contains any attribute mentioned in "filter.skipAttributes" config key, position is not filtered out.
+ */
+ public static final ConfigKey<String> FILTER_SKIP_ATTRIBUTES = new StringConfigKey(
+ "filter.skipAttributes",
+ List.of(KeyType.CONFIG, KeyType.DEVICE),
+ "");
/**
* Override device time. Possible values are 'deviceTime' and 'serverTime'
*/
- public static final ConfigKey<String> TIME_OVERRIDE = new ConfigKey<>(
+ public static final ConfigKey<String> TIME_OVERRIDE = new StringConfigKey(
"time.override",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* List of protocols for overriding time. If not specified override is applied globally. List consist of protocol
* names that can be separated by comma or single space character.
*/
- public static final ConfigKey<String> TIME_PROTOCOLS = new ConfigKey<>(
+ public static final ConfigKey<String> TIME_PROTOCOLS = new StringConfigKey(
"time.protocols",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Replaces coordinates with last known if change is less than a 'coordinates.minError' meters
* or more than a 'coordinates.maxError' meters. Helps to avoid coordinates jumps during parking period
* or jumps to zero coordinates.
*/
- public static final ConfigKey<Boolean> COORDINATES_FILTER = new ConfigKey<>(
+ public static final ConfigKey<Boolean> COORDINATES_FILTER = new BooleanConfigKey(
"coordinates.filter",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Distance in meters. Distances below this value gets handled like explained in 'coordinates.filter'.
*/
- public static final ConfigKey<Integer> COORDINATES_MIN_ERROR = new ConfigKey<>(
+ public static final ConfigKey<Integer> COORDINATES_MIN_ERROR = new IntegerConfigKey(
"coordinates.minError",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Distance in meters. Distances above this value gets handled like explained in 'coordinates.filter', but only if
* Position is also marked as 'invalid'.
*/
- public static final ConfigKey<Integer> COORDINATES_MAX_ERROR = new ConfigKey<>(
+ public static final ConfigKey<Integer> COORDINATES_MAX_ERROR = new IntegerConfigKey(
"coordinates.maxError",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Enable to save device IP addresses information. Disabled by default.
*/
- public static final ConfigKey<Boolean> PROCESSING_REMOTE_ADDRESS_ENABLE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> PROCESSING_REMOTE_ADDRESS_ENABLE = new BooleanConfigKey(
"processing.remoteAddress.enable",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Enable copying of missing attributes from last position to the current one. Might be useful if device doesn't
* send some values in every message.
*/
- public static final ConfigKey<Boolean> PROCESSING_COPY_ATTRIBUTES_ENABLE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> PROCESSING_COPY_ATTRIBUTES_ENABLE = new BooleanConfigKey(
"processing.copyAttributes.enable",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Enable computed attributes processing.
*/
- public static final ConfigKey<Boolean> PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES = new ConfigKey<>(
+ public static final ConfigKey<Boolean> PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES = new BooleanConfigKey(
"processing.computedAttributes.deviceAttributes",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Boolean flag to enable or disable reverse geocoder.
*/
- public static final ConfigKey<Boolean> GEOCODER_ENABLE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> GEOCODER_ENABLE = new BooleanConfigKey(
"geocoder.enable",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Reverse geocoder type. Check reverse geocoding documentation for more info. By default (if the value is not
* specified) server uses Google API.
*/
- public static final ConfigKey<String> GEOCODER_TYPE = new ConfigKey<>(
+ public static final ConfigKey<String> GEOCODER_TYPE = new StringConfigKey(
"geocoder.type",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Geocoder server URL. Applicable only to Nominatim and Gisgraphy providers.
*/
- public static final ConfigKey<String> GEOCODER_URL = new ConfigKey<>(
+ public static final ConfigKey<String> GEOCODER_URL = new StringConfigKey(
"geocoder.url",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* App id for use with Here provider.
*/
- public static final ConfigKey<String> GEOCODER_ID = new ConfigKey<>(
+ public static final ConfigKey<String> GEOCODER_ID = new StringConfigKey(
"geocoder.id",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Provider API key. Most providers require API keys.
*/
- public static final ConfigKey<String> GEOCODER_KEY = new ConfigKey<>(
+ public static final ConfigKey<String> GEOCODER_KEY = new StringConfigKey(
"geocoder.key",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Language parameter for providers that support localization (e.g. Google and Nominatim).
*/
- public static final ConfigKey<String> GEOCODER_LANGUAGE = new ConfigKey<>(
+ public static final ConfigKey<String> GEOCODER_LANGUAGE = new StringConfigKey(
"geocoder.language",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Address format string. Default value is %h %r, %t, %s, %c. See AddressFormat for more info.
*/
- public static final ConfigKey<String> GEOCODER_FORMAT = new ConfigKey<>(
+ public static final ConfigKey<String> GEOCODER_FORMAT = new StringConfigKey(
"geocoder.format",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Cache size for geocoding results.
*/
- public static final ConfigKey<Integer> GEOCODER_CACHE_SIZE = new ConfigKey<>(
+ public static final ConfigKey<Integer> GEOCODER_CACHE_SIZE = new IntegerConfigKey(
"geocoder.cacheSize",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Disable automatic reverse geocoding requests for all positions.
*/
- public static final ConfigKey<Boolean> GEOCODER_IGNORE_POSITIONS = new ConfigKey<>(
+ public static final ConfigKey<Boolean> GEOCODER_IGNORE_POSITIONS = new BooleanConfigKey(
"geocoder.ignorePositions",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Boolean flag to apply reverse geocoding to invalid positions.
*/
- public static final ConfigKey<Boolean> GEOCODER_PROCESS_INVALID_POSITIONS = new ConfigKey<>(
+ public static final ConfigKey<Boolean> GEOCODER_PROCESS_INVALID_POSITIONS = new BooleanConfigKey(
"geocoder.processInvalidPositions",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Optional parameter to specify minimum distance for new reverse geocoding request. If distance is less than
* specified value (in meters), then Traccar will reuse last known address.
*/
- public static final ConfigKey<Integer> GEOCODER_REUSE_DISTANCE = new ConfigKey<>(
+ public static final ConfigKey<Integer> GEOCODER_REUSE_DISTANCE = new IntegerConfigKey(
"geocoder.reuseDistance",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Perform geocoding when preparing reports and sending notifications.
*/
- public static final ConfigKey<Boolean> GEOCODER_ON_REQUEST = new ConfigKey<>(
+ public static final ConfigKey<Boolean> GEOCODER_ON_REQUEST = new BooleanConfigKey(
"geocoder.onRequest",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Boolean flag to enable LBS location resolution. Some devices send cell towers information and WiFi point when GPS
* location is not available. Traccar can determine coordinates based on that information using third party
* services. Default value is false.
*/
- public static final ConfigKey<Boolean> GEOLOCATION_ENABLE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> GEOLOCATION_ENABLE = new BooleanConfigKey(
"geolocation.enable",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Provider to use for LBS location. Available options: google, mozilla and opencellid. By default opencellid is
* used. You have to supply a key that you get from corresponding provider. For more information see LBS geolocation
* documentation.
*/
- public static final ConfigKey<String> GEOLOCATION_TYPE = new ConfigKey<>(
+ public static final ConfigKey<String> GEOLOCATION_TYPE = new StringConfigKey(
"geolocation.type",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Geolocation provider API URL address. Not required for most providers.
*/
- public static final ConfigKey<String> GEOLOCATION_URL = new ConfigKey<>(
+ public static final ConfigKey<String> GEOLOCATION_URL = new StringConfigKey(
"geolocation.url",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Provider API key. OpenCellID service requires API key.
*/
- public static final ConfigKey<String> GEOLOCATION_KEY = new ConfigKey<>(
+ public static final ConfigKey<String> GEOLOCATION_KEY = new StringConfigKey(
"geolocation.key",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Boolean flag to apply geolocation to invalid positions.
*/
- public static final ConfigKey<Boolean> GEOLOCATION_PROCESS_INVALID_POSITIONS = new ConfigKey<>(
+ public static final ConfigKey<Boolean> GEOLOCATION_PROCESS_INVALID_POSITIONS = new BooleanConfigKey(
"geolocation.processInvalidPositions",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Default MCC value to use if device doesn't report MCC.
*/
- public static final ConfigKey<Integer> GEOLOCATION_MCC = new ConfigKey<>(
+ public static final ConfigKey<Integer> GEOLOCATION_MCC = new IntegerConfigKey(
"geolocation.mcc",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Default MNC value to use if device doesn't report MNC.
*/
- public static final ConfigKey<Integer> GEOLOCATION_MNC = new ConfigKey<>(
+ public static final ConfigKey<Integer> GEOLOCATION_MNC = new IntegerConfigKey(
"geolocation.mnc",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Boolean flag to enable speed limit API to get speed limit values depending on location. Default value is false.
*/
- public static final ConfigKey<Boolean> SPEED_LIMIT_ENABLE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> SPEED_LIMIT_ENABLE = new BooleanConfigKey(
"speedLimit.enable",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Provider to use for speed limit. Available options: overpass. By default overpass is used.
*/
- public static final ConfigKey<String> SPEED_LIMIT_TYPE = new ConfigKey<>(
+ public static final ConfigKey<String> SPEED_LIMIT_TYPE = new StringConfigKey(
"speedLimit.type",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Speed limit provider API URL address.
*/
- public static final ConfigKey<String> SPEED_LIMIT_URL = new ConfigKey<>(
+ public static final ConfigKey<String> SPEED_LIMIT_URL = new StringConfigKey(
"speedLimit.url",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Override latitude sign / hemisphere. Useful in cases where value is incorrect because of device bug. Value can be
* N for North or S for South.
*/
- public static final ConfigKey<String> LOCATION_LATITUDE_HEMISPHERE = new ConfigKey<>(
+ public static final ConfigKey<String> LOCATION_LATITUDE_HEMISPHERE = new StringConfigKey(
"location.latitudeHemisphere",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Override longitude sign / hemisphere. Useful in cases where value is incorrect because of device bug. Value can
* be E for East or W for West.
*/
- public static final ConfigKey<String> LOCATION_LONGITUDE_HEMISPHERE = new ConfigKey<>(
+ public static final ConfigKey<String> LOCATION_LONGITUDE_HEMISPHERE = new StringConfigKey(
"location.longitudeHemisphere",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Jetty Request Log Path.
@@ -1220,112 +1301,112 @@ public final class Keys {
* over the file.
* Example: ./logs/jetty-yyyy_mm_dd.request.log
*/
- public static final ConfigKey<String> WEB_REQUEST_LOG_PATH = new ConfigKey<>(
+ public static final ConfigKey<String> WEB_REQUEST_LOG_PATH = new StringConfigKey(
"web.requestLog.path",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Set the number of days before rotated request log files are deleted.
*/
- public static final ConfigKey<Integer> WEB_REQUEST_LOG_RETAIN_DAYS = new ConfigKey<>(
+ public static final ConfigKey<Integer> WEB_REQUEST_LOG_RETAIN_DAYS = new IntegerConfigKey(
"web.requestLog.retainDays",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Disable systemd health checks.
*/
- public static final ConfigKey<Boolean> WEB_DISABLE_HEALTH_CHECK = new ConfigKey<>(
+ public static final ConfigKey<Boolean> WEB_DISABLE_HEALTH_CHECK = new BooleanConfigKey(
"web.disableHealthCheck",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Sets SameSite cookie attribute value.
* Supported options: Lax, Strict, None.
*/
- public static final ConfigKey<String> WEB_SAME_SITE_COOKIE = new ConfigKey<>(
+ public static final ConfigKey<String> WEB_SAME_SITE_COOKIE = new StringConfigKey(
"web.sameSiteCookie",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Enables persisting Jetty session to the database
*/
- public static final ConfigKey<Boolean> WEB_PERSIST_SESSION = new ConfigKey<>(
+ public static final ConfigKey<Boolean> WEB_PERSIST_SESSION = new BooleanConfigKey(
"web.persistSession",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Public URL for the web app. Used for notification and report link.
*
* If not provided, Traccar will attempt to get a URL from the server IP address, but it might be a local address.
*/
- public static final ConfigKey<String> WEB_URL = new ConfigKey<>(
+ public static final ConfigKey<String> WEB_URL = new StringConfigKey(
"web.url",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Output logging to the standard terminal output instead of a log file.
*/
- public static final ConfigKey<Boolean> LOGGER_CONSOLE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> LOGGER_CONSOLE = new BooleanConfigKey(
"logger.console",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Log executed SQL queries.
*/
- public static final ConfigKey<Boolean> LOGGER_QUERIES = new ConfigKey<>(
+ public static final ConfigKey<Boolean> LOGGER_QUERIES = new BooleanConfigKey(
"logger.queries",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Log file name. For rotating logs, a date is added at the end of the file name for non-current logs.
*/
- public static final ConfigKey<String> LOGGER_FILE = new ConfigKey<>(
+ public static final ConfigKey<String> LOGGER_FILE = new StringConfigKey(
"logger.file",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Logging level. Default value is 'info'.
* Available options: off, severe, warning, info, config, fine, finer, finest, all.
*/
- public static final ConfigKey<String> LOGGER_LEVEL = new ConfigKey<>(
+ public static final ConfigKey<String> LOGGER_LEVEL = new StringConfigKey(
"logger.level",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Print full exception traces. Useful for debugging. By default shortened traces are logged.
*/
- public static final ConfigKey<Boolean> LOGGER_FULL_STACK_TRACES = new ConfigKey<>(
+ public static final ConfigKey<Boolean> LOGGER_FULL_STACK_TRACES = new BooleanConfigKey(
"logger.fullStackTraces",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Create a new log file daily. Helps with log management. For example, downloading and cleaning logs. Enabled by
* default.
*/
- public static final ConfigKey<Boolean> LOGGER_ROTATE = new ConfigKey<>(
+ public static final ConfigKey<Boolean> LOGGER_ROTATE = new BooleanConfigKey(
"logger.rotate",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* A list of position attributes to log.
*/
- public static final ConfigKey<String> LOGGER_ATTRIBUTES = new ConfigKey<>(
+ public static final ConfigKey<String> LOGGER_ATTRIBUTES = new StringConfigKey(
"logger.attributes",
- Collections.singletonList(KeyType.CONFIG),
+ List.of(KeyType.CONFIG),
"time,position,speed,course,accuracy,result");
/**
* Multicast address for broadcasting synchronization events.
*/
- public static final ConfigKey<String> BROADCAST_ADDRESS = new ConfigKey<>(
+ public static final ConfigKey<String> BROADCAST_ADDRESS = new StringConfigKey(
"broadcast.address",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
/**
* Multicast port for broadcasting synchronization events.
*/
- public static final ConfigKey<Integer> BROADCAST_PORT = new ConfigKey<>(
+ public static final ConfigKey<Integer> BROADCAST_PORT = new IntegerConfigKey(
"broadcast.port",
- Collections.singletonList(KeyType.CONFIG));
+ List.of(KeyType.CONFIG));
}
diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java
index 81043fd7a..a3e04f920 100644
--- a/src/main/java/org/traccar/database/DeviceManager.java
+++ b/src/main/java/org/traccar/database/DeviceManager.java
@@ -73,34 +73,6 @@ public class DeviceManager extends BaseObjectManager<Device> implements Identity
refreshLastPositions();
}
- @Override
- public Device addUnknownDevice(String uniqueId) {
- Device device = new Device();
- device.setName(uniqueId);
- device.setUniqueId(uniqueId);
- device.setCategory(Context.getConfig().getString(Keys.DATABASE_REGISTER_UNKNOWN_DEFAULT_CATEGORY));
-
- long defaultGroupId = Context.getConfig().getLong(Keys.DATABASE_REGISTER_UNKNOWN_DEFAULT_GROUP_ID);
- if (defaultGroupId != 0) {
- device.setGroupId(defaultGroupId);
- }
-
- try {
- addItem(device);
-
- LOGGER.info("Automatically registered device " + uniqueId);
-
- if (defaultGroupId != 0) {
- Context.getPermissionsManager().refreshDeviceAndGroupPermissions();
- }
-
- return device;
- } catch (StorageException e) {
- LOGGER.warn("Automatic device registration error", e);
- return null;
- }
- }
-
public void updateDeviceCache(boolean force) {
long lastUpdate = devicesLastUpdate.get();
if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay)
@@ -316,35 +288,6 @@ public class DeviceManager extends BaseObjectManager<Device> implements Identity
return result != null ? (String) result : defaultValue;
}
- @Override
- public int lookupAttributeInteger(
- long deviceId, String attributeName, int defaultValue, boolean lookupServer, boolean lookupConfig) {
- Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig);
- if (result != null) {
- return result instanceof String ? Integer.parseInt((String) result) : ((Number) result).intValue();
- }
- return defaultValue;
- }
-
- @Override
- public long lookupAttributeLong(
- long deviceId, String attributeName, long defaultValue, boolean lookupServer, boolean lookupConfig) {
- Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig);
- if (result != null) {
- return result instanceof String ? Long.parseLong((String) result) : ((Number) result).longValue();
- }
- return defaultValue;
- }
-
- public double lookupAttributeDouble(
- long deviceId, String attributeName, double defaultValue, boolean lookupServer, boolean lookupConfig) {
- Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig);
- if (result != null) {
- return result instanceof String ? Double.parseDouble((String) result) : ((Number) result).doubleValue();
- }
- return defaultValue;
- }
-
private Object lookupAttribute(long deviceId, String attributeName, boolean lookupServer, boolean lookupConfig) {
Object result = null;
Device device = getById(deviceId);
diff --git a/src/main/java/org/traccar/database/IdentityManager.java b/src/main/java/org/traccar/database/IdentityManager.java
index ee386fdfd..10a64ebd9 100644
--- a/src/main/java/org/traccar/database/IdentityManager.java
+++ b/src/main/java/org/traccar/database/IdentityManager.java
@@ -20,8 +20,6 @@ import org.traccar.model.Position;
public interface IdentityManager {
- Device addUnknownDevice(String uniqueId);
-
Device getById(long id);
Device getByUniqueId(String uniqueId) throws Exception;
@@ -38,13 +36,4 @@ public interface IdentityManager {
String lookupAttributeString(
long deviceId, String attributeName, String defaultValue, boolean lookupServer, boolean lookupConfig);
- int lookupAttributeInteger(
- long deviceId, String attributeName, int defaultValue, boolean lookupServer, boolean lookupConfig);
-
- long lookupAttributeLong(
- long deviceId, String attributeName, long defaultValue, boolean lookupServer, boolean lookupConfig);
-
- double lookupAttributeDouble(
- long deviceId, String attributeName, double defaultValue, boolean lookupServer, boolean lookupConfig);
-
}
diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java
index 0511ec98b..00cbf92a0 100644
--- a/src/main/java/org/traccar/handler/FilterHandler.java
+++ b/src/main/java/org/traccar/handler/FilterHandler.java
@@ -21,11 +21,18 @@ import org.slf4j.LoggerFactory;
import org.traccar.BaseDataHandler;
import org.traccar.config.Config;
import org.traccar.config.Keys;
-import org.traccar.database.DataManager;
-import org.traccar.database.IdentityManager;
import org.traccar.helper.UnitsConverter;
+import org.traccar.helper.model.AttributeUtil;
+import org.traccar.model.Device;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.storage.Storage;
import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Limit;
+import org.traccar.storage.query.Order;
+import org.traccar.storage.query.Request;
import javax.inject.Inject;
import java.util.Date;
@@ -50,11 +57,11 @@ public class FilterHandler extends BaseDataHandler {
private final long skipLimit;
private final boolean skipAttributes;
- private final IdentityManager identityManager;
- private final DataManager dataManager;
+ private final CacheManager cacheManager;
+ private final Storage storage;
@Inject
- public FilterHandler(Config config, IdentityManager identityManager, DataManager dataManager) {
+ public FilterHandler(Config config, CacheManager cacheManager, Storage storage) {
enabled = config.getBoolean(Keys.FILTER_ENABLE);
filterInvalid = config.getBoolean(Keys.FILTER_INVALID);
filterZero = config.getBoolean(Keys.FILTER_ZERO);
@@ -69,8 +76,18 @@ public class FilterHandler extends BaseDataHandler {
filterRelative = config.getBoolean(Keys.FILTER_RELATIVE);
skipLimit = config.getLong(Keys.FILTER_SKIP_LIMIT) * 1000;
skipAttributes = config.getBoolean(Keys.FILTER_SKIP_ATTRIBUTES_ENABLE);
- this.identityManager = identityManager;
- this.dataManager = dataManager;
+ this.cacheManager = cacheManager;
+ this.storage = storage;
+ }
+
+ private Position getPrecedingPosition(long deviceId, Date date) throws StorageException {
+ return storage.getObject(Position.class, new Request(
+ new Columns.All(),
+ new Condition.And(
+ new Condition.Equals("deviceId", "deviceId", deviceId),
+ new Condition.Compare("fixTime", "<=", "time", date)),
+ new Order(true, "fixTime"),
+ new Limit(1)));
}
private boolean filterInvalid(Position position) {
@@ -144,9 +161,8 @@ public class FilterHandler extends BaseDataHandler {
private boolean skipAttributes(Position position) {
if (skipAttributes) {
- String attributesString = identityManager.lookupAttributeString(
- position.getDeviceId(), "filter.skipAttributes", "", false, true);
- for (String attribute : attributesString.split("[ ,]")) {
+ String string = AttributeUtil.lookup(cacheManager, Keys.FILTER_SKIP_ATTRIBUTES, position.getDeviceId());
+ for (String attribute : string.split("[ ,]")) {
if (position.getAttributes().containsKey(attribute)) {
return true;
}
@@ -183,13 +199,13 @@ public class FilterHandler extends BaseDataHandler {
if (filterRelative) {
try {
Date newFixTime = position.getFixTime();
- preceding = dataManager.getPrecedingPosition(deviceId, newFixTime);
+ preceding = getPrecedingPosition(deviceId, newFixTime);
} catch (StorageException e) {
LOGGER.warn("Error retrieving preceding position; fallbacking to last received position.", e);
- preceding = getLastReceivedPosition(deviceId);
+ preceding = cacheManager.getPosition(deviceId);
}
} else {
- preceding = getLastReceivedPosition(deviceId);
+ preceding = cacheManager.getPosition(deviceId);
}
if (filterDuplicate(position, preceding) && !skipLimit(position, preceding) && !skipAttributes(position)) {
filterType.append("Duplicate ");
@@ -209,7 +225,7 @@ public class FilterHandler extends BaseDataHandler {
}
if (filterType.length() > 0) {
- String uniqueId = identityManager.getById(deviceId).getUniqueId();
+ String uniqueId = cacheManager.getObject(Device.class, deviceId).getUniqueId();
LOGGER.info("Position filtered by {}filters from device: {}", filterType, uniqueId);
return true;
}
@@ -217,10 +233,6 @@ public class FilterHandler extends BaseDataHandler {
return false;
}
- private Position getLastReceivedPosition(long deviceId) {
- return identityManager.getLastPosition(deviceId);
- }
-
@Override
protected Position handlePosition(Position position) {
if (enabled && filter(position)) {
diff --git a/src/main/java/org/traccar/handler/HemisphereHandler.java b/src/main/java/org/traccar/handler/HemisphereHandler.java
index 2e3ed9d91..f760457a3 100644
--- a/src/main/java/org/traccar/handler/HemisphereHandler.java
+++ b/src/main/java/org/traccar/handler/HemisphereHandler.java
@@ -39,7 +39,7 @@ public class HemisphereHandler extends BaseDataHandler {
latitudeFactor = -1;
}
}
- String longitudeHemisphere = config.getString(Keys.LOCATION_LATITUDE_HEMISPHERE);
+ String longitudeHemisphere = config.getString(Keys.LOCATION_LONGITUDE_HEMISPHERE);
if (longitudeHemisphere != null) {
if (longitudeHemisphere.equalsIgnoreCase("E")) {
longitudeFactor = 1;
diff --git a/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java b/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java
index 7849abff9..2d105af3e 100644
--- a/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java
@@ -16,10 +16,13 @@
package org.traccar.handler.events;
import io.netty.channel.ChannelHandler;
-import org.traccar.database.IdentityManager;
+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.session.cache.CacheManager;
import javax.inject.Inject;
import java.util.Collections;
@@ -28,31 +31,28 @@ import java.util.Map;
@ChannelHandler.Sharable
public class FuelDropEventHandler extends BaseEventHandler {
- public static final String ATTRIBUTE_FUEL_DROP_THRESHOLD = "fuelDropThreshold";
-
- private final IdentityManager identityManager;
+ private final CacheManager cacheManager;
@Inject
- public FuelDropEventHandler(IdentityManager identityManager) {
- this.identityManager = identityManager;
+ public FuelDropEventHandler(CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
}
@Override
protected Map<Event, Position> analyzePosition(Position position) {
- Device device = identityManager.getById(position.getDeviceId());
+ Device device = cacheManager.getObject(Device.class, position.getDeviceId());
if (device == null) {
return null;
}
- if (!identityManager.isLatestPosition(position)) {
+ if (!PositionUtil.isLatest(cacheManager, position)) {
return null;
}
- double fuelDropThreshold = identityManager
- .lookupAttributeDouble(device.getId(), ATTRIBUTE_FUEL_DROP_THRESHOLD, 0, true, false);
-
+ double fuelDropThreshold = AttributeUtil.lookup(
+ cacheManager, Keys.EVENT_FUEL_DROP_THRESHOLD, position.getDeviceId());
if (fuelDropThreshold > 0) {
- Position lastPosition = identityManager.getLastPosition(position.getDeviceId());
+ Position lastPosition = cacheManager.getPosition(position.getDeviceId());
if (position.getAttributes().containsKey(Position.KEY_FUEL_LEVEL)
&& lastPosition != null && lastPosition.getAttributes().containsKey(Position.KEY_FUEL_LEVEL)) {
@@ -60,7 +60,6 @@ public class FuelDropEventHandler extends BaseEventHandler {
- position.getDouble(Position.KEY_FUEL_LEVEL);
if (drop >= fuelDropThreshold) {
Event event = new Event(Event.TYPE_DEVICE_FUEL_DROP, position);
- event.set(ATTRIBUTE_FUEL_DROP_THRESHOLD, fuelDropThreshold);
return Collections.singletonMap(event, position);
}
}
diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java
index 45bb13be5..6de56d11e 100644
--- a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java
@@ -23,6 +23,8 @@ import io.netty.channel.ChannelHandler;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.database.DeviceManager;
+import org.traccar.helper.model.AttributeUtil;
+import org.traccar.helper.model.PositionUtil;
import org.traccar.model.Device;
import org.traccar.session.DeviceState;
import org.traccar.model.Event;
@@ -36,7 +38,6 @@ import javax.inject.Inject;
public class OverspeedEventHandler extends BaseEventHandler {
public static final String ATTRIBUTE_SPEED = "speed";
- public static final String ATTRIBUTE_SPEED_LIMIT = "speedLimit";
private final DeviceManager deviceManager;
private final CacheManager cacheManager;
@@ -58,7 +59,7 @@ public class OverspeedEventHandler extends BaseEventHandler {
Position position = deviceState.getOverspeedPosition();
Event event = new Event(Event.TYPE_DEVICE_OVERSPEED, position);
event.set(ATTRIBUTE_SPEED, deviceState.getOverspeedPosition().getSpeed());
- event.set(ATTRIBUTE_SPEED_LIMIT, speedLimit);
+ event.set(Position.KEY_SPEED_LIMIT, speedLimit);
event.setGeofenceId(deviceState.getOverspeedGeofenceId());
deviceState.setOverspeedState(notRepeat);
deviceState.setOverspeedPosition(null);
@@ -115,15 +116,15 @@ public class OverspeedEventHandler extends BaseEventHandler {
protected Map<Event, Position> analyzePosition(Position position) {
long deviceId = position.getDeviceId();
- Device device = deviceManager.getById(deviceId);
+ Device device = cacheManager.getObject(Device.class, position.getDeviceId());
if (device == null) {
return null;
}
- if (!deviceManager.isLatestPosition(position) || !position.getValid()) {
+ if (!PositionUtil.isLatest(cacheManager, position) || !position.getValid()) {
return null;
}
- double speedLimit = deviceManager.lookupAttributeDouble(deviceId, ATTRIBUTE_SPEED_LIMIT, 0, true, false);
+ double speedLimit = AttributeUtil.lookup(cacheManager, Keys.EVENT_OVERSPEED_LIMIT, deviceId);
double positionSpeedLimit = position.getDouble(Position.KEY_SPEED_LIMIT);
if (positionSpeedLimit > 0) {
@@ -137,7 +138,7 @@ public class OverspeedEventHandler extends BaseEventHandler {
for (long geofenceId : device.getGeofenceIds()) {
Geofence geofence = cacheManager.getObject(Geofence.class, geofenceId);
if (geofence != null) {
- double currentSpeedLimit = geofence.getDouble(ATTRIBUTE_SPEED_LIMIT);
+ double currentSpeedLimit = geofence.getDouble(Keys.EVENT_OVERSPEED_LIMIT.getKey());
if (currentSpeedLimit > 0 && geofenceSpeedLimit == 0
|| preferLowest && currentSpeedLimit < geofenceSpeedLimit
|| !preferLowest && currentSpeedLimit > geofenceSpeedLimit) {
diff --git a/src/main/java/org/traccar/helper/model/AttributeUtil.java b/src/main/java/org/traccar/helper/model/AttributeUtil.java
new file mode 100644
index 000000000..5b3fc1cbe
--- /dev/null
+++ b/src/main/java/org/traccar/helper/model/AttributeUtil.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 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.helper.model;
+
+import org.traccar.config.ConfigKey;
+import org.traccar.config.KeyType;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.session.cache.CacheManager;
+
+public final class AttributeUtil {
+
+ private AttributeUtil() {
+ }
+
+ @SuppressWarnings({ "deprecation", "unchecked" })
+ public static <T> T lookup(CacheManager cacheManager, ConfigKey<T> key, long deviceId) {
+ Device device = cacheManager.getObject(Device.class, deviceId);
+ Object result = device.getAttributes().get(key.getKey());
+ long groupId = device.getGroupId();
+ while (result == null && groupId > 0) {
+ Group group = cacheManager.getObject(Group.class, groupId);
+ if (group != null) {
+ result = group.getAttributes().get(key.getKey());
+ }
+ }
+ if (result == null && key.hasType(KeyType.SERVER)) {
+ result = cacheManager.getServer().getAttributes().get(key.getKey());
+ }
+ if (result == null && key.hasType(KeyType.CONFIG)) {
+ result = cacheManager.getConfig().getString(key.getKey());
+ }
+
+ if (result != null) {
+ Class<T> valueClass = key.getValueClass();
+ if (valueClass.equals(Boolean.class)) {
+ return (T) (result instanceof String
+ ? Boolean.parseBoolean((String) result)
+ : result);
+ } else if (valueClass.equals(Integer.class)) {
+ return (T) (Object) (result instanceof String
+ ? Integer.parseInt((String) result)
+ : ((Number) result).intValue());
+ } else if (valueClass.equals(Long.class)) {
+ return (T) (Object) (result instanceof String
+ ? Long.parseLong((String) result)
+ : ((Number) result).longValue());
+ } else if (valueClass.equals(Double.class)) {
+ return (T) (Object) (result instanceof String
+ ? Double.parseDouble((String) result)
+ : ((Number) result).doubleValue());
+ } else {
+ return (T) result;
+ }
+ }
+ return key.getDefaultValue();
+ }
+
+}
diff --git a/src/main/java/org/traccar/model/CellTower.java b/src/main/java/org/traccar/model/CellTower.java
index af33b1f5c..16a28ea79 100644
--- a/src/main/java/org/traccar/model/CellTower.java
+++ b/src/main/java/org/traccar/model/CellTower.java
@@ -38,7 +38,7 @@ public class CellTower {
}
public static CellTower fromLacCid(Config config, int lac, long cid) {
- return from(config.getInteger(Keys.GEOLOCATION_MCC), config.getInteger(Keys.GEOLOCATION_MCC), lac, cid);
+ return from(config.getInteger(Keys.GEOLOCATION_MCC), config.getInteger(Keys.GEOLOCATION_MNC), lac, cid);
}
public static CellTower fromCidLac(Config config, long cid, int lac) {
diff --git a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java
index 0ff668fa8..aa23bfac5 100644
--- a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 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.
@@ -17,6 +17,8 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.AttributeUtil;
import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DataConverter;
@@ -66,8 +68,9 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder {
}
public String[] getFormat(long deviceId) {
- return getIdentityManager().lookupAttributeString(
- deviceId, getProtocolName() + ".format", format, false, false).split(",");
+ String value = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_FORMAT.withPrefix(getProtocolName()), deviceId);
+ return (value != null ? value : format).split(",");
}
public void setFormat(String format) {
@@ -75,8 +78,9 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder {
}
public DateFormat getDateFormat(long deviceId) {
- DateFormat dateFormat = new SimpleDateFormat(getIdentityManager().lookupAttributeString(
- deviceId, getProtocolName() + ".dateFormat", this.dateFormat, false, false));
+ String value = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_DATE_FORMAT.withPrefix(getProtocolName()), deviceId);
+ DateFormat dateFormat = new SimpleDateFormat(value != null ? value : this.dateFormat);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
return dateFormat;
}
diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java
index 6340def86..44ba1da38 100644
--- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java
@@ -20,6 +20,8 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.AttributeUtil;
import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -71,8 +73,8 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
}
public int getProtocolType(long deviceId) {
- return getIdentityManager().lookupAttributeInteger(
- deviceId, getProtocolName() + ".protocolType", protocolType, false, true);
+ Integer value = AttributeUtil.lookup(getCacheManager(), Keys.PROTOCOL_TYPE, deviceId);
+ return value != null ? value : protocolType;
}
public void setHbm(boolean hbm) {
@@ -80,8 +82,8 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
}
public boolean isHbm(long deviceId) {
- return getIdentityManager().lookupAttributeBoolean(
- deviceId, getProtocolName() + ".hbm", hbm, false, true);
+ Boolean value = AttributeUtil.lookup(getCacheManager(), Keys.PROTOCOL_HBM, deviceId);
+ return value != null ? value : hbm;
}
public void setIncludeAdc(boolean includeAdc) {
@@ -89,8 +91,9 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
}
public boolean isIncludeAdc(long deviceId) {
- return getIdentityManager().lookupAttributeBoolean(
- deviceId, getProtocolName() + ".includeAdc", includeAdc, false, true);
+ Boolean value = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_INCLUDE_ADC.withPrefix(getProtocolName()), deviceId);
+ return value != null ? value : includeAdc;
}
public void setIncludeRpm(boolean includeRpm) {
@@ -98,8 +101,9 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
}
public boolean isIncludeRpm(long deviceId) {
- return getIdentityManager().lookupAttributeBoolean(
- deviceId, getProtocolName() + ".includeRpm", includeRpm, false, true);
+ Boolean value = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_INCLUDE_RPM.withPrefix(getProtocolName()), deviceId);
+ return value != null ? value : includeRpm;
}
public void setIncludeTemp(boolean includeTemp) {
@@ -107,8 +111,9 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
}
public boolean isIncludeTemp(long deviceId) {
- return getIdentityManager().lookupAttributeBoolean(
- deviceId, getProtocolName() + ".includeTemp", includeTemp, false, true);
+ Boolean value = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_INCLUDE_TEMPERATURE.withPrefix(getProtocolName()), deviceId);
+ return value != null ? value : includeTemp;
}
private Position decode9(
diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java
index 6d5fefa75..3fa467b57 100644
--- a/src/main/java/org/traccar/session/ConnectionManager.java
+++ b/src/main/java/org/traccar/session/ConnectionManager.java
@@ -28,6 +28,7 @@ import org.traccar.config.Keys;
import org.traccar.database.NotificationManager;
import org.traccar.handler.events.MotionEventHandler;
import org.traccar.handler.events.OverspeedEventHandler;
+import org.traccar.helper.model.AttributeUtil;
import org.traccar.model.Device;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -279,9 +280,9 @@ public class ConnectionManager {
result.putAll(event);
}
+ double speedLimit = AttributeUtil.lookup(cacheManager, Keys.EVENT_OVERSPEED_LIMIT, deviceId);
event = Main.getInjector().getInstance(OverspeedEventHandler.class)
- .updateOverspeedState(deviceState, Context.getDeviceManager().
- lookupAttributeDouble(deviceId, OverspeedEventHandler.ATTRIBUTE_SPEED_LIMIT, 0, true, false));
+ .updateOverspeedState(deviceState, speedLimit);
if (event != null) {
result.putAll(event);
}
diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java
index 896df83e7..87384f746 100644
--- a/src/main/java/org/traccar/session/cache/CacheManager.java
+++ b/src/main/java/org/traccar/session/cache/CacheManager.java
@@ -74,6 +74,10 @@ public class CacheManager {
invalidateUsers();
}
+ public Config getConfig() {
+ return config;
+ }
+
public <T extends BaseModel> T getObject(Class<T> clazz, long id) {
try {
lock.readLock().lock();